Python学习笔记——进阶分类技术:管道函数、网格搜索、Optuna参数优化库、维度规约、单变量统计、自定义得分函数、过采样法

目录

分类技术在评价中的应用

读取数据

数据预处理

缺失值检验

one-hot编码

将评估结果列和其他属性分开

对预测属性进行one-hot编码

分割训练集与检验集

建立神经网络模型

训练神经网络模型

管道(pipeline)命令

交叉验证

搜索最优参数

网格搜索(Grid Search)

网格搜索的常用属性

检验分类准确率

随机网格搜索(Randomized Grid Search)

Optuna参数优化库

建立决策树模型

获得后剪枝ccp_alpha值列表

网格搜索最优ccp_alpha

可视化决策树

在完整训练集和检验集上检验

分类技术在直接营销中的应用

读取数据

数据可视化

维度规约(即数据降维)

维度规约原因

维度规约方法:特征选择、特征提取

用特征选择中的单变量统计来筛选属性

标称、序列型属性与分类结果的线性相关性检验

区间、比率型属性与分类结果的线性相关性检验

将分类结果转变为数值型

将序列属性转换为数值

数据预处理

one-hot编码

划分训练集与检验集

建立神经网络模型

建立管道模型

网格搜索最优参数

自定义得分函数

性能检验

过采样法处理类别样本数量不平衡

用过采样方法重新训练神经网络模型 

建立决策树模型

建立模型

获得后剪枝ccp_alpha列表

网格搜索最优参数

性能检验


 机器算法分类

分类技术在评价(助教教学)中的应用

  • 目标是预测一名助教的教学效果
  • 数据集记录了151名助教在5个学期中的教学效果的评估,评估结果分别是“差”、“一般”、“好”。数据属性的含义如下表所示:

读取数据

tadf = pd.read_csv('./data/classificationSupplement/tae.txt')
  • 原始数据不含有属性(列)名,用上述方式导致将第一行数据作为列名,这种读取方式不正确
tadf = pd.read_csv('./data/classificationSupplement/tae.txt',
names=['english','instructor','course','period','size','label'])

数据预处理

缺失值检验

tadf.isna().sum(axis=0)

one-hot编码

  • 将评估结果列和其他属性分开
    taX = tadf.iloc[:,:-1]
    taY = tadf['label']
  • 对预测属性进行one-hot编码
    taXOH = pd.get_dummies(taX,
    columns=['english','instructor','course','period'])

分割训练集与检验集

from sklearn.model_selection import train_test_split

taTrainX,taTestX,taTrainY,taTestY = 
train_test_split(taXOH,taY,test_size=0.25,random_state=10, stratify=taY)
  • stratify=taY:这个参数指定了在分割数据时保持类别比例不变(如taTrainY是一个二分类问题,其中标签0和1分别代表两个不同的类别,可使60%的样本属于类别0,40%的样本属于类别1)。这在处理分类问题时非常重要,因为它确保了训练集和测试集在类别分布上是一致的。这对于防止模型过拟合非常有效。
taTrainY.value_counts(normalize=True)      #训练集的类别比例
taTestY.value_counts(normalize=True)      #检验集的类别比例
taY.value_counts(normalize=True)          #原始数据的类别比例

   taTrainY.value_counts(normalize=True) 这行代码的作用是计算taTrainY中每个类别出现的次数,并且如果normalize=True,那么这个函数还会计算每个类别的相对频率,即将每个类别的计数除以总的样本数,得到的是一个概率分布。 

建立神经网络模型

from sklearn.neural_network import MLPClassifier
  • 输入层神经元数量:56
    • one-hot编码后的预测属性的数量
  • 输出层神经元数量:3
    • 评估类别的数量
np.sqrt(56*3)

使用 NumPy 库中的 sqrt 函数来计算一个数学表达式56*3的平方根 

  • 隐藏层神经元数量:13
