大家好,我是北游。
我们在做风险预测模型的时候,经常会遇到数据不平衡问题,关于什么是不平衡以及它可能导致的影响,前面已经有过一期分享,这里不赘述:预测模型小白入门:不平衡数据与处理方法。文章发布后,有网友留言说想学习具体操作方法,于是这期就专门来聊聊如何具体如何去做smote。
提示:本期会用到R软件,如果你还不会使用,请提前学习相关基础知识,这些知识在我们护理统计随笔平台上都有分享,随着现在原创文章达到了三百余篇,想要找过去的文章会不太容易,所以我们设置了一些菜单页面,可以方便去查找想要的内容,大家不妨去看看。在此之前,特意跟大家求一个关注、点赞和转发,谢谢支持!
一、SMOTE的基本介绍
SMOTE算法的底层原理:
选择少数类样本:从少数类中随机选择一个样本点,称为“种子样本”(Seed Sample)。
确定K近邻:计算该种子样本点的K个最近邻(K-Nearest Neighbors,KNN),通常使用欧氏距离来衡量。
选择近邻样本:从K个最近邻中随机选择一个样本点,称为“邻居样本”。
生成新样本:在种子样本和邻居样本之间的连线上,根据随机选择的缩放因子(在0到1之间均匀分布),生成一个新的合成样本点。
重复过程:重复上述过程,直到生成足够数量的合成样本,使得少数类的样本数量达到预期的平衡状态。
SMOTE算法的特点:
合成样本:SMOTE通过合成新样本而不是简单地复制现有样本,这有助于增加数据的多样性,减少过拟合的风险。
基于最近邻:通过考虑种子样本的K个最近邻,SMOTE能够较好地捕捉到少数类样本的局部特征。
可调整性:用户可以根据需要调整K值和合成样本的数量,以适应不同的数据集和问题。
SMOTE算法的局限性:
对噪声敏感:如果数据中存在噪声或异常值,SMOTE可能会生成质量不高的合成样本。
依赖参数选择:K值的选择可能会影响算法的效果,需要根据具体情况进行调整。
计算成本:对于大规模数据集,计算K近邻可能会带来较高的计算成本。
补充一点(个人亲测):适用于数值变量,如果是分类变量,可能某些工具就无法使用或者需要做点调整。
尽管存在一些局限性,SMOTE算法由于其简单有效性,在处理不平衡数据问题时仍然被广泛使用。此外,还有许多SMOTE的变体,如Borderline-SMOTE、SVM-SMOTE等,旨在解决原始SMOTE的一些不足。
最后,处理类别不平衡问题也不一定要做smote,rose等方法也是很棒的,大家不妨去学习下。鉴于smote比较常用,所以本期以它为例子,分享实操方法。
二、R语言实操
这里用几个我自己写的例子来分别展示下数值型变量的处理方法,以及如果既有数值又有分类,该如何处理。
1、预测变量是数值型
这个将会用到smotefamily包。在此之前,我们需要先做点预处理:不能有缺失值,不要对测试集进行平衡处理,确保自变量是数值型的。
library(tidyverse)
library(tidymodels)
library(MASS)
md1 = biopsy[,-1]
md1 = na.omit(md1) #smote不能有缺失值
str(md1)
# 分割数据集
set.seed(123)
md_split = initial_split(md1)
md_train = training(md_split)
md_test = testing(md_split)
# 查看类别比例
table(md_train$class)
这是一个分类任务的预测模型,现在正式执行smote处理:
library(DMwR2)
library(smotefamily)
#少数类别增加1倍,只能处理数值变量
list = SMOTE(md_train[,-10],md_train[,10],dup_size=1)
# 查看平衡后的类别比例
table(list$data$class)
可以看到,平衡后的类别比例相对合理了。
2、预测变量是混合类型
在护理研究领域,我们做风险预测模型时基本不会出现纳入变量全是数值的情况,如果有分类变量,在R语言体系中,是必须进行处理的(比如因子化、设置哑变量等)。在此背景下,如果是混合类型的数据(既有因子、又有数值),怎么处理呢?前面的方法能用吗?答:不行,会报错(个人亲测结果)。这里分享另一种方法。
# 导入数据,后台回复“泰坦尼克”即可获取
data = read_csv('train.csv')
# 剔除缺失值
data = na.omit(data)
# 选取几个变量,并对分类变量进行因子化
varname = colnames(data)
data = data %>% dplyr::select(Survived,Pclass,Sex,Age,SibSp,Embarked) %>%
mutate(
across(c('Survived','Pclass','Sex','Embarked'),factor)
)
str(data)
# 分割数据集
set.seed(123)
data_split = initial_split(data)
data_train = training(data_split)
data_test = testing(data_split)
# 查看类别比例
table(data_train$Survived)
str(data_train)
library(UBL)
smote_train = SmoteClassif(Survived~.,
as.data.frame(data_train),
dist = "HEOM")
table(smote_train$Survived)
这份数据源于kaggel竞赛平台,有需要的朋友可以回复关键词自动获取。
其实,不光是smote能处理这些类别不平衡问题,还有一些可能更好用的算法。且,对于smote,也有一些更为方便的方法去实现。比如说,mlr3(R语言机器学习的集大成者)、tidymodel(没那么强大,但个人很喜欢),这些框架也集成了多种类别不平衡的处理方法,可能会在后续分享,所以还没有关注公众号的朋友可以关注下哦。
另外,我们也可能会在新开的同名视频号中,以视频的形式分享更多新知识,大家不妨关注下。这期就写到这里了,我们下期再见!
主要参考来源:
Lee YW, Choi JW, Shin EH. Machine learning model for predicting malaria using clinical information. Comput Biol Med. 2021 Feb;129:104151. doi: 10.1016/j.compbiomed.2020.104151. Epub 2020 Nov 28. PMID: 33290932.
相关R包的帮助文档;
本期第一部分内容由AI参与创作。
免责声明:仅供科研学习和分享,不做商业用途,如有侵权,请联系我们删除,谢谢。
补充:护理统计随笔平台的内容现在已经非常丰富,很多方面都有涉及到,如果你觉得你没有看到往期的相关文章,不妨打开公众号的菜单页,在各级目录中查找你想要的内容。如果你在科研学习中遇到了疑问,恰好也想跟网友们交流,可以加入我们建立的“护理科研交流群”。这是一个完全自由、开放、没有套路的纯交流群。入群方式:私信发送关键词“加群”。