2013. január 27., vasárnap

R : a meaningful bejegyzésekről

Az elmúlt héten egy nagy online piackutatáson dolgoztam, amely során sok-sok blogbejegyzést, fórum-postot és twitter csippet néztem át. A nagy social media monitoring eszközök egyelőre leginkább kulcsszó-alapon hozzák a találatokat, de messze nem olyan jók az eredmények, mint mondjuk egy kereső-motor esetében. Persze ez érthető, hiszen míg a weben sok tényező alapján lehet rangsorolni a dokumentumokat, a szociális médiában megjelenő postoknál sokkal kevesebb ilyennel rendelkezünk. Így tehát, sajnos, sok a rossz, irreleváns találat, és ezek feldolgozásánál emberi munkát kell bevetni.

De engem azért mégis érdekel, mi különböztet meg egy irreleváns postot (blogbejegyzést, tweet-et, facebook hozzászólást) egy értékestől. Eddig még semmit sem olvastam ebben a témában, úgyhogy naív, próba-szerencse alapon látok neki a dolognak. Valódi kutatáshoz felhasznált, valódi adatokat néztem meg: az egyik legnagyobb nemzetközi social media monitoring eszköz által generált 300 fórum hozzászólás, amelyből 48 bizonyult (emberi átnézés után) "meaningful"-nak, vagyis értékelhető információt is tartalmazónak. A többi vagy nem releváns, vagy spam.

Úgy gondolom, hogy a "jó" hozzászólást onnan lehet megismerni, hogy "jó" kulcsszavakat tartalmaz. A kulcsszavak felismerése azonban bonyolult -- az sem jó, ha túl általánosak, és az sem jó, ha túl specifikusak. Specifikus, csak az adott hozzászólásra jellemző kulcsszót pl. a TF-IDF módszerrel lehet generálni, általános kulcsszavakat pedig egy egyszerű term frequency számítással.

A kettő közötti arany középút keresését egy plottal kezdtem:




Itt egy log-log skálán látható a két korpusz kulcsszó-eloszlása:

plot(diff[1:1500]*3, log = "y", col = "red")
points(TF_sorted, col = "blue")


A kék pontok a teljes (vagyis a jó és a felesleges dokumentumokat is tartalmazó) korpuszra vonatkoznak -- becsületesen ki is rajzolják a Zipf-eloszlást. A piros pontok jelölik a "jó dokumentumok" kulcsszavait.

Két csavar van a dologban:
Mind a kék, mind a piros pontok X tengelyén ugyanott vannak a kulcsszavak, hiszen máskülönben a piros pontok is csak egy többé-kevésbbé szabályos Zipf-eloszlást produkálnának. Ezt így oldottam meg (biztosan lehet elegánsabban is):

diff <- rep(0, length(TF_sorted) )
names(diff) <- names(TF_sorted)
for (i in 1:length(names(TF2)) ) { nm <- names(TF2)[i]; diff[nm] <- TF2[nm]}


A második csavar, hogy a piros pontok értékeit megszoroztam hárommal, hiszen sokkal kisebb halmazzal dolgozom (pontosan 6.25-ször kisebbel)).

Mit látunk? Hogy a meaningful postok (piros) kulcsszavai más eloszlást rajzolnak ki, mint a teljes korpuszé. Minket most a felfelé kilógó kulcsszavak érdekelnek, hiszen ezek "jobban jellemzik" a meaningful halmazt.

diff3 <- diff * 3
diff3 <- diff3 - TF_sorted
positive <- function(x) { if (x > 0) return (TRUE) else (FALSE) }
Filter(positive, diff3[100:500])


A fenti sorokkal azokat a pontokat (kulcsszavakat) választjuk ki, amelyek felfele lógnak ki (positive TRUE).



Sajnos, a kulcsavak nem magyarul vannak ;)
Persze még így is jócskán tartalmaznak általános, érdektelen kulcsszavakat, de messze jobb a merítés így, mintha csak egyszerűen term-frequencyt-t mérnénk a teljes meaningful korpuszon.

Még több kód erre (evernote firka)








2013. január 22., kedd

my Reading List on Text Classification

I am going to read in the next few days some texts on text classification and sentiment analysis:

How to build a twitter sentiment analyzer
http://ravikiranj.net/drupal/201205/code/machine-learning/how-build-twitter-sentiment-analyzer

NLTK Book:  6   Learning to Classify Text
http://nltk.org/book/ch06.html

Mining Twitter with R
https://sites.google.com/site/miningtwitter/

Bo Pang and Lillian Lee: Opinion mining and sentiment analysis
http://www.cs.cornell.edu/home/llee/omsa/omsa.pdf

