我正在处理一个数据集,格式如下:
Feature1 Feature2 Feature3 Class 0.1 0.2 0.3 Apple 0.3 0.1 0.4 Orange 0.12 0.22 0.13 Banana 0.112 0.231 0.3 Watermelon
假设我的数据集总共有40,000个观测值,其中22,000个属于西瓜类。如何处理如上所示的Python中的多类不平衡问题?
回答:
在这种情况下,通常的方法是减少多数类样本或增加少数类样本。不过,这些方法不一定是最佳选择。这将始终取决于具体问题和所使用的模型。例如,应用样本权重也是一种常见的方法。
由于评论中提到了过采样,这里是我们如何使用SMOTE
来过采样少数类的方法。请注意,SMOTE
需要数值特征,因此您需要对分类数据进行独热编码(标签可以是分类的,但这仅适用于分类特征,如果您没有这样的特征,则不需要这一步)。我们可以使用Pipeline
来方便操作。还要注意,当使用SMOTE
时,您应该使用imblearn
的Pipeline
,因为它包含了当输入数据形状发生变化时所需的额外方法,这些方法在scikit-learn的对应版本中并未考虑。
让我们从示例数据框创建一个不平衡的分类问题:
df = df.append(pd.concat([df.iloc[[0]]]*200))df = df.append(pd.concat([df.iloc[[1]]]*2000))df = df.append(pd.concat([df.iloc[[2]]]*100))df = df.append(pd.concat([df.iloc[[3]]]*300))df.Class.value_counts()Orange 2001Watermelon 301Apple 201Banana 101Name: Class, dtype: int64
为了获得无偏估计,我们希望平衡这些类。让我们构建一个包含OneHotEncoder
和SMOTE
过采样的管道:
from imblearn.over_sampling import SMOTEfrom sklearn.preprocessing import OneHotEncoderfrom imblearn.pipeline import PipelineX = df.drop(['Class'],1)y = df.Classsteps = [('onehot', OneHotEncoder()), ('smt', SMOTE())]pipeline = Pipeline(steps=steps)X, y = pipeline.fit_resample(X, y)
现在,通过对目标进行value_counts
操作,我们会得到:
pd.Series(y.to_numpy()).value_counts()Banana 2001Orange 2001Watermelon 2001Apple 2001dtype: int64
另外,我们可能并不希望将所有其他类别过采样到与多数类相同的数量。在这种情况下,SMOTE
允许提供一个字典,指定每个目标类的样本数量:
smote_samples = {'Apple':1000, 'Orange':2001, 'Banana':1000, 'Watermelon':1000}steps = [('onehot', OneHotEncoder()), ('smt', SMOTE(smote_samples))]pipeline = Pipeline(steps=steps)
在这种情况下,结果将是:
X, y = pipeline.fit_resample(X, y)pd.Series(y.to_numpy()).value_counts()Orange 2001Banana 1000Apple 1000Watermelon 1000dtype: int64