这次实验主要是通过sklearn库来熟悉PCA流程,掌握PCA的必要步骤。通过两个代码示例来做实验,并实现PCA(实现代码在最后部分),部分理解如下:
第一个示例只是用来降维,部分如下:
这是提前导入PCA库:
from sklearn.decomposition import PCA
这是用PCA保留1个特征个数:
pca = PCA(n_components=1)
这是用X来训练,即对X进行PCA降维:
pca.fit(X)
返回具有最大方差的成分
pca.components_
这是用X来训练PCA模型,同时返回降维后的数据:
X_reduction = pca.transform(X)
这是将降维后的数据转换成原始数据,方便绘图:
X_restore = pca.inverse_transform(X_reduction)
第二个示例则使用了数据集来实现了较为完整的PCA和K近邻算法的使用,部分如下:
这是将数据分成训练集和测试集:
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
这是导入k近邻算法转换器:
knn_clf = KNeighborsClassifier()
这是用X_train, y_train来训练模型:
knn_clf.fit(X_train, y_train)
这是用测试集来检验模型的正确率:
knn_clf.score(X_test, y_test)
这是第一个示例,图中紫色散点图是原来数据的二维特征,图中红色散点是用PCA将2维数据降至1维后,又返回到二维绘制的图像,这就相当于将紫色的点投影到红色所在的线上。而且发现投影后各点分布比较离散,方差很大,说明降维的效果很好。
这是第二个示例中,随着特征个数保留的变化,方差的变化情况,从图中可以看出,当保留特征数为2时,方差仅仅只有0.2左右,所以这就是为什么正确率只有60%。当特征数在30左右时,方差增加的很缓慢,区域稳定,所以当保留95%的方差时,数据降维到28维,且正确率为0.98。所以降维所保留特征数不能太少,那样正确率比较低,保留太大特征时,方差变化不大,正确率增加也不大,应该灵活调整。
这是第二个示例中,用PCA将数据降到二维后画出的10个类型的散点图,从图中可以发现有些数据存在重合现象。将本来的64维降到2维后,方差保留较少,降维的效果不太好,所以应该适当选择保留特征数。
PCA算法的主要优点有:
1.仅仅需要以方差衡量信息量,不受数据集以外的因素影响。
2.各主成分之间正交,可消除原始数据成分间的相互影响的因素。
3.计算方法简单,主要运算是特征值分解,易于实现。
PCA算法的主要缺点有:
1.主成分各个特征维度的含义具有一定的模糊性,不如原始样本特征的解释性强。
2.方差小的非主成分也可能含有对样本差异的重要信息,因降维丢弃可能对后续数据处理有影响。
PCA类:
class PCA(object):
"""定义PCA类"""
def __init__(self, x, n_components=None):
self.x = x
self.dimension = x.shape[1]
if n_components and n_components >= self.dimension:
raise DimensionValueError("n_components error")
self.n_components = n_components
def reduce_dimension(self):
"""指定维度降维和根据方差贡献率自动降维"""
c_df_sort = self.get_feature()
varience = self.explained_varience_()
if self.n_components: #指定降维维度
p = c_df_sort.values[0:self.n_components, 1:]
y = np.dot(p, np.transpose(self.x))
return np.transpose(y)
varience_sum = sum(varience)
varience_radio = varience / varience_sum
varience_contribution = 0
for R in xrange(self.dimension):
varience_contribution += varience_radio[R]
if varience_contribution >= 0.99:
break
p = c_df_sort.values[0:R+1, 1:] #取前R个特征向量
y = np.dot(p, np.transpose(self.x))
return np.transpose(y)
def cov(self):
"""求x的协方差矩阵"""
x_T = np.transpose(self.x) #矩阵转置
x_cov = np.cov(x_T) #协方差矩阵
return x_cov
def get_feature(self):
"""求协方差矩阵C的特征值和特征向量"""
x_cov = self.cov()
a, b = np.linalg.eig(x_cov)
m = a.shape[0]
c = np.hstack((a.reshape((m,1)), b))
c_df = pd.DataFrame(c)
c_df_sort = c_df.sort(columns=0, ascending=False)
return c_df_sort
第一个示例:
import numpy as np
import matplotlib.pyplot as plt
X = np.empty((100, 2))
X[:,0] = np.random.uniform(0., 100., size=100)
X[:,1] = 0.75 * X[:,0] + 3. + np.random.normal(0, 10., size=100)
from playML import PCA
pca = PCA(n_components=2)#保留2个特征个数
pca.fit(X)#用X来训练
pca.components_#返回具有最大方差的成分
pca = PCA(n_components=1)
pca.fit(X)
X_reduction = pca.transform(X)#用X来训练PCA模型,同时返回降维后的数据
X_reduction.shape
X_restore = pca.inverse_transform(X_reduction)#将降维后的数据转换成原始数据
X_restore.shape
plt.scatter(X[:,0], X[:,1], color='b', alpha=0.5)#散点图
plt.scatter(X_restore[:,0], X_restore[:,1], color='r', alpha=0.5)
plt.show()
第二个示例:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
digit = datasets.load_digits()
X = digit.data
y = digit.target
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
X_train.shape
%%time
from sklearn.neighbors import KNeighborsClassifier
knn_clf = KNeighborsClassifier()
knn_clf.fit(X_train, y_train)
knn_clf.score(X_test, y_test)
%%time
knn_clf = KNeighborsClassifier()
knn_clf.fit(X_train_reduction, y_train)
knn_clf.score(X_test_reduction, y_test)
pca.explained_variance_ratio_ ##拟合原数据的多少
pca = PCA(n_components=X_train.shape[1])
pca.fit(X_train)
pca.explained_variance_ratio_#返回所保留的n个成分各自的方差百分比
plt.plot([i for i in range(X_train.shape[1])],
[np.sum(pca.explained_variance_ratio_[:i+1]) for i in range(X_train.shape[1])])
plt.show()
pca = PCA(0.95) #解释原来数据95%的方差
pca.fit(X_train)
pca.n_components_
X_train_reduction = pca.transform(X_train)
X_test_reduction = pca.transform(X_test)
%%time
knn_clf = KNeighborsClassifier()
knn_clf.fit(X_train_reduction, y_train)
knn_clf.score(X_test_reduction, y_test)
pca = PCA(n_components=2)
pca.fit(X)
X_reduction = pca.transform(X)
X_reduction.shape
for i in range(10):
plt.scatter(X_reduction[y==i,0], X_reduction[y==i,1], alpha=0.8)
plt.show()