因果推断(二)倾向匹配得分(PSM)

news2024/9/24 17:20:17

因果推断(二)倾向匹配得分(PSM)

前文介绍了如何通过合成控制法构造相似的对照组,除此之外,也可以根据倾向匹配得分(PSM)进行构造,即为每一个试验组样本在对照组中找对与之相似的样本进行匹配。PSM 通过统计学模型计算每个样本的每个协变量的综合倾向性得分,再按照倾向性得分是否接近进⾏匹配。本文参考自PSM倾向得分匹配法。

⚠️注意:倾向匹配得分常用于截面数据

数据准备

# !pip install psmatching
import psmatching.match as psm
import pytest
import pandas as pd
import numpy as np
from psmatching.utilities import *
import statsmodels.api as sm

以下数据如果有需要的同学可关注公众号HsuHeinrich,回复【因果推断02】自动获取~

# 读取数据
path = "psm_data.csv"
raw_data = pd.read_csv(path)
raw_data.set_index("ID", inplace=True)
raw_data.head()

image-20230206154724976

倾向得分与匹配

  • 自定义函数
# 计算propensity
def cal_propensity(df, formula, k):
    df=df.copy()
    # 利用逻辑回归框架计算倾向得分,即广义线性估计 + 二项式Binomial
    glm_binom = sm.formula.glm(formula = formula, data = df, family = sm.families.Binomial())
    # 模型拟合
    result = glm_binom.fit()
    # 计算propensity score
    propensity_scores = result.fittedvalues
    df["PROPENSITY"] = propensity_scores
    
    return df

# 计算matched_data
def cal_matched_data(df, treatment, propensity, k):
    
    groups = df[treatment] # 干预项
    propensity = df[propensity]
    # 把干预项替换成True和False
    groups = groups == groups.unique()[1]
    n = len(groups)
    # 计算True和False的数量
    n1 = groups[groups==1].sum()
    n2 = n-n1
    g1, g2 = propensity[groups==1], propensity[groups==0]
    # 确保n2>n1,,少的匹配多的,否则交换下
    if n1 > n2:
        n1, n2, g1, g2 = n2, n1, g2, g1
        
    # 随机排序干预组,减少原始排序的影响
    np.random.seed(0)
    m_order = list(np.random.permutation(groups[groups==1].index))

    # 根据倾向评分差异将干预组与对照组进行匹配
    # 注意:caliper = None可以替换成自己想要的精度
    matches = {}
    k = int(k)
    print("\n给每个干预组匹配 [" + str(k) + "] 个对照组 ... ", end = " ")
    for m in m_order:
        # 计算所有倾向得分差异,这里用了最粗暴的绝对值
        # 将propensity[groups==1]分别拿出来,每一个都与所有的propensity[groups==0]相减
        dist = abs(g1[m]-g2)
        array = np.array(dist)
        # 如果无放回地匹配,最后会出现要选取3个匹配对象,但是只有一个候选对照组的错误,故进行判断
        if k < len(array):
            # 在array里面选择K个最小的数字,并转换成列表
            k_smallest = np.partition(array, k)[:k].tolist()
            # 用卡尺做判断
            caliper = None
            if caliper:
                caliper = float(caliper)
                # 判断k_smallest是否在定义的卡尺范围
                keep_diffs = [i for i in k_smallest if i <= caliper]
                keep_ids = np.array(dist[dist.isin(keep_diffs)].index)
            else:
                # 如果不用标尺判断,那就直接上k_smallest了
                keep_ids = np.array(dist[dist.isin(k_smallest)].index)
            #  如果keep_ids比要匹配的数量多,那随机选择下,如要少,通过补NA配平数量
            if len(keep_ids) > k:
                matches[m] = list(np.random.choice(keep_ids, k, replace=False))
            elif len(keep_ids) < k:
                while len(matches[m]) <= k:
                    matches[m].append("NA")
            else:
                matches[m] = keep_ids.tolist()
            # 判断 replace 是否放回
            replace = False
            if not replace:
                g2 = g2.drop(matches[m])
                
    # 将匹配完成的结果合并起来
    matches = pd.DataFrame.from_dict(matches, orient="index")
    matches = matches.reset_index()
    column_names = {}
    column_names["index"] = "干预组"
    for i in range(k):
        column_names[i] = str("匹配对照组_" + str(i+1))
    matches = matches.rename(columns = column_names)
    print("\n匹配完成!")
    return matches

