前言
众所周知,非平衡数据会极大的影响模型的评判效果,并且会过拟合。所以我们在处理数据的时候,首先需要做的是处理非平衡数据,使得各类型数据均衡。
一、处理非平衡数据的各种方法
1-1、欠采样(下采样)
下采样:
- 在自然语言处理中,下采样是指对文本数据进行降采样,即减少文本数据中词语的出现次数。这种处理方式可以有效地减少文本数据的维度,提高模型训练的效率,同时也可以避免过拟合的问题。
- 常见的下采样算法包括TF-IDF(Term Frequency-Inverse Document Frequency)算法和词汇表剪枝(Vocabulary Pruning)算法。TF-IDF算法通过计算文档中每个词语的频率和逆文档频率来衡量词语的重要性,并选择出现频率较高但又不是停用词的词语进行保留。而词汇表剪枝算法则是通过设置词语出现频率的阈值来删除出现频率较低的词语,从而达到降采样的目的。
- 需要注意的是,下采样虽然可以提高模型训练的效率,但也可能会导致信息的丢失。因此,在实际应用中需要根据具体的任务需求和数据情况来选择合适的下采样算法和参数,以平衡数据降维和信息保留之间的关系。
- 下列代码为对下采样的简单解释:
# define:下采样,是对非平衡数据中样本较多的那一类进行采样,使其等于样本量较少的那一类 # eg: Dataframe 列名为y的这一行,统计 0、1出现的频率 df['y'].value_counts() 0 143346 1 16225 Name: y, dtype: int64 # notice: 很明显的数据不均衡,对样本较多的0类进行采样,采样数量为样本量较少那一类的数量 # n:数量 也可以用frac参数直接取比例 df_y0_undersample = df[df['y'] == 0].sample(n=(df['y']==1).sum(), random_state=201) # 之后将他们连结在一起。 df = pd.concat([df[df['y'] == 1], df_y0_undersample])
1-2、过采样
过采样:
- 在自然语言处理中,过采样(oversampling)是指对文本数据进行过采样处理,即增加文本数据中某些词语的出现次数,以达到平衡数据分布的目的。过采样通常应用于数据不平衡的情况下,例如在文本分类任务中某些类别的样本数量很少,而另一些类别的样本数量很多的情况下,可以通过过采样的方式来平衡样本分布。
- 对非平衡数据中样本较少的那一类进行采样,一般做法是将其复制几遍来达到正负样本平衡,这样容易过拟合,所以使用较少
1-3、人工合成
人工合成:
- 常见的人工合成(过采样)算法包括SMOTE(Synthetic Minority Over-sampling Technique)算法和ADASYN(Adaptive Synthetic Sampling)算法。这些算法都是通过在数据集中生成新的样本来实现过采样的目的。具体来说,SMOTE算法会生成一些合成样本,这些样本是由少数类样本和它们的近邻点组合而成的,而ADASYN算法则是根据每个少数类样本周围的密度来生成不同数量的合成样本。
- 需要注意的是,过采样可能会导致过拟合的问题,因为在数据集中引入了一些人工生成的样本。因此,在实际应用中需要权衡过采样和过拟合之间的关系,根据具体的任务需求和数据情况来选择合适的过采样算法和参数。
- 下边以SMOTE为例:
# define:人为合成一些样本量较少的数据,来达到正负样本平衡,比较常用的方法就是SMOTE。 # SMOTE的算法原理如下:根据正负样本比例,确认采样的比例,即要合成样本的数量(k值),对于少数样本中的每个x,利用KNN算法,选取k个待采样的值x_n,然后对x_n进行如下运算得到对应的x_new:x_new=x+rand(1)*|x-x_n| # (rand(1)表示生成0-1之间的一个随机数) # 关于SMOTE算法的实现也由现成的库,我们直接pip安装就可以使用。 from collections import Counter from imblearn.over_sampling import SMOTE print('Original dataset shape {}'.format(Counter(y))) sm = SMOTE(random_state=42) X_res, y_res = sm.fit_sample(x, y) print('Resampled dataset shape {}'.format(Counter(y_res))) # 将模型进行封装,方便调用 def get_result_data(x,y): x_=scale(x,with_mean=True,with_std=True) x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.4,random_state=0) model=LogisticRegression() clf=model.fit(x_train,y_train) print("LR模型测试成绩:{:.2f}".format(clf.score(x_test,y_test))) y_pred=clf.predict(x_test) target_names = ['class 0', 'class 1'] print(classification_report(y_test, y_pred, target_names=target_names)) y_pred1=clf.decision_function(x_test) fpr,tpr,threshold=roc_curve(y_test,y_pred1) rocauc=auc(fpr,tpr)#计算AUC print("ROC分数:{:.2f}".format(rocauc)) if __name__=="__main__": get_result_data(X_res, y_res)
1-4、调整权重(效果较好而且快捷)
调整权重:
- 在自然语言处理中,由于某些类别的样本数量很少,而其他类别的样本数量很多,导致数据分布不平衡。这种情况下,调整权重是一种常见的处理方法之一。
- 调整权重的思路是给样本设置不同的权重,以强调少数类样本的重要性。在文本分类任务中,可以根据每个类别的样本数量来设置权重,具体地,可以使用倒数或平方根等函数来计算样本权重,如下所示:
- 其中 w i 表示第 i 个类别的样本权重,N表示第 i 个类别的样本数量。这种权重设置方式可以使得少数类样本的权重更大,从而在模型训练中更容易被捕捉到。
- 在实际应用中,除了调整样本权重之外,还可以采用其他方法来处理非平衡数据,例如过采样、下采样等方法,或者使用集成学习的方法,如基于bagging和boosting的方法等。需要根据具体的任务需求和数据情况来选择合适的方法,以提高模型的性能和泛化能力。
- 下边是一个简单的调整权重案例代码:
# define:人为合成一些样本量较少的数据,来达到正负样本平衡。即人为的定义不同样本的表决权重,比如正负样本绝对量的比值为1:10,为了抵消这种量级上的不平衡,我们在模型中可以给与模型正负样本10:1的表决权重,也就是10个正样本的表决相当于1个负样本的表决。 # realize:通过设置模型的参数class_weight="balanced"来实现 x_=scale(x,with_mean=True,with_std=True) x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.4,random_state=0) model=LogisticRegression(class_weight="balanced") clf=model.fit(x_train,y_train) print("LR模型测试成绩:{:.2f}".format(clf.score(x_test,y_test))) y_pred=clf.predict(x_test) target_names = ['class 0', 'class 1'] print(classification_report(y_test, y_pred, target_names=target_names)) y_pred1=clf.decision_function(x_test) fpr,tpr,threshold=roc_curve(y_test,y_pred1) rocauc=auc(fpr,tpr)#计算AUC print("ROC分数:{:.2f}".format(rocauc))
参考文章:
总结
今天很轻松,有空学习新知识!