Piątek, chmura słów, TextMining, morfologik i oczywiście R

Dzisiaj jest piątek, więc zamiast zaprzątać sobie głowę liczbami pooglądamy obrazki.

Dwa dni temu, w tym wpisie opisałem jak ściągnąć dane z Twittera i jako przykład ściągnąłem dane z kanału #debataACTA. Pokazałem też kilka podsumowań odkładając na później bardziej złożone analizy. Analizę nastawienia odłożę jeszcze na później, a dzisiaj pokażę jak danych tekstowych zrobić chmurę słów (ang. word cloud) używając R.

Samą chmurę słów można wykonać używając funkcji wordcloud() z pakietu wordcloud. Jako argumenty należy podać listę słów oraz współczynnik skalujący, odpowiadający wielkości danego słowa (najczęściej odpowiadający liczbie wystąpień danego słowa w tekście). Listę słów oraz częstości ich wystąpień można wygenerować używając funkcji str_split() i table(), ale aby było ciekawiej użyję w tym celu pakietu tm, który ma wiele przydatnych narzędzi do analizy tekstu (najwięcej przydatnych narzędzi ma do analizy tekstu angielskiego, ale z polskim też coś można zrobić).

Poniższy fragment kodu wczytuje dane, liczy tablicę częstości a następnie przedstawia ją graficznie z użyciem funkcji wordcloud(),

 

# Odczytaj dane
tweets = read.table(file="debataACTA4_13_luty.csv", sep=";", head=T)
 
# funkcje z pakietu tm i wordcloud
# do tworzenia korpusu wyrazów i ich wizualizacji
actaSlownik = Corpus(DataframeSource(data.frame(tweets[,2])))
actaSlownik = tm_map(actaSlownik, removePunctuation)
actaSlownik = tm_map(actaSlownik, tolower)
tdm = TermDocumentMatrix(actaSlownik)
m = as.matrix(tdm)
v = sort(rowSums(m),decreasing=TRUE)
 
# mając policzone częstości występowania możemy je zwizualizować
wordcloud(names(v), v^0.3, scale=c(5,0.5),random.order=F, colors="black")

 

Wykres otrzymany w ten sposób nie wygląda zbyt dobrze, ponieważ słowa występują w najróżniejszych odmianach a liczenie częstości osobno dla ,premierze’, 'premier’, 'premiera’, 'premierem’ nie wiele daje. Aby wykres wyglądał lepiej chcielibyśmy dla każdego ze słów znaleźć jego rdzeń i zliczać liczbę wystąpień rdzeni a nie różnych form. Jak to zrobić? Potrzebny będzie lematyzator, a dokładniej tzw. stemmer, czyli narzędzie, które dla każdego słowa wyodrębni tzw. 'stem’ (nie znam niestety polskiej terminologii a nie chcę tworzy kwiecistych tłumaczeń) czyli część słowa nie ulegającą odmianie.

Wykorzystam bezpłatny morfologik-stemmer dostępny na blogu http://morfologik.blogspot.com/ rozwijany przez Dawida Weissa i współpracowników. Narzędzie z którego skorzystałem to duży plik tekstowy mający w jednej kolumnie różne formy słów, w drugiej rdzenie a w trzeciej informacje o formie gramatycznej danego słowa. Oczywiście nie wszystkie słowa z twittera można znaleźć w tym zbiorze, nie ma tam np. wszystkich nazwisk. W każdym razie pierwsza transformacja polegała na przemapowaniu słowa na jego rdzeń, jeżeli słowo występuje w słowniku, lub pozostawienie słowa bez zmiany jeżeli w słowniku nie występuje. Dzięki temu z 13334 różnych słów zostaliśmy z 8597 słowami, z czego zdecydowana większość występuje tyko raz i nie znajdzie się na mapie tagów.

Zobaczmy jak wygląda rzeczona mapa.

[Rysunek 1. Chmura słów występujących przynajmniej dwa razy w zapisach z kanału debataACTA. Gdy było to możliwe słowa zostały przekształcone do swoich rdzeni. Wersja wektorowa tego rysunku (uwaga 7MB) znajduje się tutaj]

Dużo tych słów, mało widać, zróbmy więc jeszcze jedną iterację. Usuńmy wszystko co nie jest rzeczownikiem. Szczęśliwie słownik z pakietu morfologik ma informacje o tym czy dane słowo jest czy nie rzeczownikiem, więc zostawiamy tylko słowa, które znajdują się w słowniku i mają 'subst’ w trzeciej kolumnie.

[Rysunek 2. Chmura rzeczowników występujących przynajmniej dwa razy w zapisach z kanału debataACTA. Wersja wektorowa tego rysunku (uwaga 8MB) znajduje się tutaj]

