京公网安备 11010802034615号
经营许可证编号:京B2-20210330
使用R进行倾向得分匹配(PSM)
根据维基百科,倾向得分匹配(PSM)是一种用来评估处置效应的统计方法。广义说来,它将样本根据其特性分类,而不同类样本间的差异就可以看作处置效应的无偏估计。因此,PSM不仅仅是随机试验的一种替代方法,它也是流行病研究中进行样本比较的重要方法之一。让我们举个栗子:
与健康相关的生活质量(HRQOL)被认为是癌症治疗的重要结果之一。对癌症患者而言,最常用的HRQOL测度是通过欧洲癌症研究与治疗中心的调查问卷计算得出的。EORTC QLD-C30是一个由30个项目组成,包括5个功能量表,9个症状量表和一个全球生活质量量表的的问卷。所有量表都会给出一个0-100之间的得分。症状量表得分越高代表被调查人生活压力越大,其余两个量表得分越高代表生活质量越高。
然而,如果没有任何参照,直接对数据进行解释是很困难的。幸运的是,EORTC QLQ-C30问卷也在一些一般人群调查中使用,我们可以对比患者的得分和一般人群的得分差异,从而判断患者的负担症状和一些功能障碍是否能归因于癌症治疗。PSM在这里可以以年龄和性别等特征,将相似的患者和一般人群进行匹配。
生成两个随机数据框
由于我不希望在本文使用真实数据,我需要生成一些仿真数据。使用Wakefield包可以很容易地实现这个功能。
第一步,我们创建一个名为df.patients的数据框,我希望它包含250个病人的年龄和性别数据,所有病人的年龄都要在30-78岁之间,并且70%的病人被设定为男性。
set.seed(1234)
df.patients <- r_data_frame(n = 250,
age(x = 30:78,
name = 'Age'),
sex(x = c("Male", "Female"),
prob = c(0.70, 0.30),
name = "Sex"))
df.patients$Sample <- as.factor('Patients')
summary函数会返回创建的数据框的基本信息,如你所见,患者平均年龄为53.7岁,并且大约70%为男性。
summary(df.patients)
## Age Sex Sample
## Min. :30.00 Male :173 Patients:250
## 1st Qu.:42.00 Female: 77
## Median :54.00
## Mean :53.71
## 3rd Qu.:66.00
## Max. :78.00
第二步,我们需要创建另一个名为df.population的数据框。我希望这个数据集的数据和患者的有些不同,因此正常人群的年龄区间被设定为18-80岁,并且男女各占一半。
set.seed(1234)
df.population <- r_data_frame(n = 1000,
age(x = 18:80,
name = 'Age'),
sex(x = c("Male", "Female"),
prob = c(0.50, 0.50),
name = "Sex"))
df.population$Sample <- as.factor('Population')
下方表格显示样本平均年龄为49.5岁,男女比例也大致相等。
summary(df.population)
## Age Sex Sample
## Min. :18.00 Male :485 Population:1000
## 1st Qu.:34.00 Female:515
## Median :50.00
## Mean :49.46
## 3rd Qu.:65.00
## Max. :80.00
合并数据框
在匹配样本之前,我们需要把两个数据框合并。先生成一个新变量Group来代表观测来自哪个全体(逻辑型变量),再添加另一个变量Distress来反应个体的痛苦程度。Distress变量是利用Wakefield包中的age函数创建的,可以发现,女性承受的痛苦级别更高。
mydata <- rbind(df.patients, df.population)
mydata$Group <- as.logical(mydata$Sample == 'Patients')
mydata$Distress <- ifelsmydata <- rbind(df.patients, df.population)
mydata$Group <- as.logical(mydata$Sample == 'Patients')
mydata$Distress <- ifelse(mydata$Sex == 'Male', age(nrow(mydata), x = 0:42, name = 'Distress'),
age(nrow(mydata), x = 15:42, name = 'Distress'))
当我们比较两类样本的年龄和性别分布时,我们可以发现明显的区别:
pacman::p_load(tableone)
table1 <- CreateTableOne(vars = c('Age', 'Sex', 'Distress'),
data = mydata,
factorVars = 'Sex',
strata = 'Sample')
table1 <- print(table1,
printToggle = FALSE,
noSpaces = TRUE)
kable(table1[,1:3],
align = 'c',
caption = 'Table 1: Comparison of unmatched samples')
更进一步,我们还发现一般人群的痛苦程度显著较高。
样本匹配
现在,我们已经完成了全部的准备工作,可以开始使用MatchIT包中的matchit函数来匹配两类样本了。函数中method=‘nearest’的设定指明了使用近邻法进行匹配。其他方法包括,次分类,优化匹配等。ratio=1意味着这是一一配对。同时也请注意Group变量需要是逻辑型变量。
set.seed(1234)
match.it <- matchit(Group ~ Age + Sex, data = mydata, method="nearest", ratio=1)
a <- summary(match.it)
为了后续工作的便利,我们将summary函数的输出赋值给名为a的变量。
在匹配万样本后,一般人群样本量所见到了和患者样本一致(250个观测)。
kable(a$nn, digits = 2, align = 'c',
caption = 'Table 2: Sample sizes')
根据输出结果,匹配后的年龄和性别分布基本一致了。
kable(a$sum.matched[c(1,2,4)], digits = 2, align = 'c',
caption = 'Table 3: Summary of balance for matched data')
倾向得分的分布可以使用MatchIt包中的plot函数进行绘制。
plot(match.it, type = 'jitter', interactive = FALSE)
输出如下:
保存匹配样本
最后,让我们把匹配好的样本保存在df.match数据框里。
df.match <- match.data(match.it)[1:ncol(mydata)]
rm(df.patients, df.population)
现在pacman::p_load(tableone)
table4 <- CreateTableOne(vars = c('Age', 'Sex', 'Distress'),
data = df.match,
factorVars = 'Sex',
strata = 'Sample')
table4 <- print(table4,
printToggle = FALSE,
noSpaces = TRUE)
kable(table4[,1:3],
align = 'c',
caption = 'Table 4: Comparison of matched samples'),我们可以对比两类人群间痛苦程度的差异是否依旧显著。
由于p值为0.222,学生t检验的结果不再显著。因此,PSM帮助我们避免犯下第一类错误。
P.S.1:本文只用的所有包可通过如下代码加载:数据分析师培训
pacman::p_load(knitr, wakefield, MatchIt, tableone, captioner)
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
CDA一级知识点汇总手册 第四章 战略与业务数据分析考点43:战略数据分析基础考点44:表格结构数据的使用考点45:输入数据和资源 ...
2026-02-22CDA一级知识点汇总手册 第三章 商业数据分析框架考点27:商业数据分析体系的核心逻辑——BSC五视角框架考点28:战略视角考点29: ...
2026-02-20CDA一级知识点汇总手册 第二章 数据分析方法考点7:基础范式的核心逻辑(本体论与流程化)考点8:分类分析(本体论核心应用)考 ...
2026-02-18第一章:数据分析思维考点1:UVCA时代的特点考点2:数据分析背后的逻辑思维方法论考点3:流程化企业的数据分析需求考点4:企业数 ...
2026-02-16在数据分析、业务决策、科学研究等领域,统计模型是连接原始数据与业务价值的核心工具——它通过对数据的规律提炼、变量关联分析 ...
2026-02-14在SQL查询实操中,SELECT * 与 SELECT 字段1, 字段2,...(指定个别字段)是最常用的两种查询方式。很多开发者在日常开发中,为了 ...
2026-02-14对CDA(Certified Data Analyst)数据分析师而言,数据分析的核心不是孤立解读单个指标数值,而是构建一套科学、完整、贴合业务 ...
2026-02-14在Power BI实操中,函数是实现数据清洗、建模计算、可视化呈现的核心工具——无论是简单的数据筛选、异常值处理,还是复杂的度量 ...
2026-02-13在互联网运营、产品迭代、用户增长等工作中,“留存率”是衡量产品核心价值、用户粘性的核心指标——而次日留存率,作为留存率体 ...
2026-02-13对CDA(Certified Data Analyst)数据分析师而言,指标是贯穿工作全流程的核心载体,更是连接原始数据与业务洞察的关键桥梁。CDA ...
2026-02-13在机器学习建模实操中,“特征选择”是提升模型性能、简化模型复杂度、解读数据逻辑的核心步骤——而随机森林(Random Forest) ...
2026-02-12在MySQL数据查询实操中,按日期分组统计是高频需求——比如统计每日用户登录量、每日订单量、每日销售额,需要按日期分组展示, ...
2026-02-12对CDA(Certified Data Analyst)数据分析师而言,描述性统计是贯穿实操全流程的核心基础,更是从“原始数据”到“初步洞察”的 ...
2026-02-12备考CDA的小伙伴,专属宠粉福利来啦! 不用拼运气抽奖,不用复杂操作,只要转发CDA真题海报到朋友圈集赞,就能免费抱走实用好礼 ...
2026-02-11在数据科学、机器学习实操中,Anaconda是必备工具——它集成了Python解释器、conda包管理器,能快速搭建独立的虚拟环境,便捷安 ...
2026-02-11在Tableau数据可视化实操中,多表连接是高频操作——无论是将“产品表”与“销量表”连接分析产品销量,还是将“用户表”与“消 ...
2026-02-11在CDA(Certified Data Analyst)数据分析师的实操体系中,统计基本概念是不可或缺的核心根基,更是连接原始数据与业务洞察的关 ...
2026-02-11在数字经济飞速发展的今天,数据已成为核心生产要素,渗透到企业运营、民生服务、科技研发等各个领域。从个人手机里的浏览记录、 ...
2026-02-10在数据分析、实验研究中,我们经常会遇到小样本配对数据的差异检验场景——比如同一组受试者用药前后的指标对比、配对分组的两组 ...
2026-02-10在结构化数据分析领域,透视分析(Pivot Analysis)是CDA(Certified Data Analyst)数据分析师最常用、最高效的核心实操方法之 ...
2026-02-10