第35步 机器学习实战DLC:不平衡数据处理(下)

失踪人口回归的第二期,继续说一说用PSM处理不平衡数据。

一、啥叫PSM

PSM全称为Propensity Score Matching,翻译过来就是倾向匹配得分,为了省流,让小Chart介绍一下:

第35步 机器学习实战DLC:不平衡数据处理(下)_第1张图片

放到我们的数据就是:根据某个特征,从对类别0的1671例中挑出一部分来跟类别1来匹配,形成新的数据集,然后建模。其实就是多变少的策略。

可以1:1、1:2、1:3等进行匹配,没啥固定说哪种比例好,慢慢试吧。

多说一句,PSM需要指定匹配的一个或者多个自变量(特征),一般来说,选取人口学特征,比如年龄、性别、民族啥的。也可以根据专业实际情况选别的,反正有个说法即可。

下面来操作:

二、SPSS实现1:1的PSM匹配

高能预警:SPSS22及以上自带1:1的PSM,对于其他版本或者想要体验完整版功能,就要安装相应的软件(R、SPSS R插件、PS matching插件)。据说,超级难装。

说实话,我也是第一次用,然后我看了看我的SPSS版本,哭了:

第35步 机器学习实战DLC:不平衡数据处理(下)_第2张图片

 没办法,默默装了一个:

第35步 机器学习实战DLC:不平衡数据处理(下)_第3张图片

 

(1)数据导入:

照着点:文件→导入数据→CSV数据:

第35步 机器学习实战DLC:不平衡数据处理(下)_第4张图片

 第35步 机器学习实战DLC:不平衡数据处理(下)_第5张图片

(2)倾向性评分匹配

照着点:数据→倾向得分匹配→打开对话框:

第35步 机器学习实战DLC:不平衡数据处理(下)_第6张图片

组指示符:将因变量(outcome)放入;

预测变量:需要匹配的变量放进去,我这就一个,你们也可以放多个;

倾向变量随便起一个名字:JET;

匹配容差,也叫卡钳值,用来设置倾向性评分匹配标准,卡钳值设置的越小,匹配后可比性越好,卡钳值太小会导致匹配难度会加大,我们先设0.02;

个案 ID填入样本的ID,也就是排序的序号;

匹配ID变量名:随便起一个名字,用来明确匹配成功的样本ID;

输出数据集名称:把匹配的观测对象单独输出一个数据集。

第35步 机器学习实战DLC:不平衡数据处理(下)_第7张图片

 

(3)额外的设置

点击右上角的选项按钮,弹出对话框:

第35步 机器学习实战DLC:不平衡数据处理(下)_第8张图片

合格个案数变量:新生成一列,用来明确实验组中某一个观测对象,在对照组中有多少个观测对象满足与其匹配的条件;

抽样:不放回抽样,顾名思义;

优先考虑精确匹配优先找实验组和对照组的JET值(倾向变量)一样的;

最优化执行性能:综合考虑精确匹配和基于设定的卡钳值范围内匹配的模糊匹配;

抽取匹配项时随机排列个案顺序:如果对照组有多个满足匹配条件的观测对象,就会随机将其与实验组观测对象匹配。注意是随机,所以为了能重复,需要设置我们熟悉的随机种子数,比如66666。

(4)看结果

(a)点击确定以后,会生成一个新的数据集(JET_M),重点看新变量:

JET_case代表对照组中有几个符合匹配条件的观测对象(等于4,说明有4个对照组观测对象符合匹配条件);

JET是算出的倾向性评分;

Jet_id代表匹配成功的ID号。

第35步 机器学习实战DLC:不平衡数据处理(下)_第9张图片

(b)看看输出窗口的结果:

第35步 机器学习实战DLC:不平衡数据处理(下)_第10张图片

 全是模糊匹配,一共152对;

(c)匹配后的数据库整理输出:

首先,把配对成功的数据撸出来:

记得是打开新的数据集(JET_M),照着点:数据→选择个案→打开新窗口:

第35步 机器学习实战DLC:不平衡数据处理(下)_第11张图片

设定条件,JET_id要大于等于1,筛选出匹配成功的对子;

挑选出来的在生成新的数据集,叫做JET_M_NEW;

记得左边选择ID:

第35步 机器学习实战DLC:不平衡数据处理(下)_第12张图片

点击确定后,生成新的数据框JET_M_NEW:

第35步 机器学习实战DLC:不平衡数据处理(下)_第13张图片

然后导出数据成scv文件,转到python试试性能。

(5)Xgboost建模

无脑套代码:

#加载相关包

import xgboost as xgb

from xgboost import plot_importance

