尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

线性相关关系别乱用:从散点图到皮尔逊相关系数的避坑指南

线性相关关系别乱用:从散点图到皮尔逊相关系数的避坑指南 前天晚上帮朋友看一组门店促销数据他一上来就发消息“两个指标的线性相关关系已经到0.98了这个月方案稳了。”我让他把散点图发过来看完差点没绷住绝大多数点挤在左下角右上角孤零零躺着一个极端大促日的点。把那个点删掉再跑一次相关系数直接跌到0.21。这是我见过最典型的“相关性翻车现场”。很多人一听到“线性相关关系”第一反应就是拿Excel或Python算一个皮尔逊相关系数然后开始写结论。但相关系数不是打印出来就能用的数字从数据形态、计算前提、异常值到“相关不等于因果”这条红线每一步都埋着坑。这篇东西既适合刚进数据分析行业的新人也适合常常被老板或客户追问“这两个数相关性多少”的运营、产品和市场同学。读完你至少能知道什么时候能放心用皮尔逊算完之后该怎么解读以及关系不线性时应该换什么工具。1. 先别急着按计算器散点图能告诉你的比相关系数更多1.1 一张散点图胜过十个统计量我做分析有个不太讲效率的习惯凡是第一次接触的两列数值型变量一定要先画散点图再看相关系数。原因很简单相关系数是个高度压缩的指标它把成千上万个点的关系压成一个数。这个“压缩”的过程注定会丢信息而且丢掉的往往是最关键的信息。比如两组数据一组是规规矩矩的线性递增另一组是在一条直线附近弯曲着向上走它们计算出来的皮尔逊相关系数可能都在0.9左右。但如果你直接按线性模型去做预测第二组的残差会呈现明显的抛物线形态误差越来越不可控。散点图能让你一眼看出这种差异相关系数却不能。所以我给团队定的规矩是任何相关系数结论必须搭配散点图。“r0.8”这句话本身没有意义只有“r0.8且散点图没有明显曲线、没有显著离群点、两列变量看起来确实是直线关系”这句话才有意义。1.2 从散点图形状预判相关系数大小看多了散点图之后你会慢慢建立起一种直觉大概什么样的图形对应多大的相关系数。我给新人培训时常用下面这张表散点图形态r的大致区间我的判断点云呈现明显的长椭圆从左下角拉伸到右上角0.7~1.0线性正相关方向清晰点云呈现明显长椭圆从左上角拉伸到右下角-1.0~-0.7线性负相关方向清晰点云形状接近圆形没有明显方向-0.3~0.3基本无线性相关点云沿着一条弯曲曲线分布比如U型或倒U型可能接近0非线性不能只用r判断绝大多数点聚在一起但有个别点被甩到很远处无法判断异常值可能主导r需要单独处理这里有个特别反直觉的地方两个变量明明存在很强的规律性联系比如x从-2变到2时y先下降再上升形成了一个完美的U形但皮尔逊相关系数可能接近0。因为它度量的只是“直线的”相关关系U型关系不是直线关系自然会被低估。这不是方法错是你问错了问题。1.3 数据清洗与单位问题画散点图之前还要确保数据是干净的。我见过太多人拿原始明细表直接算相关系数结果数据里带着缺失值、重复记录甚至有些行是“合计”或者“汇总”行混在明细里没筛掉。这些都能把计算结果搅得天翻地覆。另一个常见疑问是单位。“销量的相关系数和金额的相关系数怎么会不一样是不是我的数据有问题”其实不会不一样。皮尔逊相关系数对变量的线性变换是不敏感的你把x从“元”换成“万元”把y从“件”换成“百件”r值不会变。因为公式里的每个变量都被标准化了分子分母会同时缩放最终把单位约掉。真正要关心的不是单位而是数据背后的业务口径是否一致、是否在同一时间粒度上、有没有明显的记录错误。2. 皮尔逊相关系数公式、直觉和它真正回答的问题2.1 从协方差说起如果你只想记一个概念线性相关关系的核心量是协方差。协方差衡量的是两个变量同时偏离各自均值的程度x偏大y也偏大贡献为正x偏小y也偏小贡献也为正x偏大y反而偏小贡献为负。把所有点的这种“共同偏离”加起来平均就得到协方差。协方差大于0说明整体呈正相关小于0说明呈负相关等于0说明两个变量的线性联动不明显。但协方差有个很麻烦的特点它的数值会受变量刻度影响。x用“厘米”和用“米”计算协方差能差出好几个数量级完全没法统一比较。皮尔逊相关系数做的就是给协方差“标准化”把每个变量先减去自己的均值再除以自己的标准差然后再算协方差。这就是公式里为什么会有那一大堆平方和以及开方的原因。2.2 标准化之后的几何意义用更直观的方式理解把变量x和y分别转成标准分z-score后每一对数据就变成平面上的一个点。如果这些点全都精确地落在一条斜率为正的直线上那么它们的标准分完全相同相关系数就是1。如果全部落在一条斜率为负的直线上相关系数就是-1。如果点云整体呈现圆形没有明显的主方向相关系数就接近0。换句话说相关系数描述的是点云在二维平面里被“拉伸”得有多厉害。拉伸得越厉害椭圆越细长r的绝对值越接近1。这个几何视角能帮你记住一件事r度量的是“一起变”的程度而不只是“一个变大另一个也变大”的方向。2.3 r0.5不是“相关了一半”很多业务同学会把相关系数当成百分比来理解觉得r0.5就是两个变量“相关了一半”其实完全不是。如果做一元线性回归回归方程的R²也就是决定系数恰好等于皮尔逊相关系数的平方。r0.5R²只有0.25。这意味着一列变量的变动只能解释另一列变量变动的25%剩下75%仍然来自其他因素。我习惯在汇报里同时给出r和R²。r0.3在统计上可能显著但放到业务里一列变量只能解释另一列9%的变动。这种关系拿来作为决策依据基本等于抛硬币时略微看了一眼光线的明暗。不能说完全没信息但别指望它能扛大梁。2.4 显著性检验和置信区间算出r0.35之后第一步不是欢呼而是看p值。scipy的pearsonr会同时返回p值p值的含义是在“两个变量没有线性相关关系”的原假设下观察到当前这个r值的概率。p值小于0.05只是说明“这个r不太可能是巧合”。但p值极易被样本量绑架。样本量5000时r0.04也能得到p0.001样本量20时r0.6也未必显著。所以专业报告不能只给p值还要给置信区间。置信区间会告诉你这个r值的估计精度有多宽。两个点得到的r0.9置信区间可能是[-0.7, 0.99]和没估算差不多。Fisher z变换是构造区间常用的方法后面写代码时会给你一个可直接抄的函数。3. 线性外衣下的陷阱非线性关系、异常值与分层样本3.1 明明存在强关系r却接近0最常见的误用场景是研究销售额与“档期天数”的关系。业务经理想知道“营销周期越长销售额越高吗”于是直接算了两个变量的线性相关关系结果r0.08很失望。但把数据按时间展开后你会发现销售额随着档期天数呈明显的倒U型开幕期和闭幕期都很低中间爆发期最高。这种情况不是没有相关而是“有非线性相关”。皮尔逊只看直线关系面对倒U型、抛物线、指数衰减它都会失明。遇到这种业务语境你应该先画曲线再用多项式回归、分段拟合或者互信息一类的方法去度量强度而不是硬扔一个皮尔逊出来。3.2 安斯库姆四重奏同一个r不同的世界统计学里有个很有名的例子叫安斯库姆四重奏。四组数据各自有几乎完全相同的均值、方差、相关系数和回归线但把它们画成散点图后会发现其中一组是标准的线性关系一组是U型曲线一组是数据被一个极端离群点拉动还有一组是垂直排列的多个点加一个离群点。这个例子最狠的地方在于如果你只看统计指标会以为四个数据集是同一副面孔一旦画图就发现它们来自完全不同的世界。所以我每次做培训都会说一句话不画图的相关系数分析都是拿命在赌自己的结论。不是夸大是真的被坑怕了。3.3 辛普森悖论合计看着正相关分组全是负相关还有一种更隐蔽的情况来自样本结构。假设你把全国的门店按区域分组每一个区域内部门店面积与坪效的关系都是负相关的但把所有区域合在一起时因为大区集中在大城市、社区店集中在小城市整体算出来反而可能是正相关。这就是辛普森悖论。没有先做分层观察就汇报总体的线性相关关系结论极有可能和真实方向相反。尤其是做“相关性分析”时一定要在分析框架里带上可能的业务分组变量。至少把散点图按类别变量着色看看不同颜色是不是各自遵循不同的趋势。如果颜色不同趋势相反那就不能把总体r当作统一规律。3.4 异常值的破坏力与处理思路文章开头的促销数据就是一个典型的异常值案例。单个极端点可以把r从0.98拉到0.21也可能把一个明明不相关的数据对拉到0.8。处理异常值不是“看到不顺眼就删”而是先要搞清楚它是什么数据录入错误比如单位多打了一个零→ 修正或删除真实存在但属于极端业务场景比如双十一大促日→ 单独分析或做敏感性检验属于被解释变量中的极值比如病毒式传播事件的峰值→ 可以考虑取对数压缩量纲。一个比较稳妥的做法是先用散点图、z-score或者四分位距IQR找出异常点然后分别在“含异常值”和“剔除异常值”两种情况下计算r。如果两种结果方向或大小差异很大说明结论不稳定需要在报告里主动说明而不是藏着掖着。4. 相关≠因果给结论之前必须补上的三句话4.1 方向问题鸡生蛋还是蛋生鸡x和y相关没人告诉你谁是因谁是果。有可能x影响y有可能y影响x有可能两个互相影响形成循环。比如“用户活跃度”和“付费金额”强相关到底是活跃度高的人更容易付费还是付费的人因为投入了沉没成本所以更活跃业务上两种机制都存在。仅凭线性相关关系你无法区分。至少需要时间上的先后证据比如用上一周期x预测下一周期y或者做一些简单的实验控制一部分用户的x观察y的变化。如果这些都做不到报告里就应该写“存在相关关系待进一步验证方向”而不是拍脑袋下因果。4.2 混杂变量冰激凌、泳池与溺水统计学入门最经典的伪相关案例是冰激凌销量和游泳池溺水人数呈很强的正相关。如果只看相关系数你可能会得出“卖冰激凌导致溺水”的可笑结论。常识告诉我们真正的原因是热天让吃冰激凌的人变多也让游泳的人变多溺水事故随之增加。温度就是那个混杂变量。找到混杂变量后可以通过偏相关分析剔除它的影响。所谓偏相关就是先分别把x和y对混杂变量做回归取残差再算两个残差之间的相关。如果控制温度后冰激凌销量和溺水人数的相关迅速衰减到接近0那就基本说明原始相关是假象。4.3 中介与调节关系内部还有暗层不是所有关系都是一条直线走到底。有些变量是中介变量x通过m影响y。比如“广告预算”影响“品牌认知”再通过“品牌认知”影响“销售额”。预算和销售额的相关中有很大一部分其实是品牌认知传递过去的。还有些变量是调节变量比如“用户等级”会改变“折扣力度”和“消费金额”的关系高等级用户吃折扣低等级用户可能完全不在价格上敏感。遇到这种业务假设不能只报一个总体的r而应该分群计算。相关性分析最怕的就是拿一个总体系数掩盖不同群体截然不同的行为结构。4.4 真正想做因果就得换一套工具如果业务目标就是回答“涨工资会不会让人更努力”这类因果问题线性相关关系只能作为起点不能作为终点。可靠的因果结论依赖随机实验A/B测试、自然实验、工具变量、断点回归等设计。这些工具的共同点是找出一个外生的随机性或变化来源把混淆因素控制住。我常说一句话相关系数可以帮助你发现值得深挖的线索但因果结论一定需要额外的设计或数据。凡是宣称“因为相关所以因果”的报告都应该被回炉重造。5. 动手算一遍Python实现线性相关分析全流程5.1 先造一份可复现的数据这里给你一套可以直接在Jupyter里跑的流程。先用numpy构造一份含噪声的线性关系数据再人为加一个异常点模拟真实的脏数据。import numpy as np import pandas as pd from scipy import stats import matplotlib.pyplot as plt rng np.random.default_rng(42) n 60 x rng.normal(100, 15, n) y 2.5 * x rng.normal(0, 40, n) df pd.DataFrame({x: x, y: y}) # 人为加入一个异常点 outlier pd.DataFrame({x: [30], y: [800]}) df pd.concat([df, outlier], ignore_indexTrue) # 先看全量相关系数 r_all, p_all stats.pearsonr(df[x], df[y]) print(f全量数据 r {r_all:.3f}, p {p_all:.3e})你会发现这里r比较虚高异常点顺着对角线的方向把r拉大了。如果你直接在业务里遇到这类结果第一反应不应该是转发结论而是去画图。5.2 画散点图把异常点“看”出来fig, ax plt.subplots(figsize(6, 4)) ax.scatter(df[x], df[y], alpha0.7) ax.set_xlabel(x) ax.set_ylabel(y) ax.set_title(x vs y) plt.show()画出图之后右上角那个孤零零的点会非常刺眼。此时先不要删除做一个稳健性对比。比如用y值小于600作为门槛排除明显异常点后再算一次。df_clean df[df[y] 600].copy() r_clean, p_clean stats.pearsonr(df_clean[x], df_clean[y]) print(f剔除异常点后 r {r_clean:.3f}, p {p_clean:.3e})把两次结果放在一起你就能看到单个点对结论的影响有多大。我管这个叫“敏感性检查”不管最终是否剔除异常点都不会被同事质疑“你是不是故意删了不好看的数据”。5.3 给出置信区间而不是只有r和p值皮尔逊r的置信区间经常被忽略但它是判断估计稳定性的核心指标。用Fisher z变换计算区间步骤如下先把r转换成近似正态的z分数利用标准误估计置信区间再通过双曲正切函数还原回r的区间。from scipy import stats def pearson_ci(x, y, alpha0.05): r, _ stats.pearsonr(x, y) n len(x) z stats.norm.ppf(1 - alpha / 2) se 1 / np.sqrt(n - 3) z_lo np.arctanh(r) - z * se z_hi np.arctanh(r) z * se return np.tanh(z_lo), np.tanh(z_hi) ci_lo, ci_hi pearson_ci(df_clean[x], df_clean[y]) print(f95%置信区间: [{ci_lo:.3f}, {ci_hi:.3f}])如果区间宽度接近0.2以上说明样本量偏小或数据噪声较大这个r值并不能支持你写“强相关”的结论。5.4 用回归线交叉验证线性形态皮尔逊只告诉我们关系的强度不告诉我们关系的具体斜率。想回答“x每增加一个单位y平均增加多少”需要用线性回归。scipy自带linregress一行就能给出斜率、截距和R²。res stats.linregress(df_clean[x], df_clean[y]) print(f斜率 {res.slope:.3f}, 截距 {res.intercept:.3f}, R² {res.rvalue**2:.3f}) xs np.linspace(df_clean[x].min(), df_clean[x].max(), 100) ax.plot(xs, res.intercept res.slope * xs, colorcrimson, linewidth2) plt.show()回归线的存在不是为了预测而是为了检验散点图是否真的围绕一条直线波动。如果点云呈现出弯曲的趋势回归线就会坐在那些点中间“硬扛”这时你就要意识到皮尔逊r低估了真实关系或者问错了问题。6. 变量不是直线关系时怎么办秩相关与非线性度量6.1 Spearman把排名当数据当业务关系明显是单调的但不一定是严格直线时SpSpearman秩相关系数是更好的选择。它的原理很简单不把原始值当数值而是把x和y各自转换成排名然后对排名做皮尔逊相关。因为只关心排序它不要求线性、不要求数据正态分布对极端值的敏感度也低很多。举个例子产品价格和销量之间的关系通常是单调递减但不是线性递减。前期的价格下降可能带来明显的销量增长到后期降价却没什么效果。这种曲线关系用皮尔逊r会被低估用Spearman则能更准确地反映“价格越高、销量越低的整体趋势”。Python里计算也相当方便rho, p_rho stats.spearmanr(df_clean[x], df_clean[y]) print(fSpearman rho {rho:.3f}, p {p_rho:.3e})6.2 Kendall tau善于处理小样本和打结数据Kendall的tau与Spearman思路不同它看的是所有样本对的“一致对”和“不一致对”。如果一对数据里x的排名和y的排名同时变大就称为一致对如果一个变大另一个变小就是不一致对。tau就等于一致对数量减去不一致对数量再除以总对数。这个方法对数据中的“并列排名”处理更稳健样本量较小时表现也不错。缺点是它的表达能力稍微保守一点数值通常比皮尔逊和Spearman小但不影响排序和比较。tau, p_tau stats.kendalltau(df_clean[x], df_clean[y]) print(fKendall tau {tau:.3f}, p {p_tau:.3e})6.3 三种相关系数怎么选用我的经验画一张简表方便你直接在项目里选型场景推荐指标理由两个连续变量散点图呈直线趋势皮尔逊r利用原始数值的全部信息估计精度高关系单调但不线性或存在有序类别Spearman只看排名容忍非线性单调关系样本量小、并列排名多想要稳健结论Kendall tau用序对关系刻画异常值影响更小关系是非单调的U型或倒U型以上都不适用需要拟合曲线或使用互信息需要特别提醒的是Spearman对U型关系同样无效。U型关系是一种“非单调”的关系排名在中段先降后升不会形成一致的单调趋势秩相关算出来依然接近0。所以别以为换一个排名版指标就能解决所有问题。6.4 更进一步的非线性关系度量如果你面对的根本不是单调关系问题就不是“选哪个相关系数”而是“要不要用非线性方法”。一类方向是做曲线拟合比如多项式回归、样条回归看拟合优度R²能到多少另一类方向是计算互信息mutual information它不假设任何函数形式能捕捉一般性的非线性依赖。sklearn里提供了现成的接口from sklearn.feature_selection import mutual_info_regression mi mutual_info_regression(df_clean[[x]], df_clean[y], random_state42) print(f互信息 {mi[0]:.3f})互信息的值不是-1到1它是一个大于等于0的绝对量适合用来衡量“有没有依赖”而不是“正相关还是负相关”。想要知道方向还是得回到散点图。最后再分享一个我自己的习惯每拿到一列新的数据我都会先做五件事——看缺失、看分布、画散点、算三类相关系数、检查异常点是“真业务”还是“录入错”。这个流程看上去笨但能挡掉大部分因为急着算r而踩到的坑。线性相关关系是数据分析里最常用的工具也是最容易被误用的工具。它的价值不在那个好看的数字本身而在你能不能用散点图、业务逻辑和必要的稳健性检验让那个数字经得起追问。
返回列表