许多二元分类任务中,每个类别的样本数量并不相等,例如类别分布是倾斜的或不平衡的。
尽管如此,准确性在两个类别中同等重要。
一个例子是语音识别中将欧洲语言的元音发音分为鼻音或口音,其中鼻音元音的样本比口音元音多得多。分类准确性对两个类别都很重要,尽管准确性作为一个度量标准不能直接使用。此外,在拟合机器学习算法时,可能需要数据采样技术来转换训练数据集,使其更加平衡。
在本教程中,您将学习如何为鼻音和口音音素的不平衡二元分类开发和评估模型。
完成本教程后,您将了解:
- 如何加载和探索数据集,并为数据准备和模型选择提供思路。
- 如何评估一套机器学习模型并通过数据过采样技术提高它们的性能。
- 如何拟合最终模型并使用它来预测特定案例的类别标签。
开始您的项目,阅读我的新书《Python 不平衡分类》,其中包含分步教程和所有示例的Python源代码文件。
让我们开始吧。
- 2021 年 1 月更新:更新了 API 文档链接。

音素不平衡分类数据集的预测模型
照片由 Ed Dunens 拍摄,部分权利保留。
教程概述
本教程分为五个部分;它们是:
- 音素数据集
- 探索数据集
- 模型测试和基线结果
- 评估模型
- 评估机器学习算法
- 评估数据过采样算法
- 在新数据上进行预测
音素数据集
在此项目中,我们将使用一个标准的不平衡机器学习数据集,称为“音素”数据集。
该数据集归功于 ESPRIT(欧洲信息技术研究战略计划)项目,题为“ROARS”(鲁棒分析语音识别系统),并在该项目的进展报告和技术报告中进行了描述。
ROARS 项目的目标是提高现有分析语音识别系统(即使用音节、音素和语音特征知识的系统)的鲁棒性,并将其作为具有连接词和对话能力的语音理解系统的一部分。该系统将在两种欧洲语言的特定应用中进行评估
该数据集的目标是区分鼻音元音和口音元音。
元音发音被录制成数字文件。然后从每个声音中自动提取音频特征。
选择了五个不同的属性来表征每个元音:它们是前五个谐波的幅度 AHi,由总能量 Ene(在所有频率上积分)归一化:AHi/Ene。每个谐波都有符号:当它对应于频谱的局部最大值时为正,否则为负。
— 音素数据集描述。
有两种类型的声音有两个类别;它们是
- 类别 0:鼻音元音(多数类别)。
- 类别 1:口音元音(少数类别)。
接下来,我们仔细看看数据。
想要开始学习不平衡分类吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
探索数据集
音素数据集是一个广泛使用的标准机器学习数据集,用于探索和演示许多专门为不平衡分类设计的技术。
一个例子是流行的 SMOTE 数据过采样技术。
首先,下载数据集并将其保存在当前工作目录中,文件名为“phoneme.csv”。
查看文件内容。
文件的前几行应如下所示
1 2 3 4 5 6 |
1.24,0.875,-0.205,-0.078,0.067,0 0.268,1.352,1.035,-0.332,0.217,0 1.567,0.867,1.3,1.041,0.559,0 0.279,0.99,2.555,-0.738,0.0,0 0.307,1.272,2.656,-0.946,-0.467,0 ... |
我们可以看到给定的输入变量是数值型的,类别标签对于鼻音和口音分别是 0 和 1。
可以使用read_csv() Pandas 函数将数据集加载为 DataFrame,指定位置和没有标题行。
1 2 3 4 5 |
... # 定义数据集位置 filename = 'phoneme.csv' # 将csv文件加载为数据框 dataframe = read_csv(filename, header=None) |
加载后,我们可以通过打印DataFrame的形状来总结行数和列数。
1 2 3 |
... # 总结数据集的形状 print(dataframe.shape) |
我们还可以使用 Counter 对象来汇总每个类别的样本数量。
1 2 3 4 5 6 7 |
... # 总结类别分布 target = dataframe.values[:,-1] counter = Counter(target) for k,v in counter.items(): per = v / len(target) * 100 print('Class=%s, Count=%d, Percentage=%.3f%%' % (k, v, per)) |
总而言之,下面列出了加载和汇总数据集的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 加载并汇总数据集 from pandas import read_csv from collections import Counter # 定义数据集位置 filename = 'phoneme.csv' # 将csv文件加载为数据框 dataframe = read_csv(filename, header=None) # 总结数据集的形状 print(dataframe.shape) # 总结类别分布 target = dataframe.values[:,-1] counter = Counter(target) for k,v in counter.items(): per = v / len(target) * 100 print('Class=%s, Count=%d, Percentage=%.3f%%' % (k, v, per)) |
运行示例首先加载数据集,并确认行数和列数,即 5,404 行,五个输入变量和一个目标变量。
然后汇总类别分布,确认存在中等程度的类别不平衡,多数类别(鼻音)约占 70%,少数类别(口音)约占 30%。
1 2 3 |
(5404, 6) Class=0.0, Count=3818, Percentage=70.651% Class=1.0, Count=1586, Percentage=29.349% |
我们还可以通过为每个变量创建直方图来查看五个数值输入变量的分布。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 |
# 创建数值输入变量的直方图 from pandas import read_csv from matplotlib import pyplot # 定义数据集位置 filename = 'phoneme.csv' # 将csv文件加载为数据框 df = read_csv(filename, header=None) # 所有变量的直方图 df.hist() pyplot.show() |
运行示例会创建图形,其中包含数据集中每个数值输入变量以及数值类别标签的直方图子图。
我们可以看到变量的尺度不同,尽管大多数看起来具有高斯或类高斯分布。
根据所选的建模算法,我们将期望缩放到相同范围的分布是有用的,并且可能标准化某些幂变换的使用。

