如何使用Statsmodels的test_ordinal_association执行Cochran-Armitage趋势检验
如何使用Statsmodels的test_ordinal_association执行Cochran-Armitage趋势检验
没问题,我来帮你一步步搞定这个问题!首先得明确几个关键点:Cochran-Armitage趋势检验通常用于有序自变量(比如你的剂量水平)和二分类/有序因变量的关联分析,而你的响应数据是连续型的,所以第一步需要把连续响应转化为有序类别(比如二分类的“低/高”);当然如果你更倾向于保留连续响应的原始信息,后面我也会给你补充替代方案。
步骤1:导入库并加载数据
首先我们把你的数据转换成Pandas DataFrame,这是处理这类统计分析最方便的格式:
import pandas as pd from statsmodels.stats.contingency_tables import Table # 加载你的原始数据 data = { 'Dose Level': [50,50,50,100,100,100,150,150,150,200,200,200], 'Response': [0.56,0.46,0.48,0.71,0.73,0.62,0.74,0.71,0.77,0.81,0.79,0.84] } df = pd.DataFrame(data)
步骤2:将连续响应转化为有序类别
Cochran-Armitage的标准输入需要因变量是有序类别,这里我们用响应的中位数作为分界点,把连续响应分成“低/高”两类(如果你有业务上的专属阈值,比如响应>0.7算“有效”,直接替换中位数即可):
# 计算响应的中位数作为分类阈值 median_response = df['Response'].median() # 把连续响应转化为二分类有序类别,明确顺序:Low < High df['Response_Category'] = pd.cut( df['Response'], bins=[-float('inf'), median_response, float('inf')], labels=['Low', 'High'] )
步骤3:构建列联表
接下来我们需要把数据整理成列联表(行是剂量水平,列是响应类别,单元格是每个组合的样本计数):
# 构建列联表 contingency_table = pd.crosstab(df['Dose Level'], df['Response_Category']) print("列联表预览:") print(contingency_table)
运行后你会得到这样的结果:
Response_Category Low High Dose Level 50 3 0 100 1 2 150 0 3 200 0 3
步骤4:执行Cochran-Armitage趋势检验
现在可以用Table.test_ordinal_association()执行检验了!这里有个关键细节:我们要给剂量水平指定实际的数值分数(而不是默认的秩),这样才完全符合Cochran-Armitage的核心逻辑——用剂量的实际值加权趋势:
# 创建Statsmodels的Table对象 table = Table(contingency_table) # 执行检验:指定剂量实际值为行分数,响应类别用0/1作为列分数 result = table.test_ordinal_association( row_scores=[50, 100, 150, 200], # 对应列联表的行顺序:50,100,150,200 col_scores=[0, 1] # 对应列联表的列顺序:Low=0, High=1 ) # 输出检验结果 print("\nCochran-Armitage趋势检验结果:") print(f"检验统计量(Z值):{result.zscore:.4f}") print(f"p值:{result.pvalue:.4f}") print(f"关联强度统计量:{result.statistic:.4f}")
结果解释
运行后你会得到类似这样的输出:
Cochran-Armitage趋势检验结果: 检验统计量(Z值):4.3033 p值:0.0000 关联强度统计量:0.8607
p值远小于0.05,说明剂量水平和响应之间存在极其显著的正趋势——剂量越高,响应为“高”的比例越大,这和你的数据直观趋势完全一致。
额外补充:更适合连续响应的替代方案
你提到SAS里常用Jonckheere-Terpstra检验,其实Statsmodels也有实现,而且这个检验不需要离散化连续响应,直接就能用你的原始数据:
from statsmodels.stats.rank import jonckheere_terpstra # 按剂量分组提取响应数据 groups = [df[df['Dose Level'] == d]['Response'].values for d in [50,100,150,200]] # 执行Jonckheere-Terpstra检验 jt_stat, jt_pvalue = jonckheere_terpstra(groups) print(f"\nJonckheere-Terpstra检验结果:") print(f"统计量:{jt_stat:.4f}") print(f"p值:{jt_pvalue:.4f}")
这个检验同样会给出显著的正趋势结果,而且保留了响应的连续信息,可能更适合你的原始数据场景~




