为什么standardscaler在不同数量的特征下有不同的效果

Why does the standardscaler have different effects under different number of features

我试验了来自 scikit-learn 的乳腺癌数据。

  1. 使用所有功能而不使用标准缩放器:

    cancer = datasets.load_breast_cancer()
    x = cancer.data
    y = cancer.target
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
    
    pla = Perceptron().fit(x_train, y_train)
    y_pred = pla.predict(x_test)
    print(accuracy_score(y_test, y_pred))
    
    • 结果 1:0.9473684210526315
  2. 使用所有功能并使用标准缩放器:

    cancer = datasets.load_breast_cancer()
    x = cancer.data
    y = cancer.target
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
    
    sc=StandardScaler()
    sc.fit(x_train)
    x_train=sc.transform(x_train)
    x_test=sc.transform(x_test)
    
    pla = Perceptron().fit(x_train, y_train)
    y_pred = pla.predict(x_test)
    print(accuracy_score(y_test, y_pred))
    
    • 结果 2:0.9736842105263158
  3. 只使用两个功能而不使用标准缩放器:

    cancer = datasets.load_breast_cancer()
    x = cancer.data[:,[27,22]]
    y = cancer.target
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
    
    pla = Perceptron().fit(x_train, y_train)
    y_pred = pla.predict(x_test)
    print(accuracy_score(y_test, y_pred))
    
    • 结果 3:0.37719298245614036
  4. 仅使用两个特征并使用标准缩放器:

    cancer = datasets.load_breast_cancer()
    x = cancer.data[:,[27,22]]
    y = cancer.target
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
    
    sc=StandardScaler()
    sc.fit(x_train)
    x_train=sc.transform(x_train)
    x_test=sc.transform(x_test)
    
    pla = Perceptron().fit(x_train, y_train)
    y_pred = pla.predict(x_test)
    print(accuracy_score(y_test, y_pred))
    
    • 结果 4:0.9824561403508771

如 result1、result2、result3、result4 所示,使用 Standardscaler 时,使用较少的特征进行训练时,准确率有了很大提高。

所以我想知道为什么standardscaler在不同数量的特征下会有不同的效果?

PS. Here is the two featrues I choose:

TL;DR

不要做特征 selection 只要你不完全理解你为什么这样做以及它可以帮助你的算法更好地学习和泛化。对于初学者,请阅读 Max Kuhn

http://www.feat.engineering/selection.html

全部阅读。

我怀疑您尝试 select 最佳特征子集,但遇到了 [任意] 子集比整个数据集表现更好的情况。 StandardScaling 在这里是没有问题的,因为它被认为是您算法的标准预处理程序。所以你真正的问题应该是“为什么特征子集比完整数据集表现更好?”

为什么你的 selection 算法是任意的? 2 个原因。

首先。没有人证明最线性相关的特征会改进您的 [或任何其他,如果您愿意的话] 算法。第二。最佳特征子集与最佳相关特征所需的不同。

让我们用代码看看这个。

提供最佳准确度的特征子集(注意a

来个蛮力吧。

acc_bench = 0.9736842105263158 # accuracy on all features
res = {}
f = x_train.shape[1]
pcpt = Perceptron(n_jobs=-1)
from itertools import combinations
for i in tqdm(range(2,10)):
    features_list = combinations(range(f),i)
    for features in features_list:
        pcpt.fit(x_train[:,features],y_train)
        preds = pcpt.predict(x_test[:, features])
        acc = accuracy_score(y_test, preds)
        if acc > acc_bench:
            acc_bench = acc
            res["accuracy"] = acc_bench
            res["features"] = features
print(res)
{'accuracy': 1.0, 'features': (0, 15, 22)}

所以你看,特征 [0,15,22] 在验证数据集上提供了完美的准确性。

最佳特征与目标相关性有什么关系吗?

让我们找到一个按线性相关度排序的列表。

featrues = pd.DataFrame(cancer.data, columns=cancer.feature_names) 
target = pd.DataFrame(cancer.target, columns=['target']) 
cancer_data = pd.concat([featrues,target], axis=1) 
features_list = np.argsort(np.abs(cancer_data.corr()['target'])[:-1].values)[::-1]
feature_list
array([27, 22,  7, 20,  2, 23,  0,  3,  6, 26,  5, 25, 10, 12, 13, 21, 24,
       28,  1, 17,  4,  8, 29, 15, 16, 19, 14,  9, 11, 18])

你看,通过蛮力找到的最佳特征子集与相关性无关。

线性相关可以解释感知器的准确性吗?

让我们尝试绘制上面列表中的特征数量(从 2 个最相关的特征开始)与结果准确度的关系。

res = dict()
for i in tqdm(range(2,10)):
    features=features_list[:i]
    pcpt.fit(x_train[:,features],y_train)
    preds = pcpt.predict(x_test[:, features])
    acc = accuracy_score(y_test, preds)
    res[i]=[acc]
pd.DataFrame(res).T.plot.bar()
plt.ylim([.9,1])

再次强调,线性相关特征与感知器精度无关。

结论。

在任何算法之前不要select特征,除非你完全确定你在做什么以及这样做会产生什么影响。不要混淆不同的 selection 和学习算法,因为不同的算法对什么重要什么不重要有不同的看法。对一种算法不重要的特征可能对另一种算法很重要。对于线性与非线性算法尤其如此。

如果您想提高算法的准确性,请改用数据清理或特征工程。