Niezrównoważone dane powodujące błędną klasyfikację zestawu danych wieloklasowych

9

Pracuję nad klasyfikacją tekstu, w której mam 39 kategorii / klas i 8,5 miliona rekordów. (W przyszłości dane i kategorie wzrosną).

Struktura lub format moich danych jest następująca.

----------------------------------------------------------------------------------------
| product_title          | Key_value_pairs                               | taxonomy_id |
----------------------------------------------------------------------------------------
  Samsung S7 Edge        | Color:black,Display Size:5.5 inch,Internal    | 211 
                          Storage:128 GB, RAM:4 GB,Primary Camera:12 MP  

  Case cover Honor 8     | Color:transparent,Height:15 mm,width:22 mm    | 212 

  Ruggers Men's T-Shirt  | Size:L,ideal for:men,fit:regular,             | 111
                          sleeve:half sleeve

  Optimum Nutrition Gold | Flavor:chocolate,form:powder,size:34 gm       | 311
  Standard Whey Protein  

Dystrybucja danych nie jest normalna; jest wysoce niezrównoważony:

-------------------------
| taxonomy_id |   count |
-------------------------
          111 |  851750 
          112 |  355592
          113 |  379433
          114 |   23138
          115 |  117735
          116 |  145757
          117 | 1339471
          121 |  394026
          122 |  193433
          123 |   78299
          124 |  111962
          131 |    1776
          132 |    4425
          133 |     908
          134 |   23062
          141 |   22713
          142 |   42073
          211 |    7892
          212 | 1574744
          221 |    1047
          222 |  397515
          223 |   53009
          231 |    1227
          232 |    7683
          251 |     739
          252 |     327
          253 |   38974
          254 |      25
          311 |    2901
          321 |    7126
          412 |     856
          421 |  697802
          422 |  414855
          423 |   17750
          425 |    1240
          427 |     658
          429 |    1058
          431 |   20760
          441 |     257       

Jak widać, są one wysoce niezrównoważone i prowadzą do błędnej klasyfikacji.

Kroki, które wykonałem do tej pory

1) Scal kolumnę product_title i key_value_pairs i usuń słowa stop oraz znaki specjalne i wykonaj tworzenie.

2) Użyłem potoku dla TFIDFvectorizer (), LinearSVC ()

vectorizerPipe = Pipeline([
                 ('tfidf', TfidfVectorizer(lowercase=True, stop_words='english')),
                 ('classification', OneVsRestClassifier(LinearSVC(penalty='l2', loss='hinge'))),
                 ])

Następnie dopasowałem rurociąg i umieściłem klasyfikator w marynacie

prd = vectorizerPipe.fit(df.loc[:, 'description'], df.loc[:, 'taxonomy_id'])

Po stronie testowej powtórzyłem krok 1, jak wspomniano powyżej, a następnie załadowałem marynatę i użyj funkcji przewidywania

pd = cl.predict([testData])

Problemy, przed którymi stoję

  1. Wiele produktów jest błędnie klasyfikowanych do niektórych innych kategorii

    Przykład: Ultimate Nutrition Prostar 100% białko serwatki należy zaklasyfikować do kategorii 311, ale mój klasyfikator klasyfikuje je jako 222, co jest całkowicie błędne.

  2. Nie jestem pewien, czy użyć TFidfVectorizer () czy Hashingvectorizer (), czy możecie mi pomóc w wyborze jednego z nich wraz z ich parametrami?

  3. Algorytm, którego używam, to LinearSVC, czy to dobry wybór w przypadku problemów z klasyfikacją wielu klas z dużą ilością danych? Czy powinienem używać różnych algorytmów?

  4. Ponieważ moje dane są wysoce niezrównoważone, próbowałem losowego testowania próbkowania. Wyniki uległy poprawie, ale nadal nie były na granicy. Nie jestem również pewien, czy jest to właściwe podejście do losowego niepełnego próbkowania:

    pipe = make_pipeline_imb(
        HashingVectorizer(lowercase=True),
        RandomUnderSampler(ratio={111: 405805, 112: 170431, 113: 241709, 114: 8341, 115: 50328, 116: 89445, 117: 650020, 121: 320803, 122: 162557, 123: 66156, 124: 36276, 131: 1196, 132: 3365, 133: 818, 134: 15001, 141: 6145, 142: 31783, 211: 24728, 212: 100000, 221: 791, 222: 8000, 223: 35406, 231: 785, 232: 3000, 251: 477, 252: 127, 253: 29563, 254: 33, 311: 2072, 321: 5370, 412: 652, 421: 520973, 422: 99171, 423: 16786, 425: 730, 427: 198, 429: 1249, 431: 13793, 441: 160},random_state=1), 
        OneVsRestClassifier(LinearSVC(penalty='l2', loss='hinge')))
    
  5. Jestem nowy w uczeniu maszynowym, więc zastosowałem to podejście do klasyfikacji tekstu. Jeśli moje podejście jest błędne, popraw mnie, używając właściwego.

(Byłoby wspaniale, gdybyś podał sugestię lub rozwiązanie z przykładami, ponieważ pomoże mi to lepiej zrozumieć).

