Klasyfikowanie dokumentów w kategoriach

Mam około 300K dokumentów przechowywanych w bazie Postgres, które są oznaczone kategoriami tematycznymi(w sumie jest około 150 kategorii). Mam jeszcze 150K dokumentów, które nie mają jeszcze kategorii. Staram się znaleźć najlepszy sposób na ich programową kategoryzację.

Badałem NLTK i jego naiwny klasyfikator Bayesa. Wydaje się dobrym punktem wyjścia (jeśli możesz zaproponować lepszy algorytm klasyfikacji dla tego zadania, zamieniam się w słuch).

Mój problem czy to, że nie mam wystarczająco dużo pamięci RAM, aby trenować NaiveBayesClassifier na wszystkich 150 kategoriach / 300K dokumentów na raz (trening na 5 kategoriach używanych 8GB). Co więcej, dokładność klasyfikatora wydaje się spadać, gdy trenuję więcej kategorii(dokładność 90% przy 2 kategoriach, 81% przy 5, 61% przy 10).

Czy powinienem po prostu szkolić klasyfikatora na 5 kategorii na raz i przepuścić wszystkie 150K dokumentów przez klasyfikator, aby sprawdzić, czy są dopasowania? Wygląda na to, że to zadziała, z tym, że będzie jest dużo fałszywych alarmów, w których dokumenty, które nie pasują do żadnej z kategorii, trafiają do klasyfikatora tylko dlatego, że jest to najlepsze dopasowanie Dostępne... Czy istnieje sposób, aby mieć opcję "Brak z powyższych" dla klasyfikatora na wypadek, gdyby dokument nie pasował do żadnej z kategorii?

Oto moja klasa testowa http://gist.github.com/451880

Author: erikcw, 2010-06-24

3 answers

Powinieneś zacząć od konwersji dokumentów na TF-log(1 + IDF) wektory : częstotliwości term są rzadkie, więc powinieneś użyć Pythona dict z term jako kluczami i liczyć jako wartości, a następnie podzielić przez całkowitą liczbę, aby uzyskać globalne częstotliwości.

Innym rozwiązaniem jest użycie abs(hash (term)) na przykład jako dodatnich kluczy całkowitych. Więc używasz scypy.nieliczne wektory, które są bardziej poręczne i wydajniejsze do wykonywania operacji algebry liniowej niż dict Pythona.

Także zbuduj wektory częstotliwości 150, uśredniając częstotliwości wszystkich oznaczonych dokumentów należących do tej samej kategorii. Następnie, aby nowy dokument mógł zostać oznaczony etykietą, możesz obliczyć cosinusowe podobieństwo między wektorem dokumentu A każdym wektorem kategorii i wybrać najbardziej podobną kategorię jako etykieta dla dokumentu.

Jeśli to nie jest wystarczająco dobre, powinieneś spróbować trenować model regresji logistycznej za pomocą kary L1, jak wyjaśniono w ten przykład z scikit-learn (jest to wrapper dla liblinear, jak wyjaśnia @ephes). Wektory używane do trenowania modelu regresji logistycznej powinny być wcześniej wprowadzonymi wektorami TD-log (1 + IDF), aby uzyskać dobrą wydajność(precyzję i przypomnienie). Scikit learn lib oferuje sklearn.moduł metryki z procedurami do obliczania tych wyników dla danego modelu i danego zbioru danych.

Dla większych zbiorów danych: powinieneś wypróbować vowpal wabbit który jest prawdopodobnie najszybszym królikiem na ziemi dla problemy z klasyfikacją dokumentów na dużą skalę (ale niełatwe w użyciu wrappery Pythona AFAIK).

 32
Author: ogrisel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-09 16:32:58

Jak duże (liczba słów) są Twoje dokumenty? Zużycie pamięci przy 150K trainingdocs nie powinno stanowić problemu.

Naive Bayes jest dobrym wyborem zwłaszcza, gdy masz wiele kategorii z zaledwie kilkoma przykładami treningu lub bardzo hałaśliwym treningiem. Ale ogólnie rzecz biorąc, liniowe Maszyny wektorowe działają znacznie lepiej.

Czy twój problem jest multiclass (dokument należy tylko do jednej kategorii) lub multilabel (dokument należy do jednej lub więcej kategorii)?

Dokładność jest słabym wyborem do oceny wydajności klasyfikatora. Powinieneś raczej użyć precision vs recall, precision recall breakeven point( prbp), f1, auc i musisz spojrzeć na krzywą precision vs recall, gdzie przypomnienie (x) jest wykreślone z precyzją (y) na podstawie wartości progu ufności (jeśli dokument należy do kategorii lub nie). Zazwyczaj można zbudować jeden klasyfikator binarny dla każdej kategorii (pozytywne przykłady szkoleń z jednej kategorii vs wszystkie inne szkolenia które nie należą do Twojej bieżącej kategorii). Musisz wybrać optymalny próg zaufania dla każdej kategorii. Jeśli chcesz połączyć te pojedyncze miary dla każdej kategorii w globalną miarę wydajności, musisz uzyskać średnią mikro (zsumować wszystkie wyniki pozytywne, fałszywe pozytywy, fałszywe negatywy i prawdziwe negatywy oraz połączone wyniki calc) lub makro (wynik calc dla kategorii, a następnie uśrednić te wyniki we wszystkich kategoriach).

Mamy korpus kilkudziesięciu milionów dokumentów, miliony przykłady szkoleń i tysiące kategorii (multilabel). Ponieważ borykamy się z poważnymi problemami związanymi z czasem szkolenia (liczba dokumentów dziennie jest dość wysoka), stosujemy zmodyfikowaną wersję liblinear. Ale w przypadku mniejszych problemów użycie jednej z owijarek Pythona wokół liblinear (liblinear2scipy lub scikit-learn ) powinno działać poprawnie.

 11
Author: ephes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-24 20:45:05

Czy jest sposób, aby mieć " żaden z powyżej " opcja dla klasyfikatora tylko w przypadku gdy dokument nie pasuje do któraś z kategorii?

Możesz uzyskać ten efekt po prostu, mając za każdym razem trenowaną pseudokategorię "żaden z powyższych". Jeśli max możesz trenować to 5 kategorii (choć nie jestem pewien, dlaczego pochłania tyle pamięci RAM), trenuj 4 rzeczywiste kategorie z ich rzeczywistych dokumentów 2K każda i "żaden z powyższych" z dokumentami 2K losowo ze wszystkich pozostałych 146 kategorii (około 13-14 z każdej, jeśli chcesz "warstwowego pobierania próbek" podejście, które może być bardziej dźwięczne).

Nadal wydaje się być trochę kludge i może być lepiej z zupełnie innym podejściem-znajdź wielowymiarową miarę doc, która definiuje Twoje 300K wstępnie oznakowanych dokumentów w 150 rozsądnie rozdzielnych klastrów, a następnie po prostu przypisać każdy z innych jeszcze nie oznakowanych dokumentów do odpowiedniego klastra, jak określono w ten sposób. Chyba NLTK nie ma wszystko bezpośrednio dostępne do obsługi tego rodzaju rzeczy, ale hej, NLTK rośnie tak szybko, że mogłem coś przeoczyć...;-)

 2
Author: Alex Martelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-24 20:42:55