本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
众所周知,非平衡数据会极大的影响模型的评判效果,并且会过拟合。所以我们在处理数据的时候,首先需要做的是处理非平衡数据,使得各类型数据均衡。一、处理非平衡数据的各种方法
1-1、欠采样(下采样)
# 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、过采样
# define:对非平衡数据中样本较少的那一类进行采样,一般做法是将其复制几遍来达到正负样本平衡,这样容易过拟合,所以使用较少
1-3、人工合成
# 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、调整权重(效果较好而且快捷)
# 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))