taAnn = MLPClassifier(hidden_layer_sizes=(13,),solver='lbfgs',
activation='relu',learning_rate='constant',max_iter=3000,random_state=12)

训练神经网络模型

管道(pipeline)命令

  • 很多数据挖掘算法都会牵涉到多个步骤:标准化属性、建立模型、训练模型
  • 可以用pipeline把这些步骤串联起来,训练的时候数据会依次经过每个步骤

from sklearn.pipeline import Pipeline
Pipeline(steps)
  • steps:变换阶段构成的列表,每个变换阶段用一个元组表示:(变换阶段名称,变换函数)
    • 例如,[('scl',StandardScaler()),('ann',MLPClassifier())]

from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

pipeAnn = Pipeline([
    ('scl',StandardScaler()),
    ('ann', taAnn)
])

交叉验证

  • 交叉验证(cross-validation):每个记录用于训练的次数相同,并且恰好检验一次
  • k折交叉验证(k-folder cross-validation)

  • 交叉验证的步骤:
  1. k−1折数据作为训练集训练模型
  1. 剩下的1折数据作为验证集(validation set)测试分类模型的性能
  1. 以所有循环性能度量的均值作为交叉验证的测试结果
from sklearn.model_selection import cross_val_score
cross_val_score(estimator, X, y=None, scoring=None, cv=None)
  • estimator:构建的分类模型
  • X:预测属性
  • y:分类标签
  • scoring:模型分类性能的评估函数,str类型,用于指定评估模型性能的评分方法。如果未指定,则使用 'accuracy' 作为默认评分方法(对于分类问题)。
  • cv:训练集的划分方法,int类型,表示具体的折数,默认是5折
  • 返回值:每一次交叉验证的评估结果构成的列表

from sklearn.model_selection import cross_val_score
taRes = cross_val_score(pipeAnn,taTrainX,taTrainY,
scoring='accuracy',cv=10,n_jobs=-1)

