Stylometria: czego używa polska policja? Prezent świąteczny dla naszych czytelników!

payload.pl 3 lat temu

Zaciekawiony świetnym artykułem Marzeny nt. wykorzystania stylometrii w informatyce śledczej, postanowiłem dokładniej obejrzeć się prezentacji Edwarda Szczypki i Wojciecha Pilszaka, w której omawiają oni, w jaki sposób polska policja używa stylometrii przeciwko wybranym grupom społecznym.

Marzena w swoim artykule nt. stylometrii przytoczyła m.in. 2 filmy, teoretycznie przedstawiające tą samą prezentację, natomiast na pierwszym brakuje paru szczegółów, które można wyciągnąć z drugiego.

Większość tej prezentacji ukazuje kod źródłowy realnego narzędzia do analizy stylometrycznej plików tekstowych, co mnie, jako byłego programistę, szczególnie zainteresowało - zwłaszcza, iż pojęcie stylometrii stale przewija się w niektórych środowiskach, z którymi związani są m.in. czytelnicy PAYLOAD. Postawiłem sobie proste pytanie: czy jestem w stanie odtworzyć to narzędzie na podstawie filmu?

Aby nie przedłużać, odpowiedź brzmi TAK. Udało mi się całość odtworzyć, jak również poprawić kilka błędów popełnionych przez autorów, a choćby dołożyć kilka własnych usprawnień. Przyjmijcie je jako prezent świąteczny:

https://github.com/payloadpl/stylometria

Aby nie przedłużać, opiszę swoje doświadczenia z tym narzędziem, oraz generalne wnioski na przyszłość.

Eksperyment

Na potrzeby odtwarzania kolejnych skryptów zebrałem zbiór plików tekstowych o stosunkowo podobnej charakterystyce do tego, co opisywał prezentujący:

  • ok. połowa tekstów to artykuły i inne teksty z PAYLOAD mojego własnego autorstwa (a więc podobnie napisane)
  • kilka losowych, ale długich i napisanych poprawną polszczyzną opracowań autorstwa różnych osób (historia Pałacu Kultury i Nauki, długi i szczegółowy artykuł o zwycięstwie Donalda Trumpa w 2016, rozprawa doktorska związana z tematyką "hakerstwa", czasopismo z obszaru automatyki/elektroniki/IT/przemysłu)
  • 2 pisma urzędowe zawierające sporo sformułowań typu "dane osobowe": formularz będący wnioskiem do wypełnienia, oraz treść pewnej decyzji GIODO wraz z uzasadnieniem
  • 2 informacje prasowe
  • 3 teksty licencji w języku angielskim (a więc z całkiem innym zakresem słownictwa, inną budową zdań itd. - ale podobne względem siebie)

Przy domyślnych długościach n-gramów, heatmapa z wynikami generowana przez odtworzony skrypt, wygląda następująco:

Poza heatmapą generowana jest też tabelka w html, zawierająca porównanie różnych adekwatności poszczególnych tekstów. Ze względu na zbyt dużą szerokość, przeniosłem ją do osobnej podstrony.

Wymagania i zawartość repozytorium

Całość napisana jest w języku Python 3 i powinna działać zarówno pod Windows jak i Linuxem, również bez trybu graficznego (skrypty omawiane w prezentacji działają w trybie graficznym lub w ramach Jupyter Notebook, odtworzone wersje zapisują wyniki do plików zewnętrznych).

Zależności instaluje się dwoma poleceniami, uruchomionymi na konsoli jako root:

1. Zależności systemowe - potrzebne tylko do działania skryptu 2_1_linux.py, który konwertuje pliki w innych formatach na format tekstowy, co równie dobrze możesz zrobić manualnie (w przypadku Windows i skryptu 2_1_windows.py, konwersja jest dokonywana dzięki LibreOffice):

apt-get install python3 unrtf catdoc poppler-utils timelimit

2. Biblioteki dodatkowe dla języka Python 3:

pip3 install prettyprint matplotlib numpy seaborn

Repozytorium zawiera 12 skryptów Python 3, z czego naprawdę istotne są tylko:

  • 2_1_linux.py lub 2_1_windows.py, zależnie od systemu operacyjnego - skrypt ten konwertuje pliki z katalogu Data w innych formatach na format tekstowy (oryginalne pliki przez cały czas zostają na miejscu)
  • 2_2.py - zamienia on kodowanie znaków we wszystkich plikach *.txt z katalogu Data na UTF-8 (docelowe pliki są zapisywane w katalogu Process)
  • 2_3.py - usuwa on niepotrzebne znaki (wszystkie pliki *.txt w katalogu Process są przepisywane - docelowo wymaga to integracji z poprzednim skryptem, na tym etapie można też wprowadzić różne ulepszenia w czyszczeniu danych)
  • 3_4_poprawiony.py - dokonuje adekwatnej analizy przygotowanych wcześniej plików *.txt z katalogu Process, jako wynik zapisuje heatmapę w formacie PNG i plik html z tabelką z adekwatnościami poszczególnych tekstów (patrz wyżej)

