为何SciPy的ttest_rel返回NaN的numpy ndarray而非单个NaN?
问题分析与解决:ttest_rel对比相同数据返回NaN数组而非单个NaN
问题原因
当用scipy.stats.ttest_rel对比完全相同的两组数据时,配对差值的标准差为0,导致t统计量无法计算(0除以0),因此scipy返回的t_statistic和p_value均为NaN。在部分scipy版本中,若输入为pandas Series,返回结果可能被包装成包含两个NaN的数组;更关键的是,自身数据的配对t检验没有统计意义,完全可以提前跳过这类无效计算。
修正代码
修改循环逻辑,跳过自身对比的情况,直接赋值单个np.nan:
import pandas as pd import numpy as np from scipy.stats import ttest_rel cities_nhl = pd.DataFrame({'metro': ['NewYork', 'LosAngeles', 'StLouis', 'Detroit', 'Boston', 'Baltimore'], 'total_ratio': [0.45, 0.51, 0.62, 0.43, 0.26, 0.32]}) cities_nba = pd.DataFrame({'metro': ['Boston', 'LosAngeles', 'Phoenix', 'Baltimore', 'Detroit', 'NewYork'], 'total_ratio': [0.50, 0.41, 0.34, 0.53, 0.33, 0.42]}) cities_mlb = pd.DataFrame({'metro': ['Seattle', 'Detroit', 'Boston', 'Baltimore', 'NewYork', 'LosAngeles'], 'total_ratio': [0.48, 0.27, 0.52, 0.33, 0.28, 0.67]}) cities_nfl = pd.DataFrame({'metro': ['LosAngeles', 'Atlanta', 'Detroit', 'Boston', 'NewYork', 'Baltimore'], 'total_ratio': [0.47, 0.41, 0.82, 0.13, 0.56, 0.42]}) needed_cols = ['metro', 'total_ratio'] df_dict = {'NHL': cities_nhl[needed_cols], 'NBA': cities_nba[needed_cols], 'MLB': cities_mlb[needed_cols], 'NFL': cities_nfl[needed_cols]} sports = ['NHL','NBA','MLB','NFL'] p_values_dict = {'NHL':[], 'NBA':[], 'MLB':[], 'NFL':[]} for clm1 in sports: for clm2 in sports: # 跳过自身对比,直接赋值单个NaN if clm1 == clm2: p_values_dict[clm1].append(np.nan) continue _df = pd.merge(df_dict[clm1], df_dict[clm2], how='inner', on='metro', suffixes=[f'_{clm1}', f'_{clm2}']) _pval = ttest_rel(_df[f"total_ratio_{clm1}"], _df[f"total_ratio_{clm2}"])[1] p_values_dict[clm1].append(_pval) p_values = pd.DataFrame(p_values_dict, index=sports) print(p_values)
修正后结果
运行后对角线位置会显示单个NaN,而非数组:
| NHL | NBA | MLB | NFL | |
|---|---|---|---|---|
| NHL | NaN | 0.589606 | 0.826298 | 0.384930 |
| NBA | 0.589606 | NaN | 0.779387 | 0.782173 |
| MLB | 0.826298 | 0.779387 | NaN | 0.713229 |
| NFL | 0.384930 | 0.782173 | 0.713229 | NaN |
内容的提问来源于stack exchange,提问作者Imran
相关产品推荐
相关产品推荐