Textbooks and learning materials from Edinurgh University's Text Technologies course
http://www.inf.ed.ac.uk/teaching/courses/tts/

Well, maybe not in the next few days, rather in next few week ;)

2013. január 15., kedd

R. Öt első benyomás.

1. Elkezdtem tanulni az R nyelvet. Az R ingyenes, nyílt forráskódú, magasszintű nyelv -- az első benyomásaim nagyon jók, az R alapvetően könnyű. Azt azonban meg kell jegyezni, hogy első nyelvnek semmiképp sem ajánlható, mivel szinte minden oktató anyag feltételezi az alapszintű informatikai fogalmak ismeretét. Szintén nem kimondott előfeltételezés, hogy friss R-es tisztában van néhány egyszerűbb matematikai és statisztikai koncepcióval. Harmadrészt pedig elég unalmas lehet úgy dolgozni az R-rel, ha nincs egy valódi és konkrét problémánk, amit meg szeretnénk oldani.

2. Az R kellemesen fapados, ami meghatározza a munka menetét is. Mindenképp szükség van bemenő adatokra és előre feltett kérdésekre. Bemenő adatonként én táblákat (csv) és nyers, formázatlan számsorokat használok, ezekkel az R nagyon jól boldogul. Miután beolvastuk az adatokat, az interaktív konzolon dolgozhatunk rajtuk, ez gyakorlatilag ugyanolyan, mint a python nyelvben: beírunk egy parancsot, és egyből megkapjuk a választ. Ez azért jó, mert egyből látjuk a végeredményt, és azért rossz, mert jól kell megfogalmazni (parancsként) a kérdéseinkent -- máskülönben sokat kell gépelnünk. Az interaktív konzol további jó tulajdonsága, hogy alapértelmezésként elmenti a teljes worspace-t:  a teljes parancs-history-t és a memória teljes tartalmát(!) is. Vagyis, a korábbi munkánkat bármikor folytathatjuk.

3. Én eddig csak az R Cookbook-ot és néhány online leírást böngésztem át; úgy tűnik, hogy az R munkastílus alapvetően nem programokban gondolkodik. Lehet természetesen különféle vezérlő-szerkezeteket, ciklusokat és elágazásokat, függvényeket és osztályokat készíteni. Ennél azonban népszerűbb a rengeteg beépített (és letölthető) függvény használata, valamint az 'adatokban gondolkodás'. Számomra ez körülbelül azt jelenti, hogy ahelyett, hogy azt terveznénk meg, mit csináljon a számítógép az adatokkal, azt gondoljuk ki, mi történjen az adatokkal. Vagyis, miként változzanak meg -- aminek a legjobb módja, hogy felállítunk pár szabályt (függvényt), amin azután áteresztjük az adatainkat. Nem kivételekben és döntésekben gondolkodunk, hanem transzformációkban és szűrésekben. Egy kicsit nehéz elfelejteni az ciklusokat és az if-eket, ha az ember egy klasszikus programnyelv felől érkezik -- cserébe viszont átlátható, tömör kód és kevés hibalehetőség a jutalmunk.

4. És végül demonstrálja néhány példa, hogy milyen kellemes az R-rel való munka:


Egy mozdulattal beolvasunk egy táblát. Ezután h[x,y] formában férhetünk hozzá az adatokhoz.
 
h <- read.csv('meki_hir.csv')

Egy mátrix nem üres elemeit mind átírjuk 1-re. Először definiálunk egy függvényt, a következő sorban pedig alkalmazzuk egy mátrixra.
 
not_zero <- function(x) { if (x==0) return(0) else return(1)}
dtm0 <- apply(dtmM, 1:2, not_zero

Oszloponként összeadjuk egy mátrix elemeit:

TF = colSums(as.matrix(dtm0))

Mátrixszorzás. Az R alapszerkezetei a vektor és a mátrix, bármilyen műveletet végezhetünk elemenként és teljes mátrixon értelmezve is.

scores <- dtmM %*% ITF_DIAG

Kiválasztjuk egy mátrix első sorának 30 legnagyobb elemét:

sort(scores[1,], decreasing = TRUE)[1:30]
 

5. Az adatok mit sem érnek, ha nem tudjuk őket megnézni. Az R grafikai képességei nagyszerűek, használatuk gyerekjáték. Itt egy nagy adathalmaz 3 véletlenszerűen kiválasztott elemére nézünk rá, hogy lássuk, milyen az eloszlásuk.

 
par(mfrow=c(1,3))
plot(egy_alatt_(7,0.05)$freq)
grid()
plot(egy_alatt_(47,0.05)$freq)
grid()
plot(egy_alatt_(67,0.05)$freq)
grid()
savePlot("kutyiDist.png", type="png")