音素数据集变量的直方图
我们还可以创建每个输入变量对的散点图,称为散点图矩阵。
这有助于了解变量之间是否存在关联或是否朝同一方向变化,例如是否相关。
我们还可以根据类别标签为每个散点图中的点着色。在这种情况下,多数类别(鼻音)将映射为蓝色点,少数类别(口音)将映射为红色点。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 创建数值输入变量的成对散点图 from pandas import read_csv from pandas import DataFrame from pandas.plotting import scatter_matrix from matplotlib import pyplot # 定义数据集位置 filename = 'phoneme.csv' # 将csv文件加载为数据框 df = read_csv(filename, header=None) # 定义类别值到颜色的映射 color_dict = {0:'blue', 1:'red'} # 根据类别值将每行映射到颜色 colors = [color_dict[x] for x in df.values[:, -1]] # 删除目标变量 inputs = DataFrame(df.values[:, :-1]) # 所有数值变量的成对散点图 scatter_matrix(inputs, diagonal='kde', color=colors) pyplot.show() |
运行示例会创建一个显示散点图矩阵的图形,该矩阵为五乘五,比较了五个数值输入变量之间的关系。矩阵的对角线显示了每个变量的密度分布。
每个配对出现两次,一次在对角线上方,一次在对角线下方,提供了两种查看相同变量交互的方式。
我们可以看到,许多变量的分布对于两个类别标签都不同,这表明可以在类别之间进行一些合理的区分。