print(f'初始建立的神经网络模型预测的平均准确率是{taRes.mean():.4f},
标准差是{taRes.std():.4f}')

搜索最优参数

  • 每个模型都有若干个参数(超参, hyperparameters)需要设置,但是事先我们并不知道如何设置参数最好,因此需要优化这些参数以取得更好的模型性能,即超参优化
  • 一种朴素的想法是尝试所有参数的组合,从中选出最优的参数组合
  • 网格(grid)搜索可以实现这样的目的

网格搜索(Grid Search)

        想象你正在制作一个披萨,你想要找到最佳的配料比例。你有很多种配料可以选择,比如西红柿、洋葱、胡椒、香肠等,每种配料都可以选择放或者不放,也可以选择放多少。这些选择就是“超参数”。

        网格搜索就像是你在尝试所有可能的配料组合。你会列出所有可能的配料组合,比如:

  • 只放西红柿
  • 放西红柿和洋葱
  • 放西红柿、洋葱和胡椒
  • 放西红柿、洋葱、胡椒和香肠
  • 等等

        然后,你会尝试每种组合制作披萨,并品尝它们,找出哪种组合最好吃。这就是“评估模型的性能”。

        在机器学习中,我们通常使用一种叫做“交叉验证”的方法来评估模型的性能。它会将数据分成几部分,每次使用其中一部分来训练模型,其他部分来测试模型。通过这种方式,我们可以得到一个更准确的性能评估。

        所以,网格搜索就是尝试所有可能的超参数组合,并使用交叉验证来评估它们的性能,最终找到最好的组合。

from sklearn.model_selection import GridSearchCV

GridSearchCV(estimator, param_grid, scoring=None,
n_jobs=None, cv=None, refit=True)
  • estimator:待估计的模型,可以是用pipeline构成的模型
  • param_grid:模型参数的可选范围,字典结构,字典的键(key)是参数名称,字典的值(value)是该参数的取值范围
    • 如果待估计模型是pipeline构成的,那么字典的键应该变换阶段名称__参数名称
  • n_jobs(可选):这是一个整数,用于指定并行执行的工作进程数。如果设置为 -1,则所有可用的CPU核心都会被使用。

  • refit:用于指示是否在使用最佳参数重新训练模型。如果为 True,则在找到最佳参数后,会使用所有数据重新训练模型,即用选出的最优参数在所有训练集上进行训练

from sklearn.model_selection import GridSearchCV

taAnnParams = {
    'ann__hidden_layer_sizes':range(13,56),
    'ann__activation':['relu','logistic','tanh'],
    'ann__learning_rate':['constant','invscaling'],
}

taAnnGs = GridSearchCV(pipeAnn,param_grid=taAnnParams,cv=10,n_jobs=-1)

%%time
taAnnGs.fit(taTrainX,taTrainY)

        在Python语言的 Jupyter Notebook 中,“%%time” 是一个魔术命令(magic command),它用于执行单元格并打印出执行时间。当你在Jupyter Notebook中使用 “%%time” 命令时,它会告诉你代码执行所需的时间,这有助于你了解代码的性能和效率。 这个命令只适用于Jupyter Notebook环境

网格搜索的常用属性
taAnnGs.best_params_ 
    #best_params_:最优参数组合

taAnnGs.best_score_ 
    #best_score_:最优的性能指标

taAnnOptimal = taAnnGs.best_estimator_
    #best_estimator_:训练的最优模型
taAnnOptimal
检验分类准确率
from sklearn import metrics

print(f'筛选的神经网络模型在完整训练集上的准确率是
{metrics.accuracy_score(taTrainY,taAnnOptimal.predict(taTrainX)):.4f}')

print(f'筛选的神经网络模型在检验集上的准确率是
{metrics.accuracy_score(taTestY,taAnnOptimal.predict(taTestX)):.4f}')

随机网格搜索(Randomized Grid Search)

        随机网格搜索是网格搜索的一种改进方法,它通过在搜索空间中随机选择超参数组合来减少搜索所需的时间。随机网格搜索的关键点如下:

  1. 定义超参数的候选集合。
  2. 随机选择超参数组合,而不是遍历整个网格。
  3. 对选定的每个组合训练模型并评估其性能。
  4. 记录每个组合的性能,并找到最佳性能的组合。

        随机网格搜索的优点是在保持较高探索能力的同时,显著减少了计算成本。通过随机选择组合,它可以避免在所有可能的组合上均匀地浪费计算资源,而是更有可能找到接近最优解的组合。然而,随机性可能会导致搜索过程缺乏透明性,因为不是所有组合都会被评估。

        在实际应用中,随机网格搜索通常比标准网格搜索更受欢迎,因为它在保持性能的同时减少了计算时间。

from sklearn.model_selection import RandomizedSearchCV

RandomizedSearchCV(estimator, param_distributions, n_iter=10,
scoring=None, n_jobs=None, refit=True, cv=None, random_state=None)
  • estimator: 这是你想要优化超参数的机器学习模型。例如,你可以是一个决策树、随机森林、支持向量机等。

  • param_distributions: 一个字典或列表,指定了你想要随机搜索的超参数及其可能的分布。例如:{'n_estimators': [3, 5, 10], 'max_depth': [None, 10, 20]}

  • n_iter: 整数,表示随机搜索的迭代次数。默认是10,即搜索10次。这个参数控制了随机搜索的广度。

from sklearn.model_selection import RandomizedSearchCV

taAnnParamsRandom = {
    'ann__hidden_layer_sizes':stats.randint(13,56),
    'ann__activation':['relu','logistic','tanh'],
    'ann__learning_rate':['constant','invscaling']
}


taAnnRs = RandomizedSearchCV(pipeAnn, taAnnParamsRandom, n_jobs=-1, cv=10, 
random_state=100)

%%time
taAnnRs.fit(taTrainX,taTrainY)

taAnnRs.best_estimator_

Optuna参数优化库

  • Optuna 是一个开源的参数优化库,用于优化机器学习模型的超参数,是一个高效的机器学习模型、深度学习模型的超参优化软件包package
  • 网址:https://optuna.org
  • 可以用于scikit-learnPyTorchTensorFlowKerasMXNet框架的超参优化
  • 安装:
  • pip install optuna
    pip install optuna-dashboard
    
def objective_fn(trial,trainX,trainY):

    hiddenNos = trial.suggest_int('hiddenNos',10,80,2)
    # 浮点数用suggest_float()

    lr = trial.suggest_categorical('lr',['constant','invscaling'])
    activation = trial.suggest_categorical('activation',['logistic','relu','tanh'])

    clf = MLPClassifier(hidden_layer_sizes=(hiddenNos,),activation=activation,
learning_rate=lr,random_state=100,max_iter=3000)

    res = model_selection.cross_val_score(clf,trainX.values,trainY.values,
scoring='accuracy',cv=5,n_jobs=-1)

    return res.mean()

        这段代码是一个超参数优化的试验函数,它使用 Optuna 来搜索最佳的 MLPClassifier 超参数配置,以提高分类器的准确率。       

  • objective_fn 是一个目标函数,它的目的是评估给定的超参数配置在多层感知机(MLP)分类器上的性能。这个函数接受三个参数:

    • trial:  是 Optuna 提供的一个对象,代表了一次试验,表示目标函数的单次执行过程
    • trainX: 训练数据的特征集合,通常是一个 NumPy 数组或类似的结构。
    • trainY: 训练数据的标签集合,通常是一个 NumPy 数组或类似的结构。
  • suggest_int 方法是用来建议一个整数类型的超参数。在这里,它建议一个隐藏层的大小,这个大小可能在 10 到 80 之间,以 2 为步长。
  • suggest_categorical 方法是用来建议一个类别型的超参数。
    • 在这里,它建议学习率可以是 'constant' 或 'invscaling' 两种选项中的一种。
    • 建议激活函数可以是 'logistic''relu' 或 'tanh' 三种选项中的一种。
  • clf = MLPClassifier(...):

    • 这个行创建了一个多层感知机分类器实例。它使用了上面建议的超参数配置。
  • res = model_selection.cross_val_score(clf,trainX.values,trainY.values,scoring='accuracy',cv=5,n_jobs=-1):

    • 这个行使用了交叉验证来评估分类器的性能。它计算了 5 折交叉验证的准确率。
  • return res.mean():

    • 最后,函数返回了交叉验证准确率的平均值。这个值将作为这次试验的目标函数值,Optuna 会尝试找到使这个值最大化的超参数配置。
%%time
study = optuna.create_study(direction='maximize',storage="sqlite:///db.sqlite3")

        整行代码的意思是:创建一个新的 Optuna 研究对象,用于最大化某个指标(在这种情况下是分类器的准确率),并将研究数据存储在一个名为 db.sqlite3 的 SQLite 数据库中。 

  1. create_study: 这是 Optuna 提供的一个函数,用于创建一个新的研究对象。研究对象用于记录超参数优化的整个过程,包括试验的配置、结果等。

  2. direction='maximize': 这是一个参数,用于指定优化方向。在分类问题中,我们通常希望最大化准确率,因此这里设置为 'maximize'。如果你是在回归问题中,可能会设置为 'minimize' 来最小化预测误差。

  3. storage="sqlite:///db.sqlite3": 这是一个参数,用于指定存储研究数据的方式。在这里,数据将被存储在一个 SQLite 数据库中,该数据库位于指定的路径下(db.sqlite3)。sqlite:/// 是一个 URL,它指定了数据库的类型和位置。db.sqlite3 是数据库文件的名称。

study.optimize(lambda trial: objective_fn(trial,taTrainX,taTrainY),n_trials=100)
print(study.best_trial)

        整行代码的意思是:对 study 对象进行优化,尝试 100 次不同的超参数配置,每次调用 objective_fn 函数来评估模型的性能,并寻找能够最大化性能指标的超参数配置。 

        在优化过程中,Optuna 会自动跟踪每个试验的超参数配置和性能指标,并在 study 对象中记录这些信息。最终,它可以提供一个包含最佳超参数配置的推荐。

  1. study: 这是之前通过 optuna.create_study() 创建的 Optuna 研究对象。这个对象记录了优化过程的详细信息,包括试验的配置、结果等。

  2. optimize: 这是 Optuna 提供的一个方法,用于启动超参数优化过程。这个方法接收两个主要参数:

    • lambda trial: objective_fn(trial,taTrainX,taTrainY): 这是一个 lambda 函数,它作为优化目标函数。这个函数接收一个 trial 对象作为输入,并调用 objective_fn 函数来计算这个试验的目标值。objective_fn 通常是用户定义的函数,它基于 trial 中的超参数配置来计算模型的性能指标(例如准确率或损失函数)。taTrainX 和 taTrainY 是训练数据的特征和标签,它们被传递给 objective_fn 以在每次试验中评估模型的性能。
    • n_trials=100: 这是一个参数,指定优化过程中要进行的试验次数。在这个例子中,将进行 100 次试验。

建立决策树模型

from sklearn import tree
taDt = tree.DecisionTreeClassifier(ccp_alpha=0.035,random_state=10)

获得后剪枝ccp_alpha值列表

taCcpPath = taDt.cost_complexity_pruning_path(taTrainX,taTrainY)
taAlphas = taCcpPath['ccp_alphas']

网格搜索最优ccp_alpha

taDtGs = GridSearchCV(estimator=taDt,param_grid=
{'ccp_alpha':taAlphas[:-1]},scoring='accuracy',cv=10,n_jobs=-1)

%%time
taDtGs.fit(taTrainX,taTrainY)

taDtGs.best_params_
taDtGs.best_score_
taDtOptimal = taDtGs.best_estimator_

可视化决策树

from graphviz import Source

taDot = tree.export_graphviz(taDtOptimal,feature_names=taTrainX.columns,
class_names=['差','一般','好'],filled=True)

taAnnOptimal.classes_

taGraphviz = Source(taDot)

在完整训练集和检验集上检验

print(f'筛选的决策树模型在完整训练集上的准确率是
{metrics.accuracy_score(taTrainY,taDtOptimal.predict(taTrainX)):.4f}')

print(f'筛选的决策树模型在检验集上的准确率是
{metrics.accuracy_score(taTestY,taDtOptimal.predict(taTestX)):.4f}')

分类技术在直接营销(客户储蓄)中的应用

  • 一家银行开展一项直接营销的活动,通过电话联系客户让他们在该银行储蓄
  • 目标是预测一个客户是否会来该银行储蓄

读取数据

#sep:每行元素之间的分隔符,默认是逗号
dmDf = pd.read_csv('./data/classificationSupplement/bank_direct_marketing.csv',sep=';')

数据可视化

dmDf['y'].value_counts().plot(kind='pie',figsize=(12,6),autopct='%.2f%%')
  1. dmDf['y']: 这表示 dmDf 这个 DataFrame 对象中的一列数据,列名为 'y'。通常,这列数据代表了某个分类变量,例如性别、颜色等。

  2. value_counts(): 这是 pandas 库中的一个方法,用于计算指定列中每个唯一值的出现次数。它会返回一个 Series,其中包含每个唯一值及其对应的计数。

  3. plot(kind='pie', figsize=(12,6), autopct='%.2f%%'): 这个方法用于将 value_counts() 方法返回的数据可视化为饼图。

    • kind='pie': 指定了要使用的图表类型,这里是饼图。
    • figsize=(12,6): 指定了图表的大小。这里创建了一个宽为 12 英寸、高为 6 英寸的图表。
    • autopct='%.2f%%': 指定了每个饼图切片百分比的格式。
      • %.2f:这是一个格式化占位符,用于格式化一个浮点数,并保留两位小数。
      • %:这是第二个格式化占位符,用于插入上面格式化后的浮点数。
      • %:这是第三个格式化占位符,用于插入百分比符号 %
dmDf.loc[dmDf['y']=='yes','age'].plot(kind='hist',bins=30,figsize=(12,6),
title='选择存储客户的年龄分布')
  1. dmDf.loc[dmDf['y']=='yes', 'age']: 这表示 dmDf 这个 DataFrame 对象中选择了一行,条件是 'y' 列中的值等于 'yes'。然后,它选择了这一行中的 'age' 列。这意味着它只关注那些在 'y' 列中值为 'yes' 的记录的 'age' 列数据。

  2. bins=30: 指定了直方图的柱状数为30个。bins 参数决定了直方图中的间隔数量,也就是将数据范围分成多少个小区间。
dmDf.loc[dmDf['y']=='yes','balance'].plot(kind='hist',bins=30,figsize=(12,6),
title='选择存储客户的账户余额分布')
dmDf.loc[dmDf['y']=='yes','job'].value_counts().plot(kind='bar',figsize=(12,6),
title='选择存储客户的工作状况')
dmDf.loc[dmDf['y']=='yes','marital'].value_counts().plot(kind='bar',figsize=(12,6),
title='选择存储客户的婚姻状况')
dmDf.loc[dmDf['y']=='yes','education'].value_counts().plot(kind='bar',figsize=(12,6),
title='选择存储客户的教育状况')
dmDf.loc[dmDf['y']=='yes','contact'].value_counts().plot(kind='bar',figsize=(12,6),
title='与选择存储客户的沟通方式')

维度规约(即数据降维)

        维度规约(Dimensionality Reduction)是数据挖掘和机器学习领域中的一种常见技术,其目的是通过减少数据的维数来简化模型的复杂性,同时尽可能保留数据中的有用信息。在实际应用中,高维数据往往含有大量信息,但并非所有维度都对解决特定问题有帮助。过多的维度可能会导致模型训练效率低下且容易过拟合(即模型对训练数据过于敏感,泛化能力差)。因此,通过维度规约可以去除冗余信息,提高数据处理的效率,并且有助于发现数据中的隐藏结构。

维度规约原因

  • 降低维度灾难(curse of dimensionality)
    • 维度灾难:随着属性数量的增加,没有足够多的数据点创建模型,很多数据挖掘算法的效果显著降低
  • 降低过度拟合
    • 属性过多,形成的分类规则复杂,过度适应训练集

维度规约方法:特征选择、特征提取

  • 特征选择的原因
    • 不相关特征:一些属性与分类结果无关,例如学生ID与学生成绩没有明显联系
    • 冗余特征:若干个属性之间信息重复,例如购买的产品价格与支付的消费税都包含了同样的信息
  • 特征选择的方法
    • 领域知识判断
    • 单变量统计检验:判断每个属性与分类变量之间的相关性
    • 嵌入到数据挖掘过程中:一些挖掘算法本身在计算过程中会筛选属性,例如决策树
  • 特征提取的原因
    • 共线性问题:一些属性之间高度相关,影响例如回归分析中的系数准确性
  • 特征提取的方法
    • 主成分分析(Principal component analysis, PCA):将原始属性通过线性变换为互相正交的少数主成分,即新属性

用特征选择中的单变量统计来筛选属性

标称、序列型属性与分类结果的线性相关性检验
from scipy import stats

crtJob = pd.crosstab(dmDf['job'],dmDf['y'],margins=True)

chiJob,pvJob,_,_ = stats.chi2_contingency(crtJob)
print(f'卡方值为{chiJob:.3f},p值为{pvJob:.3f}')

for each in ['job','marital','default','housing','loan','contact','poutcome']:
    crtb = pd.crosstab(dmDf[each],dmDf['y'],margins=True)
    chi,pv,_,_ = stats.chi2_contingency(crtb)
    print(f'{each}和存储与否的卡方值为{chi:.3f},p值为{pv:.3f}')
区间、比率型属性与分类结果的线性相关性检验
将分类结果转变为数值型
pandas.factorize(values, sort = False, na_sentinel = -1)
  • values:需要转换的分类属性
  • sort:是否对类别排序
  • na_sentinel:替换需要转换的分类属性中的缺失值,用于指定缺失值(NaN)在转换后的因子数据中的表示。默认值为 -1
  • 返回包含两个元素的元组,分别是转换为数值的属性、原属性中的所有独特类别
dmDf['y'].unique()
yVal,_ = pd.factorize(dmDf['y'],sort=True)
将序列属性转换为数值
dmDf['education'].unique()
dmDf['month'].unique()

dmDf['education'].replace({'primary':1,'secondary':2,'tertiary':3,'unknown':0},inplace=True)
dmDf['month'].replace({'jan':1,'feb':2,'mar':3,'apr':4,'may':5,'jun':6,'jul':7,'aug':8,'sep':9,'oct':10,'nov':11,'dec':12},inplace=True)


for each in ['age','education','balance','day','duration','campaign','month','pdays','previous']:
    r,pv = stats.pearsonr(dmDf[each],yVal)
    print(f'{each}和存储与否的相关系数是{r:.3f},显著性是{pv:.3f}')

dmX = dmDf.loc[:,['age','job','marital','education','housing','loan','contact','campaign','pdays','previous','poutcome']]
dmY = dmDf['y']

数据预处理

one-hot编码

dmXOH = pd.get_dummies(dmX,columns=['job','marital','housing','loan','contact','poutcome','education'])

划分训练集与检验集

dmTrX,dmTeX,dmTrY,dmTeY = 
train_test_split(dmXOH,dmY,test_size=0.25,stratify=dmY,random_state=10)

建立神经网络模型

  • 隐藏层神经元初始数量
    np.sqrt(34*1)

建立管道模型

dmPipe = Pipeline([
    ('scl',StandardScaler()),
    ('ann',MLPClassifier(max_iter=3000,random_state=12))
])

网格搜索最优参数

自定义得分函数
  • 处理pos_label默认值不是1的情况
    • pos_label 指的是我们定义的正类标签,即我们希望在预测中优先关注的那个类别。
metrics.make_scorer(score_func, **kwargs)
  • score_func:分类性能函数
  • **kwargsscore_func需要的参数
  • 例如,如果score_func=f1_score,那么**kwargs位置则可写pos_label='yes'
from sklearn.metrics import recall_score,make_scorer,f1_score

my_scorer = make_scorer(f1_score, pos_label='yes')

dmParams = {
    'ann__hidden_layer_sizes':range(6,62,20),
    'ann__learning_rate':['constant','invscaling'],
    'ann__activation':['relu','logistic','tanh'],
}

dmGs = GridSearchCV(estimator=dmPipe,param_grid=dmParams,scoring=my_scorer,cv=5,n_jobs=-1)

%%time
dmGs.fit(dmTrX,dmTrY)

dmGs.best_params_
dmGs.best_score_
dmAnnOpt = dmGs.best_estimator_
metrics.plot_precision_recall_curve(dmAnnOpt,dmTrX,dmTrY,pos_label="yes")

 

性能检验

print(f'建立的神经网络模型在检验集上的准确率是
{metrics.accuracy_score(dmTeY,dmAnnOpt.predict(dmTeX)):.4f}')

print(f'建立的神经网络模型在检验集上对存储的召回率是
{metrics.recall_score(dmTeY,dmAnnOpt.predict(dmTeX),pos_label="yes"):.4f}')

print(f'建立的神经网络模型在检验集上对未存储的召回率是
{metrics.recall_score(dmTeY,dmAnnOpt.predict(dmTeX),pos_label="no"):.4f}')

过采样法处理类别样本数量不平衡

        类别样本数量不平衡指的是在分类问题中,不同类别的样本数量不成比例。换句话说,就是数据集中的一个类别有大量的样本,而另一个类别只有少量的样本。这种情况在很多实际问题中很常见,比如欺诈检测中欺诈案例远少于正常交易,疾病诊断中某种疾病的病例远少于其他疾病。

        过采样(over-sampling):对训练集里面样本数量较少的类别进行多次抽样,合成新的样本

pip install -U imbalanced-learn
conda install -c conda-forge imbalanced-learn

from imblearn.over_sampling import SMOTE #导入过采样函数
import imblearn.pipeline as imbpipe #导入管道函数

用过采样方法重新训练神经网络模型 

from imblearn.over_sampling import SMOTE
import imblearn.pipeline as imbpipe

dmImbPipe = imbpipe.Pipeline([
    ('scl',StandardScaler()),
    ('sampling',SMOTE(random_state=0,n_jobs=-1)),
    ('ann',MLPClassifier(solver='lbfgs',max_iter=3000,random_state=12))
])

dmImbGs = GridSearchCV(estimator=dmImbPipe,param_grid=dmParams,
scoring=recall_scorer,cv=5,n_jobs=2)

%%time
dmImbGs.fit(dmTrX,dmTrY)

dmImbGs.best_params_

dmImbGs.best_score_

dmImbAnnOpt = dmImbGs.best_estimator_

print(f'建立的神经网络模型在检验集上的准确率是
{metrics.accuracy_score(dmTeY,dmImbAnnOpt.predict(dmTeX)):.4f}')

print(f'建立的神经网络模型在检验集上对订阅的召回率是
{metrics.recall_score(dmTeY,dmImbAnnOpt.predict(dmTeX),pos_label="yes"):.4f}')

print(f'建立的神经网络模型在检验集上对订阅的召回率是
{metrics.recall_score(dmTeY,dmAnnOpt.predict(dmTeX),pos_label="no"):.4f}')

metrics.plot_precision_recall_curve(dmImbAnnOpt,dmTeX,dmTeY,pos_label="yes")

建立决策树模型

建立模型

dmTree = tree.DecisionTreeClassifier(ccp_alpha=0.2,
class_weight='balanced',random_state=14)
  • class_weight:这个参数用于处理类别不平衡的数据集,给类别赋权重,调整样本类别不均衡
    • balanced根据数据中的分类变量中各个类比出现的频率自动计算类别权重,频率越低,权重越大。它告诉决策树分类器在训练时应该使用平衡类别权重。对于不平衡的数据集,这意味着少数类的权重会被调整得更高,以提高模型在少数类上的性能。

获得后剪枝ccp_alpha列表

dmCcpPath = dmTree.cost_complexity_pruning_path(dmTrX,dmTrY)
dmAlphas = dmCcpPath['ccp_alphas']

网格搜索最优参数

dmTreeGs = GridSearchCV(estimator=dmTree,param_grid={'ccp_alpha':dmAlphas[:-1]},scoring=recall_scorer,cv=5,n_jobs=-1)

%%time
dmTreeGs.fit(dmTrX,dmTrY)

dmTreeGs.best_params_

dmTreeGs.best_score_

dmTreeOpt = dmTreeGs.best_estimator_

性能检验

print(f'建立的决策树模型在检验集上的准确率是
{metrics.accuracy_score(dmTeY,dmTreeOpt.predict(dmTeX)):.4f}')

print(f'建立的决策树模型在检验集上对存储的召回率是
{metrics.recall_score(dmTeY,dmTreeOpt.predict(dmTeX),pos_label="yes"):.4f}')

print(f'建立的决策树模型在检验集上对不存储的召回率是
{metrics.recall_score(dmTeY,dmTreeOpt.predict(dmTeX),pos_label="no"):.4f}')
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值