ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

12种相关系数全解析:告别只会用皮尔逊

12种相关系数全解析:告别只会用皮尔逊 如果你在分析两列变量之间的关系第一反应是不是直接df.corr()一把梭如果你的默认选项只有皮尔逊相关系数这一个那你和很多刚入门数据分析的同学一样其实错过了整整一整个相关分析工具箱。皮尔逊确实经典但真不是万能钥匙——数据稍微换换形态比如变成有序等级、分类标签、或者存在明显非线性关系时它的结果就可能严重失真甚至会给出完全相反的结论。这篇文章我会把日常工作中真正用得上的12种相关系数一次讲透。每种都会说清楚它解决什么问题、使用的边界条件、在Python里怎么实现、以及实际案例中的解读细节。看完之后你可以根据自己的数据形态直接对号入座不再被动等待pandas的默认输出。1. 先有皮尔逊为什么还需要另外11种很多同学的困惑从这里开始皮尔逊相关系数不是教科书里写的“两个变量相关程度的度量”吗难道不够用说实话如果数据满足皮尔逊协方差定义的几个苛刻前提它确实很强大要求两个变量必须是连续型数据、呈线性关系、大致服从正态分布、且没有明显异常值。但真实业务数据往往一个条件都不满足。拿一个我踩过的坑举例。某次做用户行为分析发现用户在App上的使用时长和次日留存率之间的皮尔逊相关系数只有0.08基本算无关。后来我把“使用时长”换成“使用时长排名”也就是对数据做秩变换后再算相关斯皮尔曼相关系数直接跳到0.61明显强相关。原因就是使用时长分布严重右偏部分重度用户把均值拉得很高皮尔逊相关系数被这群“极端值”带偏到沟里去了。皮尔逊本身也只对线性关系敏感。假设Y X²这个关系X在[-10, 10]范围内均匀分布皮尔逊算出来会非常接近0但你心里清楚X和Y之间明明有确定性的函数关系。这就是皮尔逊的盲区——它衡量的是“线性相关”不是“相关”。所以当你面对多样化的数据形态时仅靠一个皮尔逊完全不够需要一套能够适配不同场景的相关系数族。后面要讲的12种方法本质上是围绕三个维度展开的变量类型连续型、有序型、二分型、混合型。关系形态线性、单调、非线性、一般依赖。业务场景探索性分析、假设检验、特征筛选、共线性诊断。先想清楚自己的数据和问题属于哪一类再决定用哪个系数这才是正确的工作顺序。2. 12种相关系数全景图先建立整体认知在逐个拆解之前先把12种相关系数放到一张总览表里让大家对它们的定位有个整体把握。这张表是我在实践中反复使用后整理出来的比翻教科书的目录更直观。相关系数数据类型可识别的关系形态取值范围一句话特点皮尔逊相关系数连续型线性[-1, 1]经典默认选项但对异常值和非线性关系很脆弱斯皮尔曼秩相关连续/有序型单调[-1, 1]基于秩计算能抵抗异常值应用最广的非参数替代方案肯德尔秩相关系数连续/有序型单调[-1, 1]擅长处理并列等级多、小样本数据计算稍慢点双列相关连续型二分型线性[-1, 1]本质是皮尔逊的特殊形式专门服务“连续二分类”结构Phi系数两个二分型线性[-1, 1]从卡方统计量出发判断两个二分变量是否存在关联偏相关系数连续型需控制变量线性[-1, 1]剔除第三个变量的干扰后看两变量间的“净”关系复相关系数多个连续型→一个连续型线性组合[0, 1]衡量一组自变量对因变量的整体解释程度等价于多元回归的R距离相关性连续型/向量线性非线性[0, 1]系数为0当且仅当两变量独立是判断“是否有关”的金标准之一最大信息系数连续型/混合型线性非线性[0, 1]擅长捕捉复杂函数关系适合探索性分析互信息任意类型任意含非线性[0, ∞)信息论视角度量“知道一个变量降低另一个变量多少不确定性”Hoeffdings D连续型/有序型一般依赖含非单调[-0.5, 1]对非单调关系也敏感大样本下判断独立性的利器余弦相似度高维向量方向相似[-1, 1]做文本、用户向量、嵌入特征的相似性计算时最爱用它这张表并不是让你把12个全部背下来。我的建议是把它当作“工具箱清单”真正遇到业务问题时先按数据类型锁定候选方法再按关系形态进一步缩小范围最终用显著性检验确认结论。2.1 从三个维度理解它们之间的关系第一个维度是数据类型。连续型数据拥有丰富的数值信息可以支持皮尔逊、距离相关、MIC等需要原始数值的方法。有序型数据本身只有排序意义比如学历等级或满意度评分这时候斯皮尔曼和肯德尔这种基于秩次的方法更合理。二分型数据则用点双列、Phi这类专门设计的方法。混合型数据场景下互信息和MIC往往是更稳妥的选择。第二个维度是关系形态。线性关系用皮尔逊没问题单调关系——也就是一个增加另一个也持续增加但不一定是直线——用斯皮尔曼或肯德尔非线性的函数关系比如指数、对数、周期波动距离相关和MIC才有机会识别出来如果你连关系形态都不确定Hoeffdings D这种针对一般依赖性设计的方法可以作为兜底。第三个维度是应用目的。如果只是做探索性分析想快速摸清哪些变量有关联优先考虑MIC和距离相关。如果是在做回归建模前的特征筛选互信息和皮尔逊用得最多。如果需要判断两变量相关是否只是“假象”背后有其他变量在捣乱那就得上偏相关。这三个维度不是割裂的实际选型时它们会同时发生作用。我自己的习惯是先画散点图用眼睛大致判断关系形态再结合数据类型去选相关系数。这个流程看起来很初级但能帮你避免不少“算出个数字却完全没法解释”的尴尬情况。3. 逐个拆解每种相关系数到底怎么用3.1 皮尔逊相关系数线性关系的默认选项皮尔逊相关系数定义为两个变量的协方差除以它们各自标准差的乘积。这个式子的含义可以理解为先把两个变量做标准化然后计算它们共同变化的程度。标准化之后变量的取值就不再受量纲影响所以身高和体重算相关、房屋面积和房价算相关量纲不同都不妨碍比较。Python中的实现很简单import numpy as np from scipy import stats x np.array([1, 2, 3, 4, 5]) y np.array([2, 4, 6, 8, 10]) r, p stats.pearsonr(x, y) print(f皮尔逊相关系数: {r:.4f}, p值: {p:.4f})这段代码输出的皮尔逊相关系数是1.0因为y恰好是x的线性函数。但要注意这个场景太理想了。真实数据中皮尔逊对异常值非常敏感一个点就足以让相关系数从0.8跌到0.2。所以每次跑完皮尔逊我都会顺手看一眼散点图确认没有极端点主导了相关趋势。另一个常见误区是把皮尔逊结果当作“非线性无关”的证明。如果你算出来r接近0只能说这两个变量不存在线性关系不能断言它们完全无关。比如Y sin(X)这种周期性关系皮尔逊几乎总是接近0但两者明明有很强的规律性关联。这一点在数据探索阶段特别容易坑到人。3.2 斯皮尔曼秩相关不用看正态脸色的稳健替代斯皮尔曼秩相关系数的工作原理很朴素先把两个变量分别排序得到秩次然后对这些秩次计算皮尔逊相关系数。举个例子身高数据从小到大排最矮的分配秩次1最高的分配秩次n体重也做同样处理最后计算两组秩次之间的相关性。这样做的好处在于它彻底摆脱了对原始数值的依赖只关心相对顺序。因此异常值对秩次的影响极为有限——哪怕某个用户的使用时长是常人的100倍它在秩次序列里的位置并不会因此“翻天”。这正是我在用户行为分析中喜欢先用斯皮尔曼的原因。from scipy import stats # x包含了极端值y与x有单调关系 x np.array([1, 2, 3, 4, 5, 100]) y np.array([1.2, 2.1, 3.3, 4.2, 5.1, 99]) r_p, _ stats.pearsonr(x, y) r_s, _ stats.spearmanr(x, y) print(f皮尔逊: {r_p:.4f}, 斯皮尔曼: {r_s:.4f})实测中这个例子的皮尔逊会被极端值放大到接近0.999以上而斯皮尔曼会给出更符合直觉的结果。如果两个变量本来就是有序变量比如“满意度评价很差到很好”和“复购意愿很低到很高”斯皮尔曼更是比皮尔逊合适——因为它不需要假设评价尺度之间的间距是均匀的。3.3 肯德尔秩相关系数处理并列等级的专家肯德尔tau和斯皮尔曼一样属于秩相关家族但计算逻辑完全不同。它统计所有样本对中“一致的顺序对”与“不一致的顺序对”的数量再据此计算相关系数。想象一下把所有用户两两配对如果用户A在变量X上比用户B高在变量Y上也比用户B高这对样本就是一致对反之如果X高了Y却低了就是不一致对。tau系数衡量一致对相对优势的程度。肯德尔tau对数据中“并列名次”的处理比斯皮尔曼细致。当你面对满意度评分这种数据时——大量用户都打4分或者5分——斯皮尔曼会因为并列等级的校正变得繁琐肯德尔tau-b则能更清晰地反映这种离散数据的关联强度。from scipy import stats x [1, 1, 2, 2, 3, 3, 4, 5] y [2, 2, 3, 3, 3, 4, 5, 5] tau, p stats.kendalltau(x, y) print(f肯德尔tau: {tau:.4f}, p值: {p:.4f})实际使用中还要注意肯德尔tau有a、b、c三种变体。a不处理并列点b做了调整c适合处理行数不等于列数的列联表。scipy默认算的是tau-b已经覆盖了多数场景。如果样本量很大比如上万条肯德尔tau的计算速度会比斯皮尔曼慢不少因为要两两比较样本对这时候优先考虑斯皮尔曼更实用。3.4 点双列相关连续和二分变量的桥梁点双列相关系数解决的是“一个连续变量和一个真正的二分变量之间怎么算相关”的问题。比如独立访客数和是否购买了会员之间的关系是否购买就是一个天然的二分变量。从数学角度看它的计算等价于把二分变量的两个类别编码为0和1后、与连续变量算皮尔逊所以取值范围仍然是[-1, 1]。from scipy import stats continuous np.array([3.2, 4.5, 7.8, 2.1, 9.0, 8.4, 5.5, 6.1]) binary np.array([0, 0, 1, 0, 1, 1, 0, 1]) r, p stats.pointbiserialr(continuous, binary) print(f点双列相关系数: {r:.4f}, p值: {p:.4f})解读时要注意一个细节点双列相关对连续变量是否正态分布比较敏感。如果连续变量严重偏态可先判断数据形态必要时改用后续会讲的非参数方法。另外如果连续变量的分布是双峰的——比如由两个不同子群体混合在一起——这个相关系数的解释会变得困难实际的“真实相关”可能被扭曲。3.5 Phi系数抓出两个二分变量的关联Phi系数是处理两个二分变量之间关联度量的经典方法。背后的计算路径是先构建一个2×2列联表比如是否为会员和是否完成购买交叉统计出四个格子的频数然后基于卡方统计量换算成介于[-1, 1]之间的系数。import numpy as np from scipy.stats import chi2_contingency table np.array([[30, 10], [15, 45]]) chi2, p, dof, expected chi2_contingency(table) n table.sum() phi np.sqrt(chi2 / n) print(fPhi系数: {phi:.4f}, p值: {p:.4f})这里输出的Phi系数是0.6左右的话说明两个二分变量之间存在较强关联。解读时不要把它当成“一个变量变化导致另一个变化多少”的因果度量它是关联强度不是效应量。Phi系数和前面提到的点双列相关在公式上同源但这是两个四分变量的前提后面再细说。3.6 四分相关两个二分变量潜在正态分布的估计四分相关Tetrachoric correlation和Phi系数很容易混淆但应用前提完全不同。Phi是整个列联表联合分布的简单关联汇总而四分相关假设两个二分变量背后各有一个连续的潜在变量这两个潜在变量服从双变量正态分布现在因为某种阈值把连续变量切成了两个类别。比如用户“是否复购”可能背后是“复购意愿强度”超过某个阈值的产物。这个场景和金融风控中的“违约与否”类似——借贷人是否违约是个二分标签但背后一定有某种连续型的信用风险水平。当你想估计违约标签和另一个二分特征之间的真实潜在相关性时用四分类相关会更贴合业务逻辑。Python生态里实现四分类相关库比较少见一般使用factor_analyzer或tetrachoric等小众库也可以自己实现迭代估计。因为涉及数值优化建议在需要这种精细分析时再使用日常探索阶段用Phi系数就够了。3.7 偏相关系数剥离混杂变量的干扰偏相关解决的是一个特别常见的业务痛点你看到X和Y相关但怀疑是第三个变量Z在背后“操纵”了这种关系。举例来说冰淇淋销量和溺水人数在夏季同步上升皮尔逊相关系数很高但谁都知道吃冰淇淋不会导致溺水。真正的原因是“气温”这个混杂变量同时影响了两者。偏相关就是在控制气温的前提下看冰淇淋销量和溺水人数还剩下多少直接相关性。用Python实现偏相关我推荐pingouin库它对统计方法的封装比statsmodels更贴近日常分析习惯import pandas as pd import pingouin as pg df pd.DataFrame({ ice_cream: [100, 120, 140, 160, 180], drowning: [10, 15, 18, 22, 30], temperature: [18, 22, 26, 30, 34] }) partial pg.partial_corr(datadf, xice_cream, ydrowning, covartemperature) print(partial)实测中不控制温度时冰淇淋和溺水的皮尔逊相关系数通常能达到0.9以上而控制温度后的偏相关可能直接落到0.1以下。这个结果说明原始相关百分之九十以上都是混杂因素造成的“伪相关”。在因果分析或者特征筛选时偏相关是一个非常有价值的排查工具。3.8 复相关系数一组变量和一个变量的整体关系如果说偏相关是在剔除干扰复相关则是要回答一个相反的问题多个自变量加在一起能解释因变量的多少变化多元线性回归中的R或者说决定系数R²的平方根就是复相关系数。它衡量的是“最优线性组合”下的最大相关性而不是简单地把各变量与因变量之间的相关系数相加。import numpy as np from sklearn.linear_model import LinearRegression X np.array([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]]) y np.array([2, 4, 6, 8, 10]) model LinearRegression().fit(X, y) r_squared model.score(X, y) multiple_r np.sqrt(r_squared) print(f复相关系数: {multiple_r:.4f})解读复相关时最需要警惕的是过拟合。变量数量越多R²一定只增不减哪怕那些变量纯粹是噪声。所以看到很高的复相关时先检查调整后的R²看看模型有没有在“背样本数据”。如果调整R²明显低于R²说明模型引入了过多无用特征需要重新修剪变量集。3.9 距离相关性识别非线性关系的金标准前面反复提到的“非线性关系”问题需要有一个能通用检测的工具那就是距离相关性。它的核心思想是不直接比较两个变量的原始取值而是把每个样本看作一个点在各自的样本空间里计算距离矩阵然后衡量这两个距离矩阵之间的相似性。如果两个变量确实存在某种依赖关系——哪怕是非线性的、非单调的——样本间的距离模式必然会相互呼应。这个性质让它拥有了一个很多相关系数不具备的“美德”距离相关系数为0当且仅当两个变量统计独立。也就是说距离相关不仅能够检测线性相关还能检测任意形态的非线性依赖这是皮尔逊绝对做不到的。Python中使用dcor库即可import numpy as np import dcor x np.linspace(-10, 10, 500) y x ** 2 dcor_val dcor.distance_correlation(x, y) print(f距离相关: {dcor_val:.4f})同样的数据皮尔逊算出来几乎等于0而距离相关会给出一个很高的值。这个特性在探索未知关系时极有价值。我通常把距离相关当“扫描雷达”用——先用它快速筛查变量之间的候选关系发现信号后再用更细的工具深入分析具体形态。缺点是计算复杂度较高大数据集上跑起来比较慢。3.10 最大信息系数大数据时代的非线性探索器最大信息系数简称MIC设计初衷和距离相关类似都是要捕捉广义的相关关系但它走了一条完全不同的路。它会在二维平面上尝试用不同分辨率的网格进行划分针对每种划分方式计算互信息并做归一化再取所有划分方式中的最大值作为变量间关联程度的估计。MIC的优势是“公平性”它不会因为某种函数形式占便宜无论关系是线性的、指数的、三角函数的还是其他复杂模式理论上都能被公平地识别。这在特征非常多、关系形态未知的场景下特别好用。Python实现通常需要安装minepy库它提供了底层C语言的绑定from minepy import MINE x np.linspace(0, 10, 500) y np.sin(x) 0.1 * np.random.randn(500) mine MINE() mine.compute_score(x, y) print(fMIC: {mine.mic():.4f})注意MIC对样本量有一定要求样本太少时网格划分不够细结果会不稳定。我自己的体验是至少要有几百条数据才比较可信。由于计算需要尝试多种网格划分方式在大规模数据上耗时也明显一般用于探索阶段的候选关系筛选而不是大规模计算的核心工具。3.11 互信息从信息论角度测量相关性互信息是信息论里的经典度量它回答的问题是知道了变量X的值对变量Y的不确定性会减少多少如果两个变量完全独立互信息为0如果知道一个就能完全预测另一个互信息达到最大值。互信息对数据类型的包容性极强连续型、离散型、混合型都能处理。它在机器学习特征选择中非常受欢迎尤其是对类别特征与连续目标变量之间的关系挖掘。scikit-learn 直接提供了相关实现from sklearn.feature_selection import mutual_info_regression X np.array([[1.2], [2.3], [3.1], [4.8], [5.2]]) y np.array([1, 4, 9, 16, 25]) mi mutual_info_regression(X, y, random_state42) print(f互信息: {mi[0]:.4f})互信息的大小没有像皮尔逊那样的[-1, 1]标准范围它是个非负数最大值取决于变量本身的熵。因此不同数据集之间的互信息值不能直接横向比较。大多数实践场景中我们用互信息做相对排序而不是绝对判断——在特征筛选中互信息值高的特征优先纳入模型这一点是可靠的。3.12 Hoeffdings D针对一般依赖关系的严格判据Hoeffdings D是一个相对冷门但非常严格的相关系数。它的独到之处在于对任何形式的一般依赖关系都有检测能力包括那些斯皮尔曼和肯德尔都容易漏掉的情况——比如“X中心区域Y波动大两端Y波动小”这类非单调模式。从数学形式来看它基于秩统计量的计算过程会同时考虑联合分布和边际分布之间的差距。只要两个变量存在任何形式的相关关系即使不是单调关系Hoeffdings D也能捕捉到信号。Python的scipy从1.9版本开始提供了原生的计算接口from scipy import stats x np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) y np.array([1, 1, 2, 2, 3, 3, 2, 2, 1, 1]) d, p stats.hoeffd(x, y) print(fHoeffdings D: {d:.4f}, p值: {p:.4f})这个例子里y先是随x上升、后又下降是非单调的“倒U形”关系皮尔逊、斯皮尔曼、肯德尔可能都只能给出很弱的相关信号但Hoeffdings D会对这种关系表现出较高灵敏度。不过它也有局限需要样本量偏大时结果才稳定小数据集上容易出现虚高的倾向。所以更适合作为“独立性检验”的最后保险而不是日常探索的首选。3.13 余弦相似度从“共变”到“方向一致”的思维转换严格来说余弦相似度并不是在统计理论上被定义出来的经典相关系数但在现代数据科学里它出场频率比很多老牌统计数据都高。特别在文本分析、推荐系统、用户画像嵌入这些场景中我们关心的并不是两列数值之间的线性相关而是两个高维向量方向是否一致。比如“用户对10类内容的偏好向量”我们更想知道用户之间品味是否相似而不是逐维度地做相关检验。from sklearn.metrics.pairwise import cosine_similarity import numpy as np user_a np.array([[5, 3, 0, 1]]) user_b np.array([[4, 2, 0, 1]]) sim cosine_similarity(user_a, user_b) print(f余弦相似度: {sim[0][0]:.4f})余弦相似度的取值范围是[-1, 1]但在非负数据场景如词频、评分下通常落在[0, 1]之间。它的核心特点是只看方向不看模长两个向量的模长差异不会影响相似度结果。这也意味着如果你关心的是“幅度”信息比如总消费量差异余弦相似度就不太适合应该考虑数字特征上更敏感的皮尔逊或距离相关。4. 实战选型不做理论党只做能落地的决策学完12种相关系数后最常被问的问题是那我到底用哪个我自己的选择流程可以总结成一张决策表核心逻辑是按数据形态来对号入座。数据形态首选方法备选方法两个连续变量关系看似线性皮尔逊斯皮尔曼有异常值时两个连续变量关系可能非线性距离相关MIC、Hoeffdings D两个连续变量只想判断是否独立距离相关Hoeffdings D有序变量或含有较强异常值斯皮尔曼肯德尔tau连续变量 二分变量点双列相关斯皮尔曼两个二分变量Phi系数四分相关样本量大时剔除混杂变量后的相关性偏相关无多个自变量对一个因变量的整体关系复相关R无文本、用户向量、高维稀疏特征余弦相似度互信息特征选择、类别特征与目标关系互信息MIC这张表解决的是第一层“选什么”的问题。第二层的问题是“怎么解读”。有几个我实践下来养成的铁律相关系数算出来再高也不能推导出因果关系。相关性只是告诉你“这两个变量在统计层面不独立”至于谁导致了谁需要实验设计或领域知识做支撑。不要只看相关系数的大小一定要看显著性p值。样本量很小时再大的相关系数也可能不显著样本量很大时再小的相关系数也可能显著。两者结合着看才靠谱。出现“皮尔逊接近0但斯皮尔曼很高”的情况时几乎可以确定是非线性或单调性关系这时候不要再依赖皮尔逊下结论。4.1 常见问题排查速查表下面这个速查表记录了我在实际项目和答疑中遇到的高频问题每条都附了处理思路希望能帮你节省一些排查时间。现象可能原因处理办法df.corr()出现NaN数据包含缺失值、列全是常数先删补缺失值剔除std为0的列皮尔逊很小但散点图明显有关关系是非线性的改用距离相关、MIC斯皮尔曼和皮尔逊方向相反异常值主导了线性趋势画图确认异常点用秩相关结果多个变量两两相关都很低可能是高维稀疏数据改用余弦相似度或互信息相关系数高但p值不显著样本量过小收集更多数据或改用非参数检验变量含真正类别标签A/B/C不适合直接算相关系数先做One-Hot编码后按需选Phi或互信息这些看似基础的问题真正做起来却是最容易翻车的地方。尤其第一条“出现NaN”我在刚用pandas时被坑过很多次后来养成习惯在跑任何相关矩阵之前先执行两行代码df.isnull().sum()和df.nunique()看一下缺失情况和常数列这比事后排查省心得多。4.2 我自己的实操建议相关分析不只是“调一个函数”最后分享几条我在真实项目中沉淀下来的操作习惯。如果你的需求只是快速看看变量之间的关系我建议先绘制成对的散点图矩阵用视觉快速筛选信号。seaborn.pairplot几分钟就能画出全貌哪些变量线性明显、哪些有曲线关系、哪些存在离群点一目了然。看完图再选相关系数方向基本不会错。如果需要批处理大量特征两两之间的关系——比如在做特征工程时有200个特征需要快速筛相关——我通常分批跑距离相关和MIC的扫描把候选关系收敛到几十对再做详细的可视化分析。直接对所有特征都跑高复杂度算法会非常耗时所以“粗筛精查”两步走是更务实的策略。还有一点踩过坑之后的体会当业务方或审稿人问起“你报的相关系数为什么和别人不一样”时真正的差异往往不在代码而在数据预处理细节。有没有删除异常值、有没有处理缺失值、有没有对分类变量做编码、用的是哪种相关系数——每一个环节都会影响最终数字。所以我现在的习惯是在汇报结果时顺手附上一句完整的方法说明“基于什么样的数据、用什么相关系数、样本量是多少、p值是多少”这一句话能挡掉后续好多沟通成本。
返回列表