import numpy as np

import matplotlib.pyplot as plt

import pandas as pd

from sklearn.feature_selection import SelectFromModel

from xgboost import plot_importance

import math

#导入数据

dataset = pd.read_csv('wwd3.csv')

dataset = dataset.fillna(dataset.median())

X = dataset.iloc[:,1:16].values

y = dataset.iloc[:,0].values

#数据拆分成训练集、测试集

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.30, random_state = 6588)   

#数据归一化

#from sklearn.preprocessing import StandardScaler

#sc = StandardScaler()

#X_train = sc.fit_transform(X_train)

#X_test = sc.transform(X_test)

#模型构建

boost = xgb.XGBClassifier(

                          n_estimators=200,

                          max_depth=9,

                          min_child_weight=3,

                          subsample=0.9,

                          colsample_bytree=0.9,

                          scale_pos_weight=1,

                          gamma=0.1,

                          reg_alpha=7,

                          )

boost.fit(X_train, y_train)

然后悲剧了:

第35步 机器学习实战DLC:不平衡数据处理(下)_第14张图片

 显示的是格式问题,不是所有数据都是数值型,所以我们怎么看数据的每一列都是什么类型呢?无脑问小Chat即可:

第35步 机器学习实战DLC:不平衡数据处理(下)_第15张图片

 我们试一下:

第35步 机器学习实战DLC:不平衡数据处理(下)_第16张图片

 果然,一堆的“object”类型。所以需要把“object”全部改成“float64”,怎么搞,继续问小Chat:

第35步 机器学习实战DLC:不平衡数据处理(下)_第17张图片

 复制TA提供的2行代码即可,其他不变:

#导入数据

dataset = pd.read_csv('wwd3.csv')

# 将所有能够转换为数字的object类型转换为float64类型

dataset = dataset.apply(pd.to_numeric, errors='coerce')

# 将剩余的object类型转换为float64类型

dataset = dataset.astype('float64')

dataset = dataset.fillna(dataset.median())

X = dataset.iloc[:,1:16].values

y = dataset.iloc[:,0].values

看看结果:

第35步 机器学习实战DLC:不平衡数据处理(下)_第18张图片

 灵敏度升高了,特异度下降了,至少没那么割裂,不过还有改进空间。毕竟样本量少了那么多,所以还得试试1:n的匹配。

三、R实现1:n的PSM匹配

说实话,我也不知道怎么做。

但是有GPT,问题不大。首先,需要写一个咒语,说清楚我们的需求:

我有一批{数据},数据包括1个因变量“outcome”和38个自变量。我希望通过R进行1:3的倾向性评分匹配,使得“outcome=1”和“outcome=0”的两组的自变量“Age”不存在显著性差异。并且整理和输出进行匹配后的数据,数据格式与{数据}一致,保存为“psm.csv”。请写出R的代码。

数据格式如下,仅列出前5行数据:

{复制你的数据,表头和前4行}

第35步 机器学习实战DLC:不平衡数据处理(下)_第19张图片

 然后就给了完整代码:

# 安装并加载所需的R包

if (!require(MatchIt)) install.packages('MatchIt')

library(MatchIt)

# 加载数据

data <- read.csv('wwd3.csv', sep = '\t')

# 使用中位数填充缺失值

for (column_name in colnames(data)) {

  median_value <- median(data[[column_name]], na.rm = TRUE)

  data[[column_name]] <- ifelse(is.na(data[[column_name]]), median_value, data[[column_name]])

}

# 提取自变量和因变量

X_columns <- colnames(data)[-1]

y_column <- 'outcome'

# 使用逻辑回归模型进行倾向性评分计算

ps_model <- glm(outcome ~ ., data = data, family = binomial())

# 保存倾向性评分

data$propensity_score <- ps_model$fitted.values

# 1:3的倾向性评分匹配

matched <- matchit(outcome ~ propensity_score, data = data, method = "nearest", ratio = 3)

# 输出匹配后的数据

matched_data <- match.data(matched)

write.csv(matched_data, 'psm.csv', row.names = FALSE)

# 检查匹配结果

summary(matched)

跑了一下,很顺序,无报错。匹配好的数据已经自动输出:

第35步 机器学习实战DLC:不平衡数据处理(下)_第20张图片

 R的输出框也给出了匹配结果,不过有些乱码,我让GPT帮整理一下:

第35步 机器学习实战DLC:不平衡数据处理(下)_第21张图片

 

收工!后面跑分类模型大家自己弄了哈。

有了GPT,效率大大提高!

你可能感兴趣的:(《100,Steps,to,Get,ML》—JET学习笔记,机器学习,人工智能,python)