Python中Mann-Whitney U检验的正确配置及结果异常排查
问题描述
我有一个18335行×748列的DataFrame,想用scipy.stats执行Mann-Whitney U检验,对每一列比较leiden=0的样本与leiden≠0的样本,但不确定正确实现方式。尝试了以下代码后,发现结果DataFrame里出现了leiden列的p值,怀疑操作有误。
尝试的代码
import pandas as pd from scipy.stats import mannwhitneyu # Perform Mann-Whitney U test for leiden=0 and leiden=1 for each column results = {} for column in df.columns[1:]: # Skip the 'leiden' column group0 = df[df['leiden'] == 0][column] group1 = df[df['leiden'] == 1][column] statistic, p_value = mannwhitneyu(group0, group1, alternative='two-sided') results[column] = { 'Mann-Whitney U Statistic': statistic, 'P-Value': p_value } # Create a DataFrame from the results results_df = pd.DataFrame.from_dict(results, orient='index') # Save the results as a CSV file results_df.to_csv('mannwhitneyu_results.csv') # Display the results DataFrame print(results_df)
原始DataFrame示例
| Leiden | Alx1 | Alx17 | Arid3a |
|---|---|---|---|
| 5 | 20 | 350 | 40 |
| 0 | 50 | 500 | 50 |
| 7 | 20 | 350 | 40 |
| 0 | 40 | 50 | 50 |
| 8 | 30 | 350 | 40 |
| 0 | 70 | 500 | 50 |
当前代码输出结果
| Column | Mann-Whitney U Statistic | p value |
|---|---|---|
| Leiden | 0.0 | 0.000000e+00 |
| Alx1 | 1994937.5 | 4.87711e-205 |
| Alx17 | 18680927.0 | 1.2641e-44 |
| Arid3a | 10927.0 | 1.261841e-44 |
问题分析与修正
你的代码存在两个核心问题:
- 分组逻辑错误:当前代码是比较
leiden=0和leiden=1的样本,但需求是比较leiden=0和所有leiden≠0的样本,分组范围不符合要求。 - 列选择逻辑不可靠:用
df.columns[1:]跳过第一列,依赖leiden列是第一列的假设,一旦列顺序变动就会错误遍历到leiden列,这也是结果里出现Leiden行的原因。
修正后的代码
import pandas as pd from scipy.stats import mannwhitneyu results = {} # 显式排除leiden列,指定要检验的目标列 test_columns = [col for col in df.columns if col != 'leiden'] for column in test_columns: # 按需求正确分组:leiden=0 对比 leiden≠0 group0 = df.loc[df['leiden'] == 0, column] group_non0 = df.loc[df['leiden'] != 0, column] # 处理空组情况,避免检验报错 if len(group0) == 0 or len(group_non0) == 0: results[column] = { 'Mann-Whitney U Statistic': None, 'P-Value': None } continue statistic, p_value = mannwhitneyu(group0, group_non0, alternative='two-sided') results[column] = { 'Mann-Whitney U Statistic': statistic, 'P-Value': p_value } # 生成结果DataFrame并格式化索引 results_df = pd.DataFrame.from_dict(results, orient='index').reset_index().rename(columns={'index': 'Column'}) results_df.to_csv('mannwhitneyu_results.csv', index=False) print(results_df)
关键说明
- 精准列筛选:通过列表推导式显式排除leiden列,彻底避免结果中出现Leiden行的问题。
- 符合需求的分组:用
df['leiden'] != 0筛选所有非0组样本,匹配你最初的检验需求。 - 健壮性处理:增加空组判断,避免因某一组无样本导致检验报错,让代码更稳定。
内容的提问来源于stack exchange,提问作者pythonbeginner
相关产品推荐
相关产品推荐

