在数据分析领域,交叉分解方法是一种强大的工具,用于探索两个多变量数据集之间的相关性。这些方法可以提取出最能解释两个数据集之间共享方差的组分。本文将介绍几种常用的交叉分解方法,包括PLS典型分析(Canonical PLS)、PLS回归(包括多变量响应的PLS2和单变量响应的PLS1),以及典型相关分析(CCA)。
PLS典型分析是一种对称的PLS方法,它旨在找到两个数据集X和Y之间的最大相关性方向。通过这种方法,可以在散点图矩阵中观察到,数据集X和Y的第一个组分具有最大的相关性,而不同组分之间的相关性较弱。
import numpy as np
from sklearn.cross_decomposition import PLSCanonical
from matplotlib import pyplot as plt
# 生成模拟数据
n = 500
latents = np.random.normal(size=n), np.random.normal(size=n)
X = np.array([latents[0], latents[0], latents[1], latents[1]]).T + np.random.normal(size=4*n).reshape((n, 4))
Y = latents + np.random.normal(size=4*n).reshape((n, 4))
# 划分训练和测试数据集
X_train, Y_train = X[:n//2], Y[:n//2]
X_test, Y_test = X[n//2:], Y[n//2:]
# 应用PLS典型分析
plsca = PLSCanonical(n_components=2)
plsca.fit(X_train, Y_train)
X_train_r, Y_train_r = plsca.transform(X_train, Y_train)
X_test_r, Y_test_r = plsca.transform(X_test, Y_test)
# 绘制得分散点图
plt.figure(figsize=(12, 8))
plt.subplot(221)
plt.scatter(X_train_r[:, 0], Y_train_r[:, 0], label="训练", marker="o", s=25)
plt.scatter(X_test_r[:, 0], Y_test_r[:, 0], label="测试", marker="o", s=25)
plt.xlabel("X得分")
plt.ylabel("Y得分")
plt.title("第1组分: X vs Y")
plt.legend(loc="best")
plt.show()
PLS回归是另一种交叉分解方法,它可以用于预测一个多变量响应(PLS2)或单变量响应(PLS1)。在PLS回归中,关注的是预测变量和响应变量之间的关系。
from sklearn.cross_decomposition import PLSRegression
# 生成模拟数据
n = 1000
p = 10
X = np.random.normal(size=n*p).reshape((n, p))
B = np.array([[1, 2] + [0]*(p-2)]).T
Y = np.dot(X, B) + np.random.normal(size=n*1).reshape((n, 1)) + 5
# 应用PLS回归
pls2 = PLSRegression(n_components=3)
pls2.fit(X, Y)
# 输出真实和估计的系数
print("真实系数 B (使得 Y = XB + Err)")
print(B)
print("估计的系数")
print(np.round(pls2.coef_, 1))
典型相关分析(CCA)是一种寻找两组变量之间典型相关变量的方法。它与PLS方法类似,但通常用于探索两个数据集之间的关系,而不是进行预测。
from sklearn.cross_decomposition import CCA
# 应用CCA
cca = CCA(n_components=2)
cca.fit(X_train, Y_train)
X_train_r, Y_train_r = cca.transform(X_train, Y_train)
X_test_r, Y_test_r = cca.transform(X_test, Y_test)
# 绘制得分散点图
plt.figure(figsize=(12, 8))
plt.subplot(221)
plt.scatter(X_train_r[:, 0], Y_train_r[:, 0], label="训练", marker="o", s=25)
plt.scatter(X_test_r[:, 0], Y_test_r[:, 0], label="测试", marker="o", s=25)
plt.xlabel("X得分")
plt.ylabel("Y得分")
plt.title("第1组分: X vs Y")
plt.legend(loc="best")
plt.show()