如何正确使用 PCA 和 Logistic 回归?

How do I correctly use PCA followed by Logistic Regression?

在程序中,我每 2.5 秒扫描在 40 x 64 x 64 图像的时间序列中采集的大量大脑样本。因此,每个图像中 'voxels'(3D 像素)的数量约为 168,000 ish (40 * 64 * 64),每个图像样本都是 'feature'。

因为n高得离谱,我想到了使用主成分分析(PCA)来进行降维。我知道 PCA 实际上并没有减少特征的数量。如果我错了请纠正我,但 PCA 会从原始特征中产生一组新特征。但是,新功能必须满足某些条件。

我定义了一个获取组件数量的方法:

def get_optimal_number_of_components():
    cov = np.dot(X,X.transpose())/float(X.shape[0])
    U,s,v = svd(cov)

    S_nn = sum(s)

    for num_components in range(0,s.shape[0]):
        temp_s = s[0:num_components]
        S_ii = sum(temp_s)
        if (1 - S_ii/float(S_nn)) <= 0.01:
            return num_components

    return s.shape[0]

此函数将 return 组件的数量,以便保留原始数据的 99% 的方差。现在,我们可以创建这些组件了:

#Scaling the values
X = scale(X)

n_comp = get_optimal_number_of_components()
print 'optimal number of components = ', n_comp

pca = PCA(n_components = n_comp)
X_new = pca.fit_transform(X)

我在这个数据集上的 运行 程序中得到了最佳组件数 = 1001。这个数字与我在执行时获得的情节一致:

#Cumulative Variance explains
var1 = np.cumsum(np.round(pca.explained_variance_ratio_, decimals=4)*100)

plt.plot(var1)
plt.title('Principle Component Analysis for Feature Selection')
plt.ylabel('Percentage of variance')
plt.xlabel('Number of voxels considered')

plt.show()

此 PCA 阶段完成后,我使用新创建的 'X_new' 代替下一阶段的 X:逻辑回归

#After PCA
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X_new, y, test_size=0.10, random_state=42)

classifier = LogisticRegression()
classifier.fit(X_train,y_train)

当我测试准确性时,我得到大约 77.57%

但这比我刚刚分析中间体素样本(比如大脑图像中间的 9K 个样本)时要少。我想知道我是否正确地处理了 PCA 和逻辑回归。

我什至用 sklearn.pipeline 的另一种方法尝试过这个:

pipe = Pipeline(steps=[('pca', pca), ('logistic', classifier)])

pipe.set_params(pca__n_components = n_comp).fit(X_train,y_train)

print 'score = ', pipe.score(X_test,y_test)

但我得到了完全相同的准确率 77.57%。我是否正确实施了 PCA + Logistic 回归?一定有什么问题,我只是想不通它是什么。

虽然我无法立即发现任何错误,但您应该尝试测试如果增加 number of components 错误的行为方式。也许缺少一些低方差信息来为逻辑回归提供所需的优势?

PCA 中的 99% 与其说是事实,不如说是指导方针。

您可以尝试的其他事情: 而不是 PCA,只需删除 零(或非常低)方差 的每个特征。 DTI 数据通常具有永不改变的特征,因此完全不需要分类。

尝试寻找与您的结果密切相关的特征,并尝试仅使用这些特征进行分类。

始终小心不要过拟合!

Correct me if I'm wrong, but PCA will produce a new set of features from the original ones.

我会尽量把它描述成非技术性的

是的。 PCA 基本上是一个花哨的 axis transformation。是的,你得到了一组新的特征,但它们是先前特征以有序方式的线性组合,因此第一个特征描述了尽可能多的数据。

这个想法是,如果你有一个超平面,PCA 实际上会 将超平面 投影到第一个轴,而使最后一个轴几乎为空。

PCA 是线性 降维,所以如果真实的数据分布不是线性的,它会给出更差的结果。

我的一个朋友也使用与您相似的大脑数据(很多特征,很少的例子),而 PCA 几乎没有帮助。可能是因为周围太多 "noise" 而没有找到重要的信息。

编辑:打字错误

我发现使用 MLPClassifer 对于 cc 默认集更准确。我将 PCA 添加到我的管道中,然后访问它以查看可以删除哪些功能。

PCA 目的 1. 相同数据但特征较少 2. 假设低方差是噪声 3. 指定保留多少特征

    pipeline= Pipeline([
    ('scaler',StandardScaler()),
    ('pca', PCA()),
    #('clf2',LogisticRegression(max_iter=10000, tol=0.1)),
    ('clf',MLPClassifier(hidden_layer_sizes=(36,150,36),  max_iter=100, solver='adam', 
             activation='relu', 
             alpha=0.1, 
             learning_rate_init=0.001,
             verbose=False,
             momentum=0.9,
             random_state=42))
     ])
     pipeline.fit(X_train,y_train)
     y_pred = pipeline.predict(X_test)
     cm = confusion_matrix(y_test,y_pred)

     class_names=[1,2]
     fig, ax = plt.subplots()
     tick_marks = np.arange(len(class_names))
     plt.xticks(tick_marks, class_names)
     plt.yticks(tick_marks, class_names)
     sns.heatmap(pd.DataFrame(cm), annot=True, cmap="coolwarm" ,fmt='g')
     ax.xaxis.set_label_position("top")
     plt.tight_layout()
     plt.title('Confusion matrix', y=1.1)
     plt.ylabel('Actual label')
     plt.xlabel('Predicted label')

     print("Test Accuracy is %s",pipeline['clf'].score(X_test,y_test)*100)

     pred_train=pipeline.predict(X_train)
     print("Train Accuracy is %s",accuracy_score(y_train, pred_train))
     
     pca=pipeline['pca']
     pca_features=pca.components_
     

     fig,ax = plt.subplots(figsize=(16,8))
     # Assign 1st column of pca_features: ys
     xs = pca_features[:,0]
     ys = pca_features[:,1]
     sns.scatterplot(x=xs, y=ys)

     mean = pca.mean_
     first_pc = pca.components_[0,:]
     # Plot first_pc as an arrow, starting at mean
     plt.arrow(mean[0],mean[1], first_pc[0], first_pc[1],       color='red', width=0.01)

     plt.axis('equal')
     plt.show()

     fig,ax = plt.subplots(figsize=(16,8))
     features = range(pca.n_components_)
     ax.bar(features, pca.explained_variance_)
     plt.xticks(features)
     plt.ylabel('variance')
     plt.xlabel('pca features')
     plt.show()