Pozostałe skrypty służą do podglądu wyników cząstkowych na różnych etapach przejściowych - numeracja plików odnosi się do numeracji zastosowanej w oryginalnej prezentacji, a w ich wnętrzu znajdziecie też znaczniki czasowe kluczowych momentów filmu. Dzięki temu dostajecie nie tylko gotowe rozwiązanie, ale też pełny instruktaż pozwalający zrozumieć, o co w tej całej stylometrii tak naprawdę chodzi.

Moje własne wnioski z eksperymentu

Szczerze mówiąc, trochę się zawiodłem - przed zagłębieniem się w temat wydawało mi się, iż analiza stylometryczna pozwala we w miarę pewny sposób rozróżnić autorów różnych tekstów, albo jednoznacznie przypisać autorstwo jakiegoś tekstu konkretnej osobie.

W praktyce okazuje się, iż teksty wielu różnych osób, na różne tematy, ale napisane:

  • poprawną i dość prostą polszczyzną, w szczególności z poprawną gramatyką i budową zdań, bez nadużywania zdań złożonych
  • w dziennikarskim stylu, czyli z określoną strukturą, jakiej można nauczyć się na studiach kierunkowych
  • w skupieniu na temacie, bez rozwlekania się na tematy poboczne
  • bez użycia mowy nieformalnej (slangu, "opisów przyrody", mowy "teatralnej", lub innego charakterystycznego sposobu wyrażania się - patrz np. film Dzień Świra jako ewidentny przykład)
  • bez nadmiaru dziwnych lub zbyt specjalistycznych słów

są do siebie pod wieloma względami (np. średniej długości zdań, czy dominacji słowa "nie") bardzo podobne - choćby dotycząc zupełnie różnych dziedzin. Zbyt podobne, aby takie narzędzie w sposób samodzielny (bez pomocy analityka), przy pomocy kilku kluczowych zmiennych mogło wydać "werdykt" o autorstwie lub zaprzeczeniu autorstwa.

Oczywiście widać drobne różnice pomiędzy takimi tekstami różnego autorstwa (każdy autor ma jakieś swoje nieświadome naleciałości, choćby starając się pisać w podobny, "dziennikarski" sposób) - tyle bez wprawnego oka analityka nie da się ich odróżnić od drobnych różnic pomiędzy różnymi tekstami tego samego autorstwa.

Sytuacja zmienia się diametralnie, gdy próbujemy dzięki metod stylometrycznych porównywać dzieła literackie - np. lektury szkolne. W przypadkach takich tekstów, stylometria pozwala dokładnie policzyć i zobaczyć to, co nauczyciele języka polskiego starają się wyjaśnić uczniom "na wyczucie". Tyle tylko, iż w przypadku tak ewidentnych różnic, stylometria nie wnosi zbyt wiele nowego: różnice między stylem poszczególnych lektur widać i "czuć" gołym okiem, a stylometria pozwala je "jedynie" sprowadzić do postaci policzalnej.

Czy to znaczy, iż stylometria do niczego się nie nadaje?

Tego bym absolutnie nie powiedział. przez cały czas widzę w analizie stylometrycznej bardzo wielki potencjał. Natomiast widzę go po pierwsze w analizie prowadzonej przez analityka zajmującego się tym zawodowo, który:

  • zna dobrze analizowany język i jego niuanse
  • zna przynajmniej podstawy statystyki
  • rozumie zależności pomiędzy np. długością n-gramów a ich poziomem specyficzności - i co za tym idzie, potrafi ad hoc tuningować stosowane narzędzia, aby uwypuklić oceniane cechy, nie zniekształcając pozostałych
  • zna jakiś język programowania (najlepiej Python i/lub R) i narzędzia statystyczne dostępne w tym języku, oraz potrafi ad hoc tworzyć proste skrypty zliczające jakieś konkretne, manualnie wypatrzone cechy w analizowanych tekstach

Po drugie zaś, stylometria pomimo powyższych ograniczeń, choćby w dość prymitywnej wersji może być świetnym narzędziem do wczesnej analizy "manifestów" różnych szaleńców, które często są przez nich publikowane na długo przed adekwatnym "wyczynem". Większość takich "manifestów" jest bowiem wyłącznie próbą zwrócenia na siebie uwagi, a działania autora kończą się na publikacji i promowaniu samego manifestu - w takich przypadkach sam manifest też często okazuje się być mniej lub bardziej przerobioną kopią wcześniej napisanych tekstów. Analiza stylometryczna powinna tu pomóc wychwytywać przypadki manifestów podejrzanie samodzielnych, gdzie można domniemać, iż autor musiał włożyć w taki manifest ponadprzeciętną ilość pracy - a więc jest też dużo większe ryzyko, iż ów manifest jest tylko wstępem do dalszych działań.