*** EDIT-1 ****

RndmFrst = RandomForestClassifier(n_estimators=100, max_depth=20, max_features=5000,n_jobs=-1)
LogReg = LogisticRegression()
voting = VotingClassifier(estimators=[('LogReg ', LogReg), ('RndmFrst', RndmFrst)], voting='soft', n_jobs=-1)

pipe = Pipeline([('tfidf', TfidfVectorizer(ngram_range=(1,4), max_features=50000)), ('clf', voting)])

pipe = pipe.fit(df.loc[:,'description'], df.loc[:,'taxonomy_id'])
Preds = pipe.predict(test_data)
odstające
źródło
Właśnie widziałem, że próbujesz niedostatecznego próbkowania. Tylko fyi, Rozpoczęta walidacja krzyżowa K-fold w Sci-Kit Learn uwzględnia również rozkład klas.
Kasra Manshaei

Odpowiedzi:

6

Dobre pytanie!

Kilka uwag

W przypadku niezrównoważonych danych masz różne podejścia. Najbardziej ugruntowaną jest ponowne próbkowanie (nadmierne próbkowanie małych klas / niedoszacowywanie dużych klas). Drugim jest zhierarchizowanie klasyfikacji, tj. Sklasyfikowanie dużych klas względem wszystkich innych, a następnie sklasyfikowanie małych klas w drugim etapie (klasyfikatory nie powinny być takie same. Spróbuj znaleźć strategie wyboru modelu, aby znaleźć najlepszą).

Praktyczna odpowiedź

Mam akceptowalne wyniki bez ponownego próbkowania danych! Spróbuj, ale później popraw go za pomocą metod ponownego próbkowania (statystycznie MUSZĄ to być).

TFIDF jest dobry na taki problem. Klasyfikatory powinny być wybierane poprzez wybór modelu, ale moje doświadczenie pokazuje, że regresja logistyczna i losowy las działają dobrze na ten konkretny problem (jednak jest to tylko praktyczne doświadczenie).

Możesz postępować zgodnie z poniższym kodem, ponieważ działał on po prostu dobrze, a następnie możesz go zmodyfikować, aby poprawić swoje wyniki:

train = pd.read_csv(...)
test = pd.read_csv(...)    

# TFIDF Bag Of Words Model For Text Curpos. Up to 4-grams and 50k Features
vec = TfidfVectorizer(ngram_range=(1,4), max_features=50000)
TrainX = vec.fit_transform(train)
TestX = vec.transform(test)


# Initializing Base Estimators
clf1 = LogisticRegression()
clf2 = RandomForestClassifier(n_estimators=100, max_depth=20, max_features=5000,n_jobs=-1)

# Soft Voting Classifier For Each Column
clf = VotingClassifier(estimators=[('lr', clf1), ('rf', clf2)], voting='soft', n_jobs=-1)
clf = clf.fit(TrainX, TrainY)
preds = clf.predict_proba(TestX)[:,1]

Pamiętaj, że kod jest abstrakcyjny, więc TianX, TrainY, TestX itp. Powinny być poprawnie zdefiniowane przez Ciebie.

Poradnik

Uważaj na to, co jest StopWord. Praktycznie wiele osób (w tym ja!) Popełniło ten błąd, usuwając słowa stop zgodnie z wcześniej zdefiniowanymi listami. To nie jest poprawne!

Słowa stop są wrażliwe na korpusy, więc musisz usunąć stopery zgodnie z teoretycznymi pojęciami informacyjnymi (dla uproszczenia musisz wiedzieć, że TFIDF ignoruje specyficzne dla korpusu hasła. Jeśli potrzebujesz więcej wyjaśnień, daj mi znać, aby zaktualizować moją odpowiedź) .

VotingClassifier to strategia meta-uczenia się w rodzinie Ensemble Methods . Korzystają z różnych klasyfikatorów. Wypróbuj je, ponieważ sprawdzają się w praktyce.

Schemat głosowania po prostu bierze wyniki różnych klasyfikatorów i zwraca wynik tego, który ma największe prawdopodobieństwo, że ma rację. Takie rodzaj demokratycznego podejścia przeciwko dyktaturze;)

Mam nadzieję, że to pomoże!

Kasra Manshaei
źródło
Witamy! W celu intuicyjnego ponownego próbkowania możesz skorzystać z linku, który umieszczam w celu ponownego próbkowania. Istnieje instrukcja krok po kroku.
Kasra Manshaei
Próbuję twojego rozwiązania, jeśli utknąłem gdziekolwiek lub w razie jakichkolwiek wątpliwości opublikuję w sekcji komentarzy. mam nadzieję, że ci się spodoba!
odstające
na pewno mój przyjacielu ... powodzenia!
Kasra Manshaei
1
jeśli zadziałało, możesz zaakceptować odpowiedź :)
Kasra Manshaei
@outlier, ponieważ odpowiedź rozwiązała Twój problem, uprzejmie go zaakceptuj (i ewentualnie głosuj pozytywnie); odpowiedzi zajmują cenny czas dla (ochotników) respondentów
desertnaut