不平衡的数据导致多类数据集的错误分类

数据挖掘 机器学习 Python 分类 scikit-学习 多类分类
2021-10-07 09:30:01

我正在研究文本分类,其中有 39 个类别/类和 850 万条记录。(在未来的数据和类别将增加)。

我的数据的结构或格式如下。

----------------------------------------------------------------------------------------
| 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  

数据分布不正常;它是高度不平衡的:

-------------------------
| 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       

如您所见,它们高度不平衡并导致错误分类。

到目前为止我已经执行的步骤

1)合并product_title和key_value_pairs列,去除停用词和特殊字符,进行词干提取。

2) 我使用了 TFIDFvectorizer()、LinearSVC() 的管道

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

在此之后,我安装了管道并将分类器存储在 pickle 中

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

在测试方面,我重复了上面提到的第 1 步,然后加载泡菜并使用预测功能

pd = cl.predict([testData])

我面临的问题

  1. 许多产品被错误分类为其他类别

    示例:Ultimate Nutrition Prostar 100% 乳清蛋白应归入类别 311,但我的分类器将其归类为 222,这是完全错误的。

  2. 我不确定是使用 TFidfVectorizer() 还是 Hashingvectorizer(),你们能帮我选择其中一个及其参数吗?

  3. 我使用的算法是LinearSVC,对于数据量大的多类分类问题,它是一个不错的选择吗?或者我应该使用不同的算法?

  4. 由于我的数据高度不平衡,我尝试了随机欠采样。结果有所改善,但仍达不到标准。另外我不确定这是否是执行随机欠采样的正确方法:

    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. 我是机器学习的新手,所以我使用这种方法进行文本分类。如果我的方法是错误的,请用正确的方法纠正我。

(如果您提供建议或解决方案并附有示例,那就太好了,因为它可以帮助我更好地理解)。

***编辑-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)
1个回答

好问题!

一些备注

对于不平衡的数据,您有不同的方法。最成熟的一个是重采样(过采样小类/欠采样大类)。另一种方法是使您的分类分层,即将大类与所有其他类进行分类,然后在第二步对小类进行分类(分类器不应该相同。尝试模型选择策略以找到最佳策略)。

实用答案

我没有重新采样数据就得到了可接受的结果!所以尝试一下,但后来使用重采样方法改进它(从统计上讲,它们是必须的)。

TFIDF 可以很好地解决这样的问题。分类器应该通过模型选择来选择,但我的经验表明,逻辑回归和随机森林在这个特定问题上效果很好(但这只是一个实践经验)。

您可以按照下面的代码进行操作,因为它运行良好,然后您可以尝试修改它以改善结果:

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]

请注意,代码是抽象的,因此 TianX、TrainY、TestX 等应由您正确定义。

提示

小心什么是 StopWord。几乎很多人(包括我自己!)都犯了这个错误,根据预定义的列表删除停用词。那是不对的!

停用词对语料库敏感,因此您需要根据信息论概念删除停用词(为简单起见,您需要知道 TFIDF 会忽略您特定于语料库的停用词。如果您需要更多解释,请告诉我以更新我的答案) .

VotingClassifier 是Ensemble Methods家族中的一种元学习策略。他们受益于不同的分类器。尝试它们,因为它们在实践中工作得很好。

投票模式只是获取不同分类器的结果,并返回最有可能正确的分类器的输出。这种反对独裁的民主方法;)

希望能帮助到你!