SPSS与Python的Kolmogorov-Smirnov正态性检验结果差异问询
SPSS与Python的Kolmogorov-Smirnov正态性检验结果差异原因及解决方法
问题背景
现有如下数据集:
age;height 8;120 8;123 8;130 8;125 10;160 9;158 8;120 7;126 6;98 5;97 7;115 7;120 7;118 8;117 6;97 6;99 9;123 10;157 10;155 9;155 9;153 5;96 7;115 6;94 6;94 5;87 8;117 6;96 5;97 6;91 6;88 9;149 6;94 8;117 10;156 10;160 6;90 6;90 7;116 5;89 6;90 7;118 10;162
使用SPSS进行KS正态性检验,输出结果如下:
| variables | statistics | sig |
|---|---|---|
| age | 0.190 | 0.000 |
| height | 0.173 | 0.002 |
但用Python编写的代码得到的结果与SPSS差异极大:
import pandas as pd from scipy.stats import kstest from scipy.stats import norm # 注意:此处列名写错,原数据集第二列是height,不是weight data = pd.DataFrame([[8, 120], [8, 123], [8, 130], [8, 125], [10, 160], [9, 158], [8, 120], [7, 126], [6, 98], [5, 97], [7, 115], [7, 120], [7, 118], [8, 117], [6, 97], [6, 99], [9, 123], [10, 157], [10, 155], [9, 155], [9, 153], [5, 96], [7, 115], [6, 94], [6, 94], [5, 87], [8, 117], [6, 96], [5, 97], [6, 91], [6, 88], [9, 149], [6, 94], [8, 117], [10, 156], [10, 160], [6, 90], [6, 90], [7, 116], [5, 89], [6, 90], [7, 118], [10, 162]], columns=['age', 'weight']) x = np.log(data.age) n = norm(loc=0,scale=1) kstest(x, n.cdf)
运行结果:
KstestResult(statistic=0.9462396895483368, pvalue=5.139087762288979e-55)
即使不对数据做对数变换,结果仍差异显著:
kstest(data.age, n.cdf)
结果:
KstestResult(statistic=0.9999997133484281, pvalue=9.27397852188504e-282)
差异原因
检验类型与参数估计逻辑不同
SPSS中用于正态性检验的KS检验是Lilliefors修正版:它会先从样本数据中估计正态分布的均值和标准差,再用这些样本统计量作为总体参数进行检验,同时对p值做修正以适应“用样本估计参数”的情况。
而你在Python中直接指定了标准正态分布norm(loc=0, scale=1),这是检验数据是否服从已知参数的标准正态分布,和你的样本数据(age均值≈7.4,标准差≈1.8)完全不匹配,自然结果离谱。多余的数据变换
你对age做了对数变换,但SPSS检验的是原始数据的正态性,这也导致了结果的额外差异。列名错误
代码中将第二列命名为weight,但原数据集是height,虽不影响age的检验,但属于细节错误。
解决方法:在Python中得到与SPSS一致的结果
要匹配SPSS的逻辑,需要:
- 用样本的均值和标准差构建正态分布,而不是标准正态;
- 若需要完全一致的p值,需使用支持Lilliefors修正的工具(如
statsmodels)。
方法1:使用scipy的kstest(统计量接近SPSS,p值未修正)
import pandas as pd import numpy as np from scipy.stats import kstest, norm # 加载正确的数据 data = pd.DataFrame([[8, 120], [8, 123], [8, 130], [8, 125], [10, 160], [9, 158], [8, 120], [7, 126], [6, 98], [5, 97], [7, 115], [7, 120], [7, 118], [8, 117], [6, 97], [6, 99], [9, 123], [10, 157], [10, 155], [9, 155], [9, 153], [5, 96], [7, 115], [6, 94], [6, 94], [5, 87], [8, 117], [6, 96], [5, 97], [6, 91], [6, 88], [9, 149], [6, 94], [8, 117], [10, 156], [10, 160], [6, 90], [6, 90], [7, 116], [5, 89], [6, 90], [7, 118], [10, 162]], columns=['age', 'height']) # 对age进行检验:用样本均值和标准差构建正态分布(SPSS用总体标准差,ddof=0) age_mean = data['age'].mean() age_std = data['age'].std(ddof=0) kstest_age = kstest(data['age'], norm(loc=age_mean, scale=age_std).cdf) print(f"age的KS检验结果:统计量={kstest_age.statistic:.3f}, p值={kstest_age.pvalue:.3f}") # 对height进行检验 height_mean = data['height'].mean() height_std = data['height'].std(ddof=0) kstest_height = kstest(data['height'], norm(loc=height_mean, scale=height_std).cdf) print(f"height的KS检验结果:统计量={kstest_height.statistic:.3f}, p值={kstest_height.pvalue:.3f}")
运行后age的统计量会接近SPSS的0.190,p值因未做Lilliefors修正会略有差异,但趋势一致。
方法2:使用statsmodels的Lilliefors检验(完全匹配SPSS逻辑)
statsmodels中的lilliefors函数直接实现了修正后的KS正态性检验,结果与SPSS高度一致:
import pandas as pd from statsmodels.stats.diagnostic import lilliefors data = pd.DataFrame([[8, 120], [8, 123], [8, 130], [8, 125], [10, 160], [9, 158], [8, 120], [7, 126], [6, 98], [5, 97], [7, 115], [7, 120], [7, 118], [8, 117], [6, 97], [6, 99], [9, 123], [10, 157], [10, 155], [9, 155], [9, 153], [5, 96], [7, 115], [6, 94], [6, 94], [5, 87], [8, 117], [6, 96], [5, 97], [6, 91], [6, 88], [9, 149], [6, 94], [8, 117], [10, 156], [10, 160], [6, 90], [6, 90], [7, 116], [5, 89], [6, 90], [7, 118], [10, 162]], columns=['age', 'height']) # 检验age的正态性 lf_age = lilliefors(data['age'], dist='norm') print(f"age的Lilliefors检验结果:统计量={lf_age[0]:.3f}, p值={lf_age[1]:.3f}") # 检验height的正态性 lf_height = lilliefors(data['height'], dist='norm') print(f"height的Lilliefors检验结果:统计量={lf_height[0]:.3f}, p值={lf_height[1]:.3f}")
运行后结果会和SPSS的输出几乎完全一致,统计量和p值都匹配。
内容的提问来源于stack exchange,提问作者fffff
相关产品推荐
相关产品推荐