Wreszcie po trzecie, widzę taki potencjał w narzędziu dużo bardziej zaawansowanym od tego, które zostało przedstawione podczas prezentacji, i które dla Was odtworzyłem.

Przypuszczam też, iż polska policja już w momencie wygłaszania tej prezentacji dysponowała znacznie bardziej rozbudowanym narzędziem od prezentowanego - za tą tezą przemawia fakt, iż prezentowany kod wyglądał na upraszczany na szybko, bez zwracania uwagi na drobne błędy.

No właśnie, co można w tych skryptach poprawić?

Całą masę drobnych rzeczy - przede wszystkim jednak należy zdać sobie sprawę, iż odtworzony skrypt to tylko jedno z wielu narzędzi, których analityk używa jednocześnie. W ogóle nie ma w nim np. analizy błędów ortograficznych, czy analizy końcówek wyrazów związanych z płcią (np. -łem vs -łam).

W szczególności nasunęły mi się następujące kwestie do poprawy:

  • w metodzie GetSentences można dorobić dużo bardziej inteligentne dzielenie tekstu na zdania, obecny sposób nie obsługuje bowiem kropek w skrótach ani w liczbach ("np. port USB 2.0" - to sformułowanie zostanie w tej chwili policzone jako 3 zdania)
  • zmienne wordNGram i byteNGram na początku skryptu 3_4_poprawiony.py (obecne wartości zdają się działać optymalnie przy opisanym wyżej zestawie porównywanych tekstów, ale w przypadku np. innego języka lub po prostu innej specyfiki tekstów, delikatny tuning tych parametrów może mieć sens) można by wyciągać z jakiegoś profilu konfiguracyjnego, dostarczanego wraz z zestawem porównywanych tekstów
  • podobnie dodanie wywołania strip() wewnątrz metody GetByteNGrams, aby skracać n-gramy bajtowe mające na początku lub końcu spację - funkcją taką można by sterować z poziomu powyższego profilu konfiguracyjnego

Tyle jeżeli chodzi o kwestie "rozwojowe". Z bardziej "przyziemnych" rzeczy można też:

  • skrypty 2_2.py i 2_3.py połączyć w jeden skrypt, przepisujący pliki tylko raz
  • w skrypcie 2_1_linux.py dodać obsługę nowych formatów plików, co najmniej Office 2007 i nowszych
  • w skrypcie 2_1_windows.py również dodać obsługę nowych formatów plików i być może spróbować zastąpić użyty tam LibreOffice jakimiś sensowniejszymi konwerterami

Co dalej?

Nie ukrywam, iż mam inne priorytety, niż rozwój tego narzędzia - osobiście nie jest mi ono do niczego potrzebne, gdyż ani nie ukrywam własnej tożsamości, ani nie próbuję demaskować nikogo innego. Odtworzenie go na podstawie prezentacji było ciekawym sposobem na oderwanie się od tzw. codzienności i spędzenie czasu nad czymś kompletnie nowym - ale to tyle.

Oddaję Wam gotowe, działające narzędzie jako prezent. Jego dalszy rozwój należy już do Was.

Ale to nie koniec. Możecie przysyłać nam swoje propozycje zmian: mailem na adres kontakt redakcji kontakt@payload.pl (tak jak wszystkie inne materiały, na które chcecie zwrócić naszą uwagę), albo bezpośrednio do mnie, korzystając z mechanizmów GitHuba (Issues i Pull requests).

Jeśli Wasze zmiany zostaną zaakceptowane (kryteria: muszą wnosić jakąś nową wartość + kod dobrej jakości), dostaniecie od nas upominkowy kubek z logotypem PAYLOAD, oraz niepowtarzalną pocztówkę z moim osobistym, odręcznym podziękowaniem.


Intencją autorów ani wydawcy treści prezentowanych w magazynie PAYLOAD nie jest namawianie bądź zachęcanie do łamania prawa. jeżeli popełniłeś lub masz zamiar popełnić przestępstwo, bądź masz wątpliwości, czy Twoje działania nie będą łamać prawa, powinieneś skonsultować się z najbliższą jednostką Policji lub Prokuratury, a jeżeli są one związane z pieniędzmi, dla pewności również z Urzędem Skarbowym.

Nie zezwala się na użycie treści prezentowanych w magazynie PAYLOAD, ani produktów dostępnych w sklepie PAYLOAD, do celów popełniania przestępstw lub przestępstw skarbowych.

Idź do oryginalnego materiału