Słowne wyliczanki

https://xpil.eu/jYbpP

Zachciało mi się niedawno sprawdzić, jakich słów używam na blogu najczęściej, a jakich najrzadziej.

Zadanie okazało się końcem końców kompletnie bezużyteczne, ponieważ - zgodnie z przewidywaniami - najczęściej używanymi słowami okazał się "klej" języka, czyli wszelakie spójniki, przedimki, zaimki i inne partykuły.

Najczęściej używane słowo pojawia się w moich wpisach piętnaście tysięcy dwieście osiemdziesiąt osiem razy - i to nie licząc tego wpisu, który właśnie piszę, a w którym to słowo pojawiło się już dwukrotnie, chociaż jesteśmy dopiero w okolicach czwartego akapitu (oops, pardon, już trzykrotnie!).

Żeby było ciekawiej, zamiast używać do wykonania tej analizy języka SQL, użyłem wyłącznie wbudowanych w system operacyjny poleceń. Blog siedzi na linuksie, więc jest z czego wybierać. Jedyny moment, kiedy użyłem SQL-a, to pierwszy krok, w którym wyciągamy z bazy danych WordPressa treści wszystkich wpisów i ładujemy je do jednego dużego pliku.

O, tak:

nano -w ./get_all_posts.sh

mysql -u uzytkownik -p -e "select post_content from wpdb.wp_posts;" > posts.txt

^O Enter ^X

chmod +x ./get_all_posts.sh

Po wykonaniu powyższych zaklęć (proszę tylko pamiętać o zmianie nazwy użytkownika z "uzytkownik" na faktyczną nazwę, której używamy - szczegóły w pliku konfiguracyjnym wp-config.php w katalogu domowym bloga) w bieżącym katalogu pojawi nam się skrypt o nazwie get_all_posts.sh, którego uruchomienie wygeneruje nam - po podaniu prawidłowego hasła do bazy danych - plik posts.txt. Ten plik to nasz punkt startowy do dalszych analiz.

Najpierw zerknijmy sobie, co na temat tego pliku "sądzi" nasz linuks:

file ./posts.txt
./posts.txt: HTML document, UTF-8 Unicode text, with very long lines, with CR, LF line terminators

Jak widać plik jest rozpoznany jako dokument HTML (nie do końca prawda, ale faktycznie, ma w środku dużo znaczników HTML, więc łatwo się pomylić), zakodowany w UTF-8, z bardzo długimi liniami oraz windowsowymi końcówkami linii (CR, LF)

Zacząłem od usunięcia z pliku wszystkich znaczników HTML:

sed -e 's/<[^>]*>//g' ./posts.txt > posts1-nohtml.txt

Następnie rzuciłem okiem na zawartość pliku wynikowego (posts-nohtml.txt) i zadałem sobie pytanie: czy chcę wyrazy z łącznikiem traktować jako pojedyncze słowa, czy rozbić je na kawałki? Wyszło mi, że chcę je rozbić na kawałki (a więc na przykład słowo "biało-czerwony" chcę potraktować jako dwa słowa: "biało" oraz "czerwony"). Od razu mówię, że nie jest to jakaś norma ISO tylko moja zachcianka. Jak ktoś chce, niech robi po swojemu...

Czyli w kolejnym kroku zamieniam wszystkie łączniki na spacje:

tr '-' ' ' < ./posts1-nohtml.txt > ./posts2-nohyphens.txt

Kolejnym krokiem będzie wywalenie wszystkich znaków niebędących literą lub spacją. W ten sposób pozbywamy się za jednym zamachem wszystkich cyfr oraz całej interpunkcji:

cat ./posts2-nohyphens.txt | sed 's/[^a-z\ A-ZżźćńąśłęóŻŹĆŃĄŚŁĘÓ]//g' > ./posts3-lettersonly.txt

Proszę zauważyć, że osobno wyszczególniam polskie znaki diakrytyczne - według linuksowego REGEX-a ą nie znajduje zię między a-z tylko gdzieś indziej. Jeżeli tego nie zrobimy, pozbawimy się też polskich znaczków.

Następnie zamieniamy wszystkie wielkie litery na małe:

tr [:upper:] [:lower:] < ./posts3-lettersonly.txt > ./posts4-small.txt

Niestety, podobnie jak w poprzednim kroku, również i tutaj trzeba pamiętać o osobnym potraktowaniu polskich znaczków - zamiana dużych na małe za pomocą [:upper:] / [:lower:] nie działa dla liter innych niż standardowe łacińskie:

tr [ŻŹĆŃĄŚŁĘÓ] [żźćńąśłęó] < ./posts4-small.txt > ./posts5-small2.txt

Następnie zamieniamy wszystkie znaki końca linii na spacje:

tr '\n' ' ' < ./posts5-small2.txt > ./posts6-eol1.txt
tr '\r' ' ' < ./posts6-eol1.txt > ./posts7-eol2.txt

Poprzedni krok na pewno wyprodukował nam sporo wielokrotnych spacji, które trzeba usunąć (pozostawić wyłącznie pojedyncze spacje). Na szczęście ktoś przed nami już kiedyś miał ten problem, więc rozwiązanie da się znaleźć na Google w pięć sekund:

tr -s ' ' < ./posts7-eol2.txt > ./posts8-spaces.txt

W tej chwili nasz plik roboczy posts8-spaces.txt zawiera wszystkie słowa z naszego bloga zapisane w jednej linii, oddzielone spacjami. Jednym z ostatnich kroków będzie zamiana spacji na znaki końca linii - w ten sposób dostaniemy plik, w którym każde słowo będzie w osobnym wierszu:

tr ' ' '\n' < ./posts8-spaces.txt > ./post9-words.txt

Już witamy się z gąską. Teraz tylko jeszcze trzeba słowa posortować alfabetycznie...

sort ./post9-words.txt > ./posts10-sorted.txt

... policzyć...

uniq -c ./posts10-sorted.txt > ./posts11-count.txt

... i na koniec posortować według częstości występowania:

sort -n ./posts11-count.txt > ./wynik.txt

Szybki rzut oka na wynik.txt i już wiemy, że najczęściej pojawiającym się słowem jest "w". Zaraz za nim mamy: się na i z nie do to a że jest po jak ale od za tak co już więc mi ma tym tylko sobie jeszcze tego czy jednak przez może bardzo żeby no oraz są dla było jeżeli będzie albo mnie można bo też ze pan trzeba...

Na drugim końcu skali są wyrazy, które występują tylko raz - nie będę ich tu wymieniał, ponieważ jest ich ponad 55%. A więc ponad połowa treści tego bloga to wyrazy, które nie pojawiają się ponownie. Aczkolwiek gdyby uwzględnić odmiany, odsetek ten pewnie trochę by się zmniejszył.

Interesujące...

Łącznie różnych wyrazów jest na moim blogu trochę ponad 74000. Z tym, że znów należy pamiętać o odmianach, więc faktyczna liczba jest pewnie dużo mniejsza. Ale to już temat na kiedy indziej. Trzeba by jakoś do tego zadania zaprząc słownik z odmianami... Dwujęzyczny... Nie, aż tak mi się nudzić chyba nie będzie 😉

https://xpil.eu/jYbpP

3 komentarze

  1. Nie trzeba słownika z odmianami, wystarczy prosty stemmer – dla angielskiego jest ich w cholerę i trochę, nawet z poziomu komend można się bawić, dla polskiego też się coś znajdzie, choć już nie tak prosto.
    A żeby pousuwać “w” et consortes też niekiedy wystarczy jakaś komenda, zależy od narzędzia używanego – w ostateczności można prosty tekstowy zestaw stopwords zaimportować dla dowolnego języka 🙂

    1. Wszystko się zgadza. Jak kiedyś będę miał chwilę i natchnienie, pewnie się w to pobawię. Póki co zostawiam jak jest 🙂

Leave a Comment

Komentarze mile widziane.

Jeżeli chcesz do komentarza wstawić kod, użyj składni:
[code]
tutaj wstaw swój kod
[/code]

Jeżeli zrobisz literówkę lub zmienisz zdanie, możesz edytować komentarz po jego zatwierdzeniu.