# 变量校验
def var_val(df, treatment):
    variables = df.columns.tolist()[0:-2]
    results = {}
    print("开始评估匹配 ...")
    #注意:将PUSH替换成自己的干预项
    for var in variables:
            # 制作用于卡方检验的频率计数交叉表
        crosstable = pd.crosstab(df[treatment],df[var])
        if len(df[var].unique().tolist()) <= 2:
            # 计算 2x2 表的卡方统计量、df 和 p 值
            p_val = calc_chi2_2x2(crosstable)[1]
        else:
            # 计算 2x2 表的卡方统计量、df 和 p 值
            p_val = calc_chi2_2xC(crosstable)[1]
        results[var] = p_val
        print("\t" + var + '(' + str(p_val) + ')', end = "")
        if p_val < 0.05:
            print(": 未通过")
        else:
            print(": 通过")
    if True in [i < 0.05 for i in results.values()]:
        print("\n变量未全部通过匹配")
    else:
        print("\n变量全部通过匹配")
  • 计算得分
# 计算propensity
k=3
formu='PUSH ~ AGE + SEX + VIP_LEVEL + LASTDAY_BUY_DIFF \
        + PREFER_TYPE + LOGTIME_PREFER + USE_COUPON_BEFORE + ACTIVE_LEVEL'
df_model=cal_propensity(raw_data, formu, k)
  • 匹配相似组
# 计算干预=1的匹配组
matches=cal_matched_data(df_model, 'PUSH', 'PROPENSITY', 3)
给每个干预组匹配 [3] 个对照组 ...  
匹配完成!
# 提取全部干预与倾向匹配数据
# 这里直接调用get_matched_data,注意输入的matches是匹配结果,raw_data是全部数据
matched_data = get_matched_data(matches, raw_data)
  • 变量校验
# 变量校验
var_val(df_model, 'PUSH')
开始评估匹配 ...
	AGE(0.9904): 通过
	SEX(0.6688): 通过
	VIP_LEVEL(0.0089): 未通过
	LASTDAY_BUY_DIFF(0.5134): 通过
	PREFER_TYPE(0.7107): 通过
	LOGTIME_PREFER(0.2442): 通过
	USE_COUPON_BEFORE(0.2961): 通过
	ACTIVE_LEVEL(0.7934): 通过

变量未全部通过匹配

总结

如果产品告诉你,我们发现使用A功能的用户比没有使用A功能的用户留存率提高了30%。如果你持有怀疑态度,就可以尝试通过PSM为每一个实验样本与之相似的样本,构造出相似的对照组后发现差异并没有很多(例如只有10%),你就可以理直气壮的驳斥他们了。

共勉~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/822926.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

dialog => :before-close的属性应用

在element-ui里面关闭弹窗的时候before-close会触发。 也就是点击X的时候回触发before-close这个属性, 代码实例: <el-dialogtitle"新增用户":visible.sync"dialogVisible"width"50%":before-close"handleClose"> handleClose…

【动态规划part15】| 392.判断子序列、115.不同的子序列

&#x1f388;LeetCode392.判断子序列 链接&#xff1a;392.判断子序列 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;…

Linux端口与netstat使用

端口是设备与外界交流的通道&#xff0c;有物理端口和虚拟端口。 Linux有六万多端口&#xff0c;可以分为下面几类&#xff1a; 1.公认端口&#xff08;1~1023&#xff09;&#xff1a;用于系统内置与知名程序的预留使用 2.注册端口&#xff08;1024~49151&#xff09;&…

使用webdriver-manager解决浏览器与驱动不匹配所带来自动化无法执行的问题

1、前言 在我们使用 Selenium 进行 UI 自动化测试时&#xff0c;常常会因为浏览器驱动与浏览器版本不匹配&#xff0c;而导致自动化测试无法执行&#xff0c;需要手动去下载对应的驱动版本&#xff0c;并替换原有的驱动&#xff0c;可能还会遇到跨操作系统进行测试的时候&…

【autoresizing案例 Objective-C语言】

一、autoresizing案例 1.在介绍autoresizing之前,告诉大家,这个只是介绍,以后不要用这个东西,都用autolayout 还有一个非常重要的就是,使用autoresizing,就不能用autolayout,反之亦然 2.我们来看一个案例,看一个什么案例呢,看这么一个案例, 大家先看我这个的要求:…

如何安装、部署、启动Jenkins

一、测试环境 Linux系统 Centos 7 二、安装步骤&#xff1a; 1、安装jdk 我安装的是jdk8&#xff0c;此处就不多说了&#xff0c;自己百度哈&#xff0c;很简单 2、安装jenkins 首先依次执行如下三个命令&#xff1a; 2.1、导入镜像&#xff1a; [rootcentos7 ~]# sudo …

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(18)-Fiddler如何接口测试,妈妈再也不担心我不会接口测试了

1.简介 Fiddler最大的优势在于抓包&#xff0c;我们大部分使用的功能也在抓包的功能上&#xff0c;fiddler做接口测试也是非常方便的。 领导或者开发给你安排接口测试的工作任务&#xff0c;但是没有给你接口文档&#xff08;由于开发周期没有时间出接口文档&#xff09;&…

小程序商品如何上传视频

小程序商品展示的方式在不断创新&#xff0c;除了传统的图片展示&#xff0c;视频成为了吸引用户注意力的重要方式之一。今天就讲解一下&#xff0c;商家怎么上传商品视频。 1. 商家需要准备好商品视频。商家可以自己拍摄商品的使用演示视频、产品介绍视频等&#xff0c;也可以…