音素数据集中数值输入变量按类别的散点图矩阵
现在我们已经审阅了数据集,接下来我们将开发一个测试工具来评估候选模型。
模型测试和基线结果
我们将使用重复分层 k 折交叉验证来评估候选模型。
k折交叉验证程序提供了模型性能的良好一般估计,该估计不太可能过于乐观地有偏倚,至少与单一的训练-测试拆分相比是如此。我们将使用 k=10,这意味着每个折叠将包含大约 5404/10 或约 540 个样本。
分层意味着每个折叠将包含相同的样本混合(按类别),即约 70% 的鼻音元音和 30% 的口音元音。重复表示将进行多次评估过程,以帮助避免偶然结果并更好地捕捉所选模型的方差。我们将使用三次重复。
这意味着一个模型将进行 10 * 3 = 30 次拟合和评估,并将报告这些运行的平均值和标准差。
这可以通过使用RepeatedStratifiedKFold scikit-learn 类来实现。
将预测类别标签,并且两个类别标签同等重要。因此,我们将选择一个度量标准来分别量化模型在两个类别上的性能。
您可能还记得,灵敏度是正面类别的准确性度量,特异性是负面类别的准确性度量。
- 灵敏度 = 真阳性 / (真阳性 + 假阴性)
- 特异性 = 真阴性 / (真阴性 + 假阳性)
G-mean 寻求这些分数之间的平衡,即几何平均数,其中一个类别的性能不佳会导致 G-mean 分数较低。
- G-Mean = sqrt(灵敏度 * 特异性)
我们可以使用 imbalanced-learn 库提供的 geometric_mean_score() 函数来计算一组模型预测的 G-mean。
我们可以定义一个函数来加载数据集,并将列拆分为输入和输出变量。下面的 load_dataset() 函数实现了这一点。
1 2 3 4 5 6 7 8 9 |
# 加载数据集 def load_dataset(full_path): # 将数据集加载为numpy数组 data = read_csv(full_path, header=None) # 检索numpy数组 data = data.values # 分割为输入和输出元素 X, y = data[:, :-1], data[:, -1] return X, y |
然后,我们可以定义一个函数来评估给定模型在数据集上的表现,并返回每个折叠和重复的 G-Mean 分数列表。下面的 evaluate_model() 函数实现了这一点,将数据集和模型作为参数,并返回分数列表。
1 2 3 4 5 6 7 8 9 |
# 评估模型 def evaluate_model(X, y, model): # 定义评估过程 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) # 定义模型评估指标 metric = make_scorer(geometric_mean_score) # 评估模型 scores = cross_val_score(model, X, y, scoring=metric, cv=cv, n_jobs=-1) return scores |
最后,我们可以使用这个测试工具评估数据集上的基线模型。
预测多数类别标签(0)或少数类别标签(1)的所有情况的模型的 G-mean 将为零。因此,一个好的默认策略是随机预测一个类别标签或另一个标签,概率为 50%,目标是 G-mean 约为 0.5。
这可以使用 scikit-learn 库中的 DummyClassifier 类并通过将“strategy”参数设置为“uniform”来实现。
1 2 3 |
... # 定义参考模型 model = DummyClassifier(strategy='uniform') |
在评估模型后,我们可以直接报告 G-Mean 分数的平均值和标准差。
1 2 3 4 5 |
... # 评估模型 scores = evaluate_model(X, y, model) # 总结性能 print('Mean G-Mean: %.3f (%.3f)' % (mean(scores), std(scores))) |
总而言之,加载数据集、评估基线模型和报告性能的完整示例列在下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# 测试框架和基线模型评估 from collections import Counter from numpy import mean from numpy import std from pandas import read_csv from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from imblearn.metrics import geometric_mean_score from sklearn.metrics import make_scorer from sklearn.dummy import DummyClassifier # 加载数据集 def load_dataset(full_path): # 将数据集加载为numpy数组 data = read_csv(full_path, header=None) # 检索numpy数组 data = data.values # 分割为输入和输出元素 X, y = data[:, :-1], data[:, -1] 返回 X, y # 评估模型 def evaluate_model(X, y, model): # 定义评估过程 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) # 定义模型评估指标 metric = make_scorer(geometric_mean_score) # 评估模型 scores = cross_val_score(model, X, y, scoring=metric, cv=cv, n_jobs=-1) 返回 分数 # 定义数据集位置 full_path = 'phoneme.csv' # 加载数据集 X, y = load_dataset(full_path) # 总结已加载的数据集 print(X.shape, y.shape, Counter(y)) # 定义参考模型 model = DummyClassifier(strategy='uniform') # 评估模型 scores = evaluate_model(X, y, model) # 总结性能 print('Mean G-Mean: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行示例首先加载并总结数据集。
我们可以看到我们加载了正确的行数,并且有五个音频派生输入变量。
接下来,报告 G-Mean 分数的平均值。
在这种情况下,我们可以看到基线算法实现了大约 0.509 的 G-Mean,接近理论最大值 0.5。该分数提供了模型技能的下限;任何平均 G-Mean 高于约 0.509(或实际上高于 0.5)的模型都具有技能,而得分低于此值的模型在此数据集上没有技能。
1 2 |
(5404, 5) (5404,) Counter({0.0: 3818, 1.0: 1586}) Mean G-Mean: 0.509 (0.020) |
现在我们有了测试工具和性能基线,我们可以开始评估该数据集上的一些模型。
评估模型
在本节中,我们将使用上一节中开发的测试工具,评估数据集上的一系列不同技术。
目标是演示如何系统地解决问题,并展示一些针对不平衡分类问题设计的技术的能力。
报告的性能良好,但尚未高度优化(例如,超参数未进行调整)。
你能做得更好吗? 如果您能使用相同的测试框架获得更好的 G-mean 性能,我很想了解。请在下面的评论中告诉我。
评估机器学习算法
让我们开始在数据集上评估一系列机器学习模型。
在数据集上对一系列不同的线性和非线性算法进行快速检查,可以很快地发现哪些效果好值得进一步关注,哪些效果不好。
我们将在音素数据集上评估以下机器学习模型
- 逻辑回归 (LR)
- 支持向量机 (SVM)
- 装袋决策树(BAG)
- 随机森林 (RF)
- 极端随机树(ET)
我们将使用大多数默认模型超参数,除了集成算法中的树的数量,我们将将其设置为合理的默认值1000。
我们将依次定义每个模型并将它们添加到一个列表中,以便我们可以按顺序评估它们。下面的 get_models() 函数定义了要评估的模型列表,以及用于稍后绘制结果的模型简称列表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 定义要测试的模型 定义 获取_模型(): models, names = list(), list() # LR models.append(LogisticRegression(solver='lbfgs')) names.append('LR') # SVM models.append(SVC(gamma='scale')) names.append('SVM') # Bagging models.append(BaggingClassifier(n_estimators=1000)) names.append('BAG') # RF models.append(RandomForestClassifier(n_estimators=1000)) names.append('RF') # ET models.append(ExtraTreesClassifier(n_estimators=1000)) names.append('ET') return models, names |
然后,我们可以逐一列出模型列表并评估每个模型,报告平均 G-Mean 并存储分数以供稍后绘制。
1 2 3 4 5 6 7 8 9 10 11 |
... # 定义模型 models, names = get_models() results = list() # 评估每个模型 for i in range(len(models)): # 评估模型并存储结果 scores = evaluate_model(X, y, models[i]) results.append(scores) # 总结并存储 print('>%s %.3f (%.3f)' % (names[i], mean(scores), std(scores))) |
在运行结束时,我们可以将每个样本的分数绘制成箱须图,并具有相同的比例,以便直接比较其分布。
1 2 3 4 |
... # 绘制结果图 pyplot.boxplot(results, labels=names, showmeans=True) pyplot.show() |
总而言之,用于在音素数据集上评估一套机器学习算法的完整示例列在下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# 在音素数据集上抽样检查机器学习算法 from numpy import mean from numpy import std from pandas import read_csv from matplotlib import pyplot from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from imblearn.metrics import geometric_mean_score from sklearn.metrics import make_scorer from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC from sklearn.ensemble import RandomForestClassifier from sklearn.ensemble import ExtraTreesClassifier from sklearn.ensemble import BaggingClassifier # 加载数据集 def load_dataset(full_path): # 将数据集加载为numpy数组 data = read_csv(full_path, header=None) # 检索numpy数组 data = data.values # 分割为输入和输出元素 X, y = data[:, :-1], data[:, -1] 返回 X, y # 评估模型 def evaluate_model(X, y, model): # 定义评估过程 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) # 定义模型评估指标 metric = make_scorer(geometric_mean_score) # 评估模型 scores = cross_val_score(model, X, y, scoring=metric, cv=cv, n_jobs=-1) 返回 分数 # 定义要测试的模型 定义 获取_模型(): models, names = list(), list() # LR models.append(LogisticRegression(solver='lbfgs')) names.append('LR') # SVM models.append(SVC(gamma='scale')) names.append('SVM') # Bagging models.append(BaggingClassifier(n_estimators=1000)) names.append('BAG') # RF models.append(RandomForestClassifier(n_estimators=1000)) names.append('RF') # ET models.append(ExtraTreesClassifier(n_estimators=1000)) names.append('ET') return models, names # 定义数据集位置 full_path = 'phoneme.csv' # 加载数据集 X, y = load_dataset(full_path) # 定义模型 models, names = get_models() results = list() # 评估每个模型 for i in range(len(models)): # 评估模型并存储结果 scores = evaluate_model(X, y, models[i]) results.append(scores) # 总结并存储 print('>%s %.3f (%.3f)' % (names[i], mean(scores), std(scores))) # 绘制结果图 pyplot.boxplot(results, labels=names, showmeans=True) pyplot.show() |
运行示例会依次评估每个算法,并报告平均和标准差 G-Mean。
注意:您的结果可能因算法或评估程序的随机性或数值精度的差异而有所不同。请考虑运行示例几次并比较平均结果。
在这种情况下,我们可以看到所有测试的算法都具有技能,G-Mean 均高于默认值 0.5。结果表明,决策树集成算法在此数据集上表现更好,其中 Extra Trees (ET) 表现最佳,G-Mean 约为 0.896。
1 2 3 4 5 |
>LR 0.637 (0.023) >SVM 0.801 (0.022) >BAG 0.888 (0.017) >RF 0.892 (0.018) >ET 0.896 (0.017) |
创建的图形显示了每个算法样本结果的箱线图。箱子显示了数据中间的 50%,箱子中间的橙色线显示了样本的中位数,箱子中的绿色三角形显示了样本的平均值。
我们可以看到,所有三个决策树集成算法(BAG、RF 和 ET)都具有紧密的分布,并且均值和中位数非常接近,这可能表明分数分布是非偏斜的和高斯分布的,例如稳定。