Zróbmy jeszcze jeden eksperyment, mianowicie sprawdźmy jakie inne kanały występowały w wiadomościach z kanału #debataACTA. Zostawiamy więc tylko słowa zaczynające się od znaku #.

 

[Rysunek 3. Chmura nazw kanałów w wiadomościach na kanale debataACTA. Wersja wektorowa tego rysunku (uwaga 7MB) znajduje się tutaj]

#debataACTA, twitteR, Twitter i R

Zaczęło się niewinnie. Dwa tygodnie temu kolega Grzesiek P. powiedział, że analizę nastawienia (ang. Sentiment analysis) na dużych ilościach tekstu robi się banalnie. Tydzień temu kolega Paweł Ch. powiedział, że API twittera ma limit do 70 zapytań na minutę. W piątek przy okazji rozmowy o raporcie ,,Obiegi Kultury” Alek T. zapytał mnie czy mam doświadczenie w analizie danych z Twittera bo chętnie zobaczyłby się działo na kanale (moje autorskie tłumaczenie hashtaga) #debataACTA. Ponieważ nie interesowałem wcześniej się ani analizą nastawienia, ani API twittera ani hashtagami, stwierdziłem, że warto zobaczyć co w trawie ćwierka.

Tak się składa, że dzięki Jeffowi Gentry’emu API Twittera jest łatwo dostępne z poziomu R. Wystarczy załadować pakiet twitteR i kilka prostych funkcji pozwala na łatwą interakcję z ćwierkami z serwisu Twitter.com (ok, dalej będę używał tłumaczenia ,,wiadomościami”).

Zobaczmy prosty przykład.

> # interfejs do API twittera
> library(twitteR)
> # pobierz maksymalnie 1500 wiadomości zawierających etykietę #debataACTA
> # stworzonych 7 lutego 2012
> tweets = searchTwitter('#debataACTA', n=1500, until="2012-02-08", since="2012-02-06")
> # zamień wyniki na ramkę danych i wyświetl treść oraz autora pierwszej z wiadomości
> debataACTA =  twListToDF(tweets)
> debataACTA[1,c(1,4,10)]
                                                                                    text             created screenName
1 Mamy tyle Kultury i Edukacji ile na nia wydajemy 0,75% Budzetu #debataACTA #PremierRP 2012-02-07 15:37:46     TPHMAC

Ten pakiet ma te same ograniczenia co API, czyli 70 zapytań na minutę. Ale każde zapytanie to 25 wiadomości, a więc w sumie możemy ściągnąć do 1500 wiadomości na minutę.

Prostą pętlą, z pewną pomocą internetu, zebrałem wpisy z Twittera z okresu od 4 do 12 lutego 2012 zawierające etykietę #debataACTA. po oczyszczeniu zapisałem je w postaci pliku csv, który można pobrać z adresu tutaj.

Mamy więc dane, przyjrzyjmy się im. Do tematu analizy nastawienia podejdziemy w piątek, a dziś przyjrzyjmy się jak wyglądała aktywność ćwierkających. Na rysunku 1 można zobaczyć ile wpisów pojawiało się z tą etykietą. Temat jak widać skończył się z samą debatą. Na rysunku 2 można zobaczyć bliżej interesujący okres liczby wiadomości nadczas trwania debaty. Rzuca się w oczy szczególnie ta chwila ciszy przed burzą.

[Rysunek 1. Liczba wiadomości zawierających etykietę #debataACTA na godzinę. Kliknij by powiększyć.]

[Rysunek 2. Liczba wiadomości zawierających etykietę #debataACTA na 5 minut (debata rozpoczęła się po godzinie 14). Kliknij by powiększyć.]

Gdyby ktoś chciał sprawdzić o czym mówiono w której minucie to komentarze z znaczkami synchronizacyjnymi znaleźć można np. tutaj.

W sumie mamy ponad 6.5 tysiąca wiadomości. Zobaczmy kto je pisał. Zamiast wpisywać ksywy ćwierkających pokażę ilu z nich generuje odpowiedni procent wszystkich wiadomości.

[Rysunek 3. Na osi y przedstawiono liczbę wiadomości wygenerowanych przez X najaktywniejszych użytkowników. Okazuje się, że 7% piszących (dokładnie 72) generuje 50% wiadomości. A tylko 2% (dokładnie 21) generuje 25% wszystkich wiadomości. Kliknij by powiększyć.]

Ściągnęliśmy dane, zobaczyliśmy podstawowe podsumowania, czas zabrać się za analizę nastawienia. Więcej na ten temat w piątek (muszę ją jeszcze zrobić) a dzisiaj zakończę podsumowaniem z procentowym udziałem wiadomości zawierających ikonę buźki (;-), ;), :-), :))) itp).

[Rysunek 4. Procentowy udział wiadomości zawierających buźkę. Kliknij by powiększyć.]

Jak widać przez pierwsze dwie godziny debaty nie było ćwierkającym do śmiechu.