见我的另一篇博客: PCA原理介绍
见我的另一篇博客: PCA+SVD原理介绍
在PCA降维数据预处理时,很多人都会遇到一个疑问:
我开始也遇到了这样的疑问,但是b的方法肯定是直接拒绝的!因为b的方法会导致训练集测试集完全在两个分布下,他们的均值不一样,标准化的标准也不一样,训练出来的结果肯定会非常不准确!
所以:
b. 还是说我该把训练集和测试集直接分开PCA降维? → False
那看到这,你肯定觉得,还是a得做法靠谱,确实我之前有段时间没有想到解决办法,也用的a办法,a办法不会有太大的损害,但是在把训练集和测试集放在一块PCA的时候,相当于训练集和测试集互相引入了信息,后来训练的网络很可能过拟合,准确率也虚高。
所以:
a. 我该把训练集和测试集放在一块,PCA降维后再分开吗? → False
↓
正确做法应该是:
1. 训练集 测试集提前分开,划分好;
2. 训练集预处理时,保存好训练集的均值+方差,它的零均值化,标准化正常进行;
3. 测试集利用刚保存的训练集的均值+方差进行零均值化,标准化;
1. 预处理后的训练集 测试集依然分开;
2. 用训练集进行PCA降维,得到投影矩阵P;
3. 测试集利用刚训练集得到的投影矩阵P进行降维;
这节重点讲代码:
data, dataTest = get_data() # 获取训练集data 测试集 dataTest准备PCA
print(len(data), '个样本', len(data.columns), '个属性')
print('---------------- PCA my data ... -------------------- ')
dataY = data[['allcase']] # 去除训练集的结果属性
dataX = data.drop('allcase', axis=1, inplace=False) # 保留训练集的普通属性 用于PCA
dataTestY = dataTest[['allcase']] # 去除测试集的结果属性
dataTestX = dataTest.drop('allcase', axis=1, inplace=False) # 保留测试集的普通属性 用于PCA
# 用训练集的平均数,方差去 预处理测试集
dataX, dataTestX = NormalizeData(dataX, dataTestX)
dataAfterPca, newColLen, dataTestAfterPca = myPCA(per, dataX, dataTestX) # PCA降维
def NormalizeData(data, dataTest):
scaler = StandardScaler() # 建立标准化模型
dataAttr = scaler.fit_transform(data) # fit_transform:采用训练集fit 模型,保存均值,方差 然后对训练集进行标准化
dataTestAttr = scaler.transform(dataTest) # transform:采用训练集的均值,方差 然后对测试集进行标准化
return dataAttr, dataTestAttr
注意: transform和fit_transform的是不一样的! fit_transform 是有两个步骤: 1. fit 训练模型; 2. transform; transform 只有transform这个步骤。
def myPCA(mcomponent, dataAttr, dataTestAttr):
p, n = np.shape(dataAttr) # shape of dataAttr p=row , n=col
# 求协方差矩阵cov_Mat
cov_Mat = np.dot(dataAttr.T, dataAttr) / (p - 1) # 对训练集得到协方差矩阵
u, d, v = np.linalg.svd(cov_Mat, full_matrices=False) # 对协方差矩阵做SVD U=UA 就是对原始样本SVD得到的Vb,即投影矩阵
# 翻转特征向量符号以强制执行确定性输出操作(svd_flip),这才是SVD每次PCA相差负号的原因。
u, v = svd_flip(u, v)
Index = index_lst(d, rate=mcomponent) # choose how many main factors
dataAttrAfterPca = pd.DataFrame(np.dot(dataAttr, u[:, :Index])) # 训练集利用PCA降维
print(len(dataAttrAfterPca.columns))
dataTestAttrAfterPca = pd.DataFrame(np.dot(dataTestAttr, u[:, :Index])) # 测试集利用PCA降维
print(len(dataTestAttrAfterPca.columns))
for each in dataAttrAfterPca.columns:
dataAttrAfterPca.rename(columns={each: str(each)}, inplace=True) # 把属性名字改成字符型的 便于存储CSV
for each in dataTestAttrAfterPca.columns:
dataTestAttrAfterPca.rename(columns={each: str(each)}, inplace=True)
# data transformation
return dataAttrAfterPca, int(Index), dataTestAttrAfterPca
见我的另一篇博客:python里如何使用成熟的现有PCA包