Linux部署jar包,隐藏命令行参数

Linux部署jar包&#xff0c;隐藏命令行参数 一、背景需求二、查阅资料三、实现隐藏库3.1、测试test.c3.2、设置隐藏库3.3、验证 四、应用jar启动命令五、直接应用结果 最新项目安全检测&#xff0c;发现配置文件中数据库密码&#xff0c;redis密码仍处理明文状态 于是整理了一篇…

做软件测试,掌握哪些技术才能算作“测试大佬”?

一、过硬的基础能力 其实所有的测试大佬都是从底层基础开始的&#xff0c;随着时间&#xff0c;经验的积累慢慢变成大佬。要想稳扎稳打在测试行业深耕&#xff0c;成为测试大牛&#xff0c;首当其冲的肯定就是拥有过硬的基础&#xff0c;所有的基础都是根基&#xff0c;后期所…

【应用层】HTTPS协议详细介绍

文章目录 前言一、什么是"加密"二、常见的加密方式三、数据摘要&#xff08;数据指纹&#xff09;四、证书总结 前言 HTTPS也是一个应用层协议&#xff0c;是在HTTP协议的基础上引入了一个加密层&#xff0c;由于HTTP协议内容都是按照文本的方式明文传输的&#xff…

【外卖系统】修改菜品

需求分析 在菜品管理列表页面点击修改按钮&#xff0c;跳转到修改页面&#xff0c;在修改页面回显菜品相关信息并进行修改&#xff0c;在最后点击确定按钮完成修改操作 代码设计 页面发送ajax请求&#xff0c;请求服务端获取分类数据&#xff0c;用于菜品分类下拉框中数据显…

【Unity学习笔记】对象池

文章目录 设计思路总体设计从生命周期考虑 一些代码 对象池这个东西老生常谈了&#xff0c;使用它的好处在于&#xff1a;当我们需要重复创建或者销毁一些物体&#xff0c;例如限制子弹数量上限为10发&#xff0c;当射出第11发就需要使第10发消失&#xff0c;第11出现。销毁10号…

vue中人员导出功能实现

大纲&#xff1a; 1、导出定义的export.js文件 代码展示 import axios from axios //导出一 export const exportExcel (url, params, name, type post) > {// url url路径 params 查询参数 name 文件名 type 请求方式axios[type](url, params, {responseType: blob,}).t…

微信小程序多码融合

1、多码融合实现 如果需要实现扫码关注、跳转页面、扫码充电以及第三方融合扫码充电的需求&#xff0c;通过“扫普通链接二维码打开小程序” 的功能采用hlht协议的方式进行融合&#xff0c;使用代码生成新的二维码&#xff0c;二维码内容格式如下&#xff1a; hlht://9900000…

性能测试基础知识(三)性能指标

性能测试基础知识&#xff08;三&#xff09;性能指标 前言一、时间特性1、响应时间2、并发数3、吞吐量&#xff08;TPS&#xff09; 二、资源特性1、CPU利用率2、内存利用率3、I/O利用率4、网络带宽使用率5、网络传输速率&#xff08;MB/s&#xff09; 三、实例场景 前言 性能…

ES6系列之let、const、箭头函数使用的坑

变量提升块级作用域的重要性箭头函数this的指向rest参数和arguments 1.ECMAScript与Js的关系 2.Babel转码器 Babel是一个广泛使用的ES6转码器&#xff0c;可以将ES6代码转为ES5代码&#xff0c;从而在老版本的浏览器执行。这意味着&#xff0c;你可以用ES6的方式编写程序&…

MyBatis的使用方法

文章目录 一、MyBatis的创建准备工作 二、MyBatis的使用1.项目分层2.业务代码1&#xff09;使用XML的方法2&#xff09;直接使用注解 总结 一、MyBatis的创建 准备工作 1.添加依赖 旧项目 方法一&#xff1a;在pom.xml中添加MyBatis和MySQL Diver依赖 <!-- 添加 MyBati…

QC API全系列揭秘之Test Execution操作(全网首发)

目录 一、QC简介&#xff1a; 二、写作目的&#xff1a; 三、解决问题&#xff1a; 四、本文重点&#xff1a; 五、QC接口规范&#xff1a; 六、QC接口操作Test Execution&#xff1a; 定义全局变量 QC服务器连接、登录&#xff08;身份验证&#xff09;及项目连接 重点…

小程序商城系统的开发方式及优缺点分析

小程序商城系统是一种新型的电子商务平台&#xff0c;它通过小程序的形式为商家提供了一种全新的销售渠道&#xff0c;同时也为消费者提供了一种便捷的购物体验。小程序商城系统具有低成本、快速上线、易于维护等特点&#xff0c;因此在市场上受到了广泛的关注和应用。这里就小…