np.cov() 默认按行计算协方差,即每行视为一个变量、每列视为一个样本;若数据为标准格式 (n_samples, n_features),必须显式设置 rowvar=False 才能得到正确的 n_features × n_features 协方差矩阵。

协方差矩阵用 np.cov(),但默认按行还是列算?
np.cov() 默认把**每一行当作一个变量(特征)**,把列当作观测样本。这和大多数统计建模习惯相反(通常一列是一个变量)。比如你有 100 个样本、3 个特征,数据形状是 (100, 3),直接传给 np.cov() 会返回 (100, 100) 的协方差矩阵——显然不是你想要的。
正确做法是加参数 rowvar=False:
import numpy as np X = np.random.randn(100, 3) # shape: (100, 3),100 样本,3 特征 cov_mat = np.cov(X, rowvar=False) # → shape: (3, 3)
常见错误现象:np.cov(X) 返回巨大矩阵、数值爆炸、对角线不是方差;调试时可先检查 cov_mat.shape 是否等于 (X.shape[1], X.shape[1])。
相关系数矩阵不能只靠 np.cov() 手动除?
虽然能用协方差矩阵除以标准差外积得到相关系数,但没必要——np.corrcoef() 就是为此设计的,行为和 np.cov() 高度一致:同样默认按行算,同样需要 rowvar=False。
立即学习“Python免费学习笔记(深入)”;
关键区别在于:np.corrcoef() 返回的是 [-1, 1] 区间内的无量纲值,且对角线恒为 1:
调用 Cutout.Pro 视觉处理 API 进行背景移除、人像抠图和照片增强,支持文件上传与图片 URL 输入。
corr_mat = np.corrcoef(X, rowvar=False) # shape: (3, 3),对角线全 1.0
- 如果输入含 NaN,结果整行/列变 NaN —— 先用
np.nanmean()或pd.DataFrame(X).dropna()清洗 -
np.corrcoef()内部仍调用np.cov(),所以性能差异可忽略 - 它不支持 Spearman 或 Kendall,要非线性相关得用
scipy.stats.spearmanr()
为什么标准化后 np.cov() 和 np.corrcoef() 结果一样?
因为相关系数本质就是“标准化后的协方差”:对每列减均值、除标准差后,协方差矩阵就自动变成相关系数矩阵。
验证方式(不推荐用于生产,仅助理解):
X_centered = X - np.mean(X, axis=0) X_scaled = X_centered / np.std(X, axis=0, ddof=1) # 注意 ddof=1 与 corrcoef 一致 cov_scaled = np.cov(X_scaled, rowvar=False) # ≈ np.corrcoef(X, rowvar=False)
容易踩的坑:
-
np.std()默认ddof=0,而np.cov()和np.corrcoef()默认用ddof=1(样本协方差),不统一会导致微小偏差 - 用
ddof=0标准化后算协方差,结果接近但不等于np.corrcoef() - 若数据已中心化但未缩放,
np.cov()输出就是协方差,不是相关系数
协方差矩阵奇异(不可逆)时怎么办?
当变量数 > 样本数,或存在完全共线性列(如两列相等、一列为另一列线性组合),np.cov(X, rowvar=False) 返回的矩阵秩亏,np.linalg.inv() 会报 LinAlgError: Singular matrix。
常见应对方式:
- 加小扰动:
cov_reg = cov_mat + 1e-8 * np.eye(cov_mat.shape[0]) - 用
np.linalg.pinv()替代np.linalg.inv()(伪逆,稳定但物理意义弱) - 降维:先用
np.linalg.svd()检查秩,或用 PCA 去掉小奇异值对应的方向 - 检查原始数据:是否有全零列、重复列、或
np.allclose(X[:, i], X[:, j])成立
这个点常被忽略:协方差矩阵是否可逆,不只取决于数值精度,更取决于采样机制和特征工程是否合理。

















