将自定义函数放入Sklearn管道

在我的分类方案中,包括以下几个步骤:

  1. SMOTE(合成少数类过采样技术)
  2. 基于Fisher准则的特征选择
  3. 标准化(Z-score标准化)
  4. SVC(支持向量分类器)

在上述方案中,需要调整的主要参数是特征选择的百分比(步骤2)和SVC的超参数(步骤4),我希望通过网格搜索来进行调整。

当前的解决方案构建了一个“部分”管道,包括方案中的步骤3和4,代码如下clf = Pipeline([('normal',preprocessing.StandardScaler()),('svc',svm.SVC(class_weight='auto'))]),并将方案分成两部分:

  1. 通过第一次网格搜索调整保留特征的百分比

    skf = StratifiedKFold(y)for train_ind, test_ind in skf:    X_train, X_test, y_train, y_test = X[train_ind], X[test_ind], y[train_ind], y[test_ind]    # SMOTE合成训练数据(我们希望保持测试数据不变)    X_train, y_train = SMOTE(X_train, y_train)    for percentile in percentiles:        # Fisher返回由参数'percentile'指定的选定特征的索引        selected_ind = Fisher(X_train, y_train, percentile)         X_train_selected, X_test_selected = X_train[selected_ind,:], X_test[selected_ind, :]        model = clf.fit(X_train_selected, y_train)        y_predict = model.predict(X_test_selected)        f1 = f1_score(y_predict, y_test)

    F1分数将被存储,并通过所有折叠分区对所有百分比进行平均,返回具有最佳交叉验证分数的百分比。将’percentile for loop’作为内循环的目的是为了在所有折叠分区和所有百分比中保持相同的训练数据(包括合成数据),以确保公平竞争。

  2. 确定百分比后,通过第二次网格搜索调整超参数

    skf = StratifiedKFold(y)for train_ind, test_ind in skf:    X_train, X_test, y_train, y_test = X[train_ind], X[test_ind], y[train_ind], y[test_ind]    # SMOTE合成训练数据(我们希望保持测试数据不变)    X_train, y_train = SMOTE(X_train, y_train)    for parameters in parameter_comb:        # 根据调整后的百分比选择特征        selected_ind = Fisher(X_train, y_train, best_percentile)         X_train_selected, X_test_selected = X_train[selected_ind,:], X_test[selected_ind, :]        clf.set_params(svc__C=parameters['C'], svc__gamma=parameters['gamma'])        model = clf.fit(X_train_selected, y_train)        y_predict = model.predict(X_test_selected)        f1 = f1_score(y_predict, y_test)

这与前面的方法非常相似,只是我们调整的是SVC的超参数而不是特征选择的百分比。

我的问题是:

  1. 在当前的解决方案中,我只在clf中包含了步骤3和4,而步骤1和2则在上述描述的两个嵌套循环中“手动”完成。是否有办法将所有四个步骤都包含在一个管道中,并一次性完成整个过程?

  2. 如果保留第一个嵌套循环是可以接受的,那么是否有可能(以及如何)使用单一管道简化下一个嵌套循环

    clf_all = Pipeline([('smote', SMOTE()),                    ('fisher', Fisher(percentile=best_percentile))                    ('normal',preprocessing.StandardScaler()),                    ('svc',svm.SVC(class_weight='auto'))]) 

    并简单地使用GridSearchCV(clf_all, parameter_comb)进行调整?

    请注意,SMOTEFisher(排名标准)必须仅在每个折叠分区的训练数据上执行。

任何评论都将不胜感激。

SMOTEFisher的代码如下所示:

def Fscore(X, y, percentile=None):    X_pos, X_neg = X[y==1], X[y==0]    X_mean = X.mean(axis=0)    X_pos_mean, X_neg_mean = X_pos.mean(axis=0), X_neg.mean(axis=0)    deno = (1.0/(shape(X_pos)[0]-1))*X_pos.var(axis=0) +(1.0/(shape(X_neg[0]-1))*X_neg.var(axis=0)    num = (X_pos_mean - X_mean)**2 + (X_neg_mean - X_mean)**2    F = num/deno    sort_F = argsort(F)[::-1]    n_feature = (float(percentile)/100)*shape(X)[1]    ind_feature = sort_F[:ceil(n_feature)]    return(ind_feature)

SMOTE来自https://github.com/blacklab/nyan/blob/master/shared_modules/smote.py,它返回合成数据。我对其进行了修改,使其返回原始输入数据与合成数据堆叠在一起及其标签和合成数据的标签。

def smote(X, y):    n_pos = sum(y==1), sum(y==0)    n_syn = (n_neg-n_pos)/float(n_pos)     X_pos = X[y==1]    X_syn = SMOTE(X_pos, int(round(n_syn))*100, 5)    y_syn = np.ones(shape(X_syn)[0])    X, y = np.vstack([X, X_syn]), np.concatenate([y, y_syn])    return(X, y)

回答:

我不知道你的SMOTE()Fisher()函数来自哪里,但答案是肯定的,你绝对可以这样做。为了做到这一点,你需要为这些函数编写一个包装类。最简单的方法是继承sklearn的BaseEstimatorTransformerMixin类,参见这个例子:http://scikit-learn.org/stable/auto_examples/hetero_feature_union.html

如果你觉得这不明白,请至少发布一个函数的详细信息(它来自哪个库,或者如果你自己编写的代码),我们可以从那里开始。

编辑:

我道歉,我没有仔细查看你的函数,意识到它们不仅转换你的训练数据,还转换你的目标(即X和y)。Pipeline不支持对目标的转换,所以你必须像最初那样在之前进行。对于你的参考,这里是为你的Fisher过程编写自定义类的样子,如果函数本身不需要影响你的目标变量,它将有效。

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注