不平衡音素数据集上的机器学习模型的箱线图
现在我们有了一套良好的初始结果,让我们看看是否可以使用数据过采样方法来改进它们。
评估数据过采样算法
数据采样提供了一种在拟合模型之前更好地准备不平衡训练数据集的方法。
最简单的过采样技术是复制少数类中的样本,称为随机过采样。也许最流行的过采样方法是 SMOTE 过采样技术,用于为少数类创建新的合成样本。
我们将测试五种不同的过采样方法;具体来说
- 随机过采样 (ROS)
- SMOTE (SMOTE)
- BorderLine SMOTE (BLSMOTE)
- SVM SMOTE (SVMSMOTE)
- ADASYN (ADASYN)
每种技术都将与上一节中表现最佳的算法(特别是 Extra Trees)进行测试。
我们将使用每种过采样算法的默认超参数,它将对少数类进行过采样,使其在训练数据集中拥有与多数类相同的样本数。
预期是每种过采样技术都将比没有过采样的算法带来性能提升,其中随机过采样提供的提升最小,而 SMOTE 或其变体之一可能提供最佳提升。
我们可以更新 get_models() 函数以返回要评估的过采样算法列表;例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 定义要测试的过采样模型 定义 获取_模型(): models, names = list(), list() # RandomOverSampler models.append(RandomOverSampler()) names.append('ROS') # SMOTE models.append(SMOTE()) names.append('SMOTE') # BorderlineSMOTE models.append(BorderlineSMOTE()) names.append('BLSMOTE') # SVMSMOTE models.append(SVMSMOTE()) names.append('SVMSMOTE') # ADASYN models.append(ADASYN()) names.append('ADASYN') return models, names |
然后,我们可以逐一列举每个模型,并创建一个 Pipeline(来自 imbalanced-learn 库),该 Pipeline 能够对训练数据集进行过采样。这将确保交叉验证模型评估中的训练数据集被正确采样,而不会发生可能导致模型性能评估过于乐观的数据泄露。
首先,我们将对输入变量进行归一化,因为大多数过采样技术都将使用最近邻算法,并且在使用此技术时,所有变量具有相同的尺度非常重要。接下来将应用一个过采样算法,最后使用将在过采样训练数据集上拟合的 Extra Trees 算法。
1 2 3 4 5 6 7 8 9 |
... # 定义模型 model = ExtraTreesClassifier(n_estimators=1000) # 定义管道的步骤 steps = [('s', MinMaxScaler()), ('o', models[i]), ('m', model)] # 定义管道 pipeline = Pipeline(steps=steps) # 评估模型并存储结果 scores = evaluate_model(X, y, pipeline) |
总而言之,下面列出了在音素数据集上使用 Extra Trees 评估过采样算法的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# 音素不平衡数据集上的数据过采样算法 from numpy import mean from numpy import std from pandas import read_csv from matplotlib import pyplot 从 sklearn.预处理 导入 MinMaxScaler from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from imblearn.metrics import geometric_mean_score from sklearn.metrics import make_scorer from sklearn.ensemble import ExtraTreesClassifier from imblearn.over_sampling import RandomOverSampler from imblearn.over_sampling import SMOTE from imblearn.over_sampling import BorderlineSMOTE from imblearn.over_sampling import SVMSMOTE from imblearn.over_sampling import ADASYN from imblearn.pipeline import Pipeline # 加载数据集 def load_dataset(full_path): # 将数据集加载为numpy数组 data = read_csv(full_path, header=None) # 检索numpy数组 data = data.values # 分割为输入和输出元素 X, y = data[:, :-1], data[:, -1] 返回 X, y # 评估模型 def evaluate_model(X, y, model): # 定义评估过程 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) # 定义模型评估指标 metric = make_scorer(geometric_mean_score) # 评估模型 scores = cross_val_score(model, X, y, scoring=metric, cv=cv, n_jobs=-1) 返回 分数 # 定义要测试的过采样模型 定义 获取_模型(): models, names = list(), list() # RandomOverSampler models.append(RandomOverSampler()) names.append('ROS') # SMOTE models.append(SMOTE()) names.append('SMOTE') # BorderlineSMOTE models.append(BorderlineSMOTE()) names.append('BLSMOTE') # SVMSMOTE models.append(SVMSMOTE()) names.append('SVMSMOTE') # ADASYN models.append(ADASYN()) names.append('ADASYN') return models, names # 定义数据集位置 full_path = 'phoneme.csv' # 加载数据集 X, y = load_dataset(full_path) # 定义模型 models, names = get_models() results = list() # 评估每个模型 for i in range(len(models)): # 定义模型 model = ExtraTreesClassifier(n_estimators=1000) # 定义管道的步骤 steps = [('s', MinMaxScaler()), ('o', models[i]), ('m', model)] # 定义管道 pipeline = Pipeline(steps=steps) # 评估模型并存储结果 scores = evaluate_model(X, y, pipeline) results.append(scores) # 总结并存储 print('>%s %.3f (%.3f)' % (names[i], mean(scores), std(scores))) # 绘制结果图 pyplot.boxplot(results, labels=names, showmeans=True) pyplot.show() |
运行该示例将在数据集上使用 Extra Trees 模型评估每种过采样方法。
注意:您的结果可能因算法或评估程序的随机性或数值精度的差异而有所不同。请考虑运行示例几次并比较平均结果。
在这种情况下,正如我们所预期的,除了随机过采样技术之外,每种过采样技术都提高了 ET 算法在没有任何过采样(0.896)的情况下的性能。
结果表明,SMOTE 和 ADASYN 的修改版本比默认 SMOTE 表现更好,并且在这种情况下,ADASYN 取得了最佳的 G-Mean 分数 0.910。
1 2 3 4 5 |
>ROS 0.894 (0.018) >SMOTE 0.906 (0.015) >BLSMOTE 0.909 (0.013) >SVMSMOTE 0.909 (0.014) >ADASYN 0.910 (0.013) |
结果的分布可以通过箱线图进行比较。
我们可以看到所有分布大致具有相同的紧密分布,并且结果的平均值差异可用于选择模型。

