如何解决在Python中对稀疏数据集进行过采样
我有一个包含多标签数据的数据集。共有20个标签(从0到20),它们之间的分布不平衡。这是数据概述:
|id |label|value |
|-----|-----|------------|
|95534|0 |65.250002088|
|95535|18 | |
|95536|0 | |
|95536|0 |100 |
|95536|0 | |
|95536|0 |53.68547236 |
|95536|0 | |
|95537|1 | |
|95538|0 | |
|95538|0 | |
|95538|0 | |
|95538|0 |656.06155202|
|95538|0 | |
|95539|2 | |
|5935 |0 | |
|5935 |0 |150 |
|5935 |0 |50 |
|5935 |0 |24.610985335|
|5935 |0 | |
|5935 |0 |223.81789584|
|5935 |0 |148.1805218 |
|5935 |0 |110.9712538 |
|34147|19 |73.62651909 |
|34147|19 | |
|34147|19 |53.35958016 |
|34147|19 | |
|34147|19 | |
|34147|19 | |
|34147|19 |393.54029411|
我希望对数据进行过度采样,并在标签之间取得平衡。我遇到了诸如SMOTE
和SMOTENC
之类的一些方法,但是它们都需要将数据拆分为训练集和测试集,并且无法使用稀疏数据。有什么办法可以在拆分之前的预处理步骤中对整个数据执行此操作?
解决方法
实际上,从理论上讲,您不需要对测试集进行升采样。
在类不平衡设置中,人为地平衡测试/验证集没有任何意义:这些集必须保持现实,即您要在现实世界中测试分类器的性能,例如,否定类将包括99%的样本,以便了解您的模型在预测1%的正阳性兴趣类别而没有太多假阳性时的表现如何。人为地夸大少数派或减少少数派将导致性能指标不切实际,与您要解决的现实问题没有任何实际联系。
重新平衡仅在训练集中才有意义,这样可以防止分类器将所有实例简单,天真地分类为负值,以达到99%的感知准确性。
因此,您可以放心,在您描述的设置中,重新平衡仅适用于训练组/折叠次数。
,要对行进行采样,以便以相等的概率对每个label
进行采样:
- 绘制给定标签行的可能性应该为
1/n_labels
- 对于给定标签
l
绘制给定行的概率应为该标签中n_rows的1/n_rows
则每一行的概率为p_row = 1/(n_labels*n_rows)
。您可以使用groupby生成这些值,并将它们传递给df.sample,如下所示:
import numpy as np
import pandas as pd
df_dict = {'id': {0: 95535,1: 95536,2: 95536,3: 95536,4: 95536,5: 95536,6: 95537,7: 95538,8: 95538,9: 95538,10: 95538,11: 95538,12: 95539,13: 5935,14: 5935,15: 5935,16: 5935,17: 5935,18: 5935,19: 5935,20: 5935,21: 34147,22: 34147,23: 34147,24: 34147,25: 34147,26: 34147,27: 34147},'label': {0: 18,1: 0,2: 0,3: 0,4: 0,5: 0,6: 1,7: 0,8: 0,9: 0,10: 0,11: 0,12: 2,13: 0,14: 0,15: 0,16: 0,17: 0,18: 0,19: 0,20: 0,21: 19,22: 19,23: 19,24: 19,25: 19,26: 19,27: 19},'value': {0: ' ',1: ' ',2: '100 ',3: ' ',4: '53.68547236 ',5: ' ',6: ' ',7: ' ',8: ' ',9: ' ',10: '656.06155202',11: ' ',12: ' ',13: ' ',14: '150 ',15: '50 ',16: '24.610985335',17: ' ',18: '223.81789584',19: '148.1805218 ',20: '110.9712538 ',21: '73.62651909 ',22: ' ',23: '53.35958016 ',24: ' ',25: ' ',26: ' ',27: '393.54029411'}}
df = pd.DataFrame.from_dict(d)
# create column that includes counts by label
n_labels = df.label.nunique()
n_rows = df.groupby("label").id.transform("count")
weights = 1/(n_rows*n_labels)
# sanity check probabilities:
bool(np.sum(weights) == 1)
df_samples = df.sample(n=40000,weights=weights,replace=True,random_state=19)
确认标签绘制大致相同:
print(df_samples.label.value_counts()/len(df_samples))
# sampling frequency by group:
# 0 0.203325
# 2 0.201075
# 18 0.200925
# 19 0.198850
# 1 0.195825
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。