Python实现控制变量匹配抽样(对照匹配 case-control matching)

发布时间:2023年12月19日
业务场景:广告业务中,需要分析优质素材和低质素材的差异,优质素材的定义就是高消耗的素材,在总体中占比仅10%,余下的均是低质素材。假设优质素材100条,低质素材900条,希望随机抽取100条和优质素材在控制变量上匹配的低质素材,进行后续的分析。
也就是说,,需要 控制变量匹配随机抽样——在保证对照组和实验组,在控制变量上属性相同的基础上,进行随机抽样。

实现的方法:

1、SPSS中有Case-control matching(个案控制匹配)的方法可以实现该抽样,具体可参考如下文章:

SPSS:病例-对照匹配(case-control?matching)的实现过程?|?Public?Library?of?Bioinformatics

SPSS操作:搞定病例与对照的1:1匹配?-?知乎

2、用Python实现对照匹配抽样的方法,参考了这篇文章中SAS程序的思路,用Python实现。

病例对照、匹配(配对)抽样?SAS?程序(原创)?-?SAS专版?-?经管之家(原人大经济论坛)

测试数据如下:

数据表包含个案编号ID,需要匹配的变量?shcool、grade、class和age,分组变量group(1是实验组,0是对照组)。

ID

school

grade

class

name

age

group

1

AA

1

1

马莺琼

19

1

2

AA

1

1

范瑞娜

17

0

3

AA

1

1

陆艺

19

0

4

AA

1

1

韩薇婕

18

0

5

AA

1

2

黎舒

16

1

6

AA

1

2

江月菁

19

0

7

AA

1

2

詹枝静

18

0

8

AA

1

2

朱炎力

18

0

9

AA

2

1

游盛

16

1

10

AA

2

1

翁钧行

18

0

11

AA

2

1

潘策子

19

0

12

AA

2

1

姜富

19

0

13

AA

2

2

丁祥明

16

1

14

AA

2

2

柯龙

16

0

15

AA

2

2

钟永国

17

0

16

AA

2

2

卢巧

19

0

17

BB

1

1

孙俊龙

16

1

18

BB

1

1

童安伟

16

0

19

BB

1

1

沈强

16

0

20

BB

1

1

马致

20

0

21

BB

1

2

沈家康

16

1

22

BB

1

2

江弘

20

0

23

BB

1

2

阮建

18

0

24

BB

1

2

邵强

19

0

25

BB

2

1

黃巧

19

1

26

BB

2

1

罗影琦

20

0

27

BB

2

1

卓姬

16

0

28

BB

2

1

温姬娜

17

0

29

BB

2

2

庄倩

16

1

30

BB

2

2

曾悦

16

0

31

BB

2

2

汪娥莲

18

0

32

BB

2

2

欧丽茗

18

0

需求:

1)需要对数据做抽样,要求对实验组中的每一个案例,从对照组中随机抽样出school、grade、class相同,age相差不超过2岁的案例。

2)进行不放回抽样,也就是说,每一个已经被抽样出来的对照组案例,在后续的抽样中都不会再被抽到。

思路:

(1)拆分实验组和对照组的数据

(2)对实验组中的每个个案,根据school、grade、class、age匹配,找到符合条件的所有对照组个案,实现匹配

(3)从符合条件的所有对照组个案中,随机抽取一个,实现随机抽样

(4)将已抽取出来的对照组个案从对照组数据中删掉,实现不放回抽样

(5)循环处理所有的实验组个案


代码:

import?pandas?as?pd
from?random?import?choice

#?读取数据
file_path?= './抽样测试数据.xlsx'
data?=?pd.read_excel(file_path)

#?显示前几行数据
data.head()

#?将数据拆分为实验组?(group=1)?和对照组?(group=0)
experimental_group?=?data[data['group'] == 1]
control_group?=?data[data['group'] == 0]

#?定义函数,对某一个特定的实验组个案,根据school、grade、class进行匹配,并确保age相差不超过2岁,筛选符合条件的控制组个案(0到多个)
def find_matching_cases(exp_case,?control_group):  
????matching_cases?=?control_group[
        (control_group['school'] ==?exp_case['school']) &
        (control_group['grade'] ==?exp_case['grade']) &
        (control_group['class'] ==?exp_case['class']) &
        (control_group['age'].between(exp_case['age'] - 2,?exp_case['age'] + 2))
    ]
    return?matching_cases

#?列表存储已经抽取出来的控制组个案的ID,确保它不会再次被抽取
selected_control_indices?= []

#?对实验组中的每一个个案,找到一个匹配的控制组个案
matched_samples?= []
for?_,?exp_case?in?experimental_group.iterrows():
    #?调用前面的函数,筛选符合条件的控制组个案
????matching_control_cases?=?find_matching_cases(exp_case,?control_group)
    #?从符合条件的控制组个案中,移除已经抽取过的个案
????matching_control_cases?=?matching_control_cases[~matching_control_cases.index.isin(selected_control_indices)]
    if not?matching_control_cases.empty:
        #?在符合条件的控制组个案中,随机选一个出来
????????selected_control_case?=?choice(matching_control_cases.to_dict('records'))
????????matched_samples.append(selected_control_case)
        #?将抽取出的个案的ID加入列表
????????selected_control_indices.append(selected_control_case['ID'])


#?把匹配样本输出到?DataFrame?中
matched_samples_df?=?pd.DataFrame(matched_samples)

#?显示前几行数据
matched_samples_df.head()  

实际业务应用场景中,将数据源和字段名替换即可。

文章来源:https://blog.csdn.net/Sun_Weiss/article/details/135092414
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。