用于不平衡音素数据集上的数据过采样的 Extra Trees 模型的箱线图
接下来,让我们看看如何使用最终模型对新数据进行预测。
对新数据进行预测
在本节中,我们将拟合最终模型并使用它来对单个数据行进行预测
我们将使用 Extra Trees 模型的 ADASYN 过采样版本作为最终模型,并在拟合模型和进行预测之前对数据进行归一化缩放。使用管道将确保转换始终正确执行。
首先,我们可以将模型定义为管道。
1 2 3 4 5 6 7 |
... # 定义模型 model = ExtraTreesClassifier(n_estimators=1000) # 定义管道的步骤 steps = [('s', MinMaxScaler()), ('o', ADASYN()), ('m', model)] # 定义管道 pipeline = Pipeline(steps=steps) |
定义好后,我们就可以在整个训练数据集上对其进行拟合。
1 2 3 |
... # 拟合模型 pipeline.fit(X, y) |
拟合后,我们可以通过调用 _predict()_ 函数来使用它为新数据进行预测。这将返回“鼻音”的类别标签 0,或“口音”的类别标签 1。
例如
1 2 3 4 5 |
... # 定义一行数据 row = [...] # 进行预测 yhat = pipeline.predict([row]) |
为了演示这一点,我们可以使用拟合模型对一些我们知道是鼻音还是口音的已知情况进行预测。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# 拟合模型并对音素数据集进行预测 from pandas import read_csv 从 sklearn.预处理 导入 MinMaxScaler from imblearn.over_sampling import ADASYN from sklearn.ensemble import ExtraTreesClassifier from imblearn.pipeline import Pipeline # 加载数据集 def load_dataset(full_path): # 将数据集加载为numpy数组 data = read_csv(full_path, header=None) # 检索numpy数组 data = data.values # 分割为输入和输出元素 X, y = data[:, :-1], data[:, -1] 返回 X, y # 定义数据集位置 full_path = 'phoneme.csv' # 加载数据集 X, y = load_dataset(full_path) # 定义模型 model = ExtraTreesClassifier(n_estimators=1000) # 定义管道的步骤 steps = [('s', MinMaxScaler()), ('o', ADASYN()), ('m', model)] # 定义管道 pipeline = Pipeline(steps=steps) # 拟合模型 pipeline.fit(X, y) # 对一些鼻音情况进行评估(已知类别 0) print('Nasal:') data = [[1.24,0.875,-0.205,-0.078,0.067], [0.268,1.352,1.035,-0.332,0.217], [1.567,0.867,1.3,1.041,0.559]] for row in data: # 进行预测 yhat = pipeline.predict([row]) # 获取标签 label = yhat[0] # 总结 print('>Predicted=%d (expected 0)' % (label)) # 对一些口音情况进行评估(已知类别 1) print('Oral:') data = [[0.125,0.548,0.795,0.836,0.0], [0.318,0.811,0.818,0.821,0.86], [0.151,0.642,1.454,1.281,-0.716]] for row in data: # 进行预测 yhat = pipeline.predict([row]) # 获取标签 label = yhat[0] # 总结 print('>Predicted=%d (expected 1)' % (label)) |
首先运行示例,在整个训练数据集上拟合模型。
然后使用拟合模型对从数据文件中选择的一些鼻音病例进行标签预测。我们可以看到所有病例都得到了正确预测。
然后将一些口音病例作为输入到模型中并预测标签。正如我们所期望的,所有病例都得到了正确的标签预测。
1 2 3 4 5 6 7 8 |
鼻音 >预测值=0(期望值 0) >预测值=0(期望值 0) >预测值=0(期望值 0) 口音 >预测值=1(期望值 1) >预测值=1(期望值 1) >预测值=1(期望值 1) |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
论文
API
- sklearn.model_selection.RepeatedStratifiedKFold API.
- sklearn.dummy.DummyClassifier API.
- imblearn.metrics.geometric_mean_score API.
数据集 (Dataset)
总结
在本教程中,您学习了如何开发和评估用于鼻音和口音不平衡二分类的模型的。
具体来说,你学到了:
- 如何加载和探索数据集,并为数据准备和模型选择提供思路。
- 如何评估一套机器学习模型并通过数据过采样技术提高它们的性能。
- 如何拟合最终模型并使用它来预测特定案例的类别标签。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
如何减小标准差?
>ROS 0.431 (0.318)
>SMOTE 0.535 (0.318)
>BLSMOTE 0.539 (0.325)
>SVMSMOTE 0.522 (0.307)
>ADASYN 0.528 (0.314)
拟合多个最终模型并组合它们的预测。这将减少预测中的方差。
感谢这篇文章。它帮助了我们这里的一些学生。
不客气,我很高兴听到这个消息。
嗨,Jason,
这是否也适用于多标签分类?
我认为没有。
尊敬的Jason博士,
对于那些忘记下载 imblearn 包的人,正如在以下行中所示:
首先关闭所有 Python IDE(例如 IDLE),然后
只需在命令行中 pip 安装该包,例如 MS DOS
重新启动您的 Python IDE 并检查 imblearn 的版本
谢谢你,
悉尼的Anthony
感谢分享!
尊敬的Jason博士,
这是关于“评估数据过采样算法”部分中的代码
特别是第 70-75 行
我的问题是关于管道的步骤
我明白 MinMaxScaler 将 X 中的每个特征缩放到 0 到 1 之间。
我明白在循环 models[i] 中指的是将 X, y 拟合到 RandomOverSampler、SMOTE、BorderlineSMOTE。
我明白 ExtraTreesClassifer 基于随机分割进行分割。参考文档:https://scikit-learn.cn/stable/modules/generated/sklearn.ensemble.ExtraTreesClassifier.html
我的问题
一旦 RandomOverSampler、SMOTE、BorderlineSMOTE、SVMSMOTE 或 ADASYN 中的任何一个被 fit_resample(X,y),那么 fit_resampled(X,y) 就通过 fit(X,y) 方法拟合到 ExtraTreesClassifier 中,然后 cross_val_score 是“...为每个交叉验证折叠拟合模型,进行预测并对它们进行评分…”,引用 Jason Brownlee 2020 年 3 月 8 日上午 6:09 的话:https://machinelearning.org.cn/metrics-evaluate-machine-learning-algorithms-python/。
谢谢你,
悉尼的Anthony
抱歉,确切的问题是什么?
尊敬的Jason博士,
谢谢你的回复。
我的问题是管道里发生了什么?
(1) 第一步,使用 MinMaxScaler 将 X 的特征转换为 0 到 1 之间。
(2) 下一步,model[i],即 RandomOverSampler、SMOTE、BorderlineSMOTE、SVMSMOTE 或 ADASYN。每个 model[i] 都具有 fit_resampled(X,y) 方法,参考:https://machinelearning.org.cn/random-oversampling-and-undersampling-for-imbalanced-classification/
(3) 下一步是,使用 ExtraTreesClassifier 的 fit(X,y) 方法将特定的已拟合的 model[i] 的 fit(X,y) 方法拟合到 ExtraTreesClassifier 中,参考:https://scikit-learn.cn/stable/modules/generated/sklearn.ensemble.ExtraTreesClassifier.html
(4) 然后最后一步是使用 RepeatedStratifiedKFold 和评分指标来评估特定的 model[i] 的 cross_val_score。
谢谢你,
悉尼的Anthony
管道首先缩放数据(列),然后重采样数据(行),然后拟合模型——所有这些都在交叉验证折叠内正确完成。
尊敬的Jason博士,
感谢您的回复。
我编写了额外的代码来查找预测是否符合预期,并发现即使是得分最低的 ROS 也正确预测了三个预期为 0 的预测和三个预期为 1 的预测。也就是说,对“鼻音”和“口音”各有三个正确预测。回想一下,每个“鼻音”和“口音”都有三行 X 的数据。
谢谢,
悉尼的Anthony
很棒的实验!
感谢分享宝贵的信息。我无法下载音素数据集。您能帮我下载吗?我
您可以在此处下载所有数据集
https://github.com/jbrownlee/Datasets
谢谢先生。
不客气。
我有一个包含多个类别的示例,并且我无法为每个类别进行概率预测,是否有任何提示或教程?
也许可以使用一个本地预测多类问题的概率的模型,例如多层感知机或 LDA。
请解释一下为什么您使用 G-means(音素分类)而不是准确率,因为数据集不严重。准确率不能使用吗?谢谢
嗨 Rotimi...您可能会发现以下资源很有趣
https://www.internationalphoneticassociation.org/icphs-proceedings/ICPhS1999/papers/p14_0707.pdf