Learning R---SMOTE
来源:互联网 发布:龙门县网络问政平台 编辑:程序博客网 时间:2024/05/19 00:56
knitr::opts_chunk$set(echo = TRUE)
AIM
使用rmarkdown编辑~
主要目标学习SMOTE算法,并且利用DMwR实现该算法,用以处理类不平衡问题。
简介
该函数使用SMOTE算法处理类不平衡问题。简而言之,这个函数能够生成SMOTE算法处理之后的数据。或者,它也可以在新生成的数据集建立二分类模型,并且返回最终的模型。
函数使用方式
Code
SMOTE(form, data, perc.over = 200, k = 5, perc.under = 200,learner = NULL, ...)
参数说明
1 . form 公式,用以描述预测问题
2 . data 原始不平衡数据集
3 . perc.over 过采样比例p1=perc.over/100,一个少数类样本生成p1·n1+n1个样本
4 . 默认值为5,k 生成少数类新样本时,所采用的邻居数。即knn中的k
5 . perc.under 欠采样比例 如果p2=perc.under/100,那么生成p1·n1·p2个新样本。貌似是可重复抽样
6 . learner 默认为NULL,参数值可以是一个字符串,表示一个函数,应用于新数据集
7 . … 指定learner的一些别的参数
8 . 若配置数据集1:1,保证perc.over/100 + 1 =perc.over/100 *perv.under/100即可
Details
类不平衡问题会对许多机器学习算法产生影响。该问题的特征为每一类所占的比例不均匀。SMOTE(Chawla et. al. 2002)是解决这一问题的好方法。SMOTE的大体思想为:利用少数类样本的近邻人为的生成新样本(少数类的)。此外,多数类样本也可以使用欠采样,使得数据集更加平衡。
参数perc.over和perc.under控制过采样、欠采样的数量。perc.over 通常大于100,每一个少数类样本都会产生perc.over/100个新样本。如果perc.over小于100,则按照给定比例(perc.over/100)随机产生样本。
参数perc.under决定多数类样本最终随机抽取到新数据集的比例(perc.over/100)
举个栗子:如果少数类样本生成200个新样本,并且perc.under值为100,那么多数类样本中也会精确地抽取200个样本,组成最终的数据集。而如果perc.under值大于100,则会从多数类中抽取更多样本,样本数为少数类新生成的样本数。
参数k决定新样本产生的方式,每一个少数类的样本都会产生新样本,产生新样本的数量有perc.over决定。这些新样本由每个老样本的k个近邻产生。参数k决定邻居的数量。
该函数还可以对新样本集建立分类模型。通过参数learner确定分类模型的名称,也可以添加该模型函数的其他参数。如果参数learner的值不是NULL,那么该函数返回的值是学习模型,而不是新的平衡数据集。模型的参数第一个参数是预测公式,第二个参数是训练集。
Value
SMOTE函数由参数learner是否为NULL,返回两种不同类型的结果。learner为NULL返回新产生的数据集,否则返回指定的分类模型。
Examples
## A small example with a data set created artificially from the IRIS## datadata(iris)data <- iris[, c(1, 2, 5)]data$Species <- factor(ifelse(data$Species == "setosa","rare","common"))## checking the class distribution of this artificial data settable(data$Species)## 少数类为common,共100个样本;多数类为rare,共50个样本。## now using SMOTE to create a more "balanced problem"## 参数说明:## perc.over 过采样600/100,6倍,则少数类样本生成6*50=300个新样本,加上原来的50个样本共计350个样本## perc.under 欠采样100/100,1倍,从多数类中抽取300*1个新样本library(DMwR)newData <- SMOTE(Species ~ ., data, perc.over = 600,perc.under = 100)table(newData$Species)## Checking visually the created data## Not run:par(mfrow = c(1, 2))plot(data[, 1], data[, 2], pch = 19 + as.integer(data[, 3]),main = "Original Data")plot(newData[, 1], newData[, 2], pch = 19 + as.integer(newData[,3]),main = "SMOTE'd Data")## End(Not run)## Now an example where we obtain a model with the "balanced" dataclassTree <- SMOTE(Species ~ ., data, perc.over = 600,perc.under = 100,learner='rpartXse',se=0.5)## check the resulting classification treeclassTree## The tree with the unbalanced data set would berpartXse(Species ~ .,data,se=0.5)
源码
# SMOTE -------------------------------------------------------------------function (form, data, perc.over = 200, k = 5, perc.under = 200, learner = NULL, ...) { tgt <- which(names(data) == as.character(form[[2]])) ## 目标变量的索引,第几列 minCl <- levels(data[, tgt])[which.min(table(data[, tgt]))] ## 取出少数类名称 minExs <- which(data[, tgt] == minCl) ## 少数类的行索引 ## 如果目标变量不是最后一列,那么把目标变量换到最后一列~ ## 用写的这么麻烦吗?单独拉出来重新赋值不就行了 if (tgt < ncol(data)) { cols <- 1:ncol(data) ## 存放列的向量1:n cols[c(tgt, ncol(data))] <- cols[c(ncol(data), tgt)] data <- data[, cols] } ## 少数类生成新样本的函数,没有找到详细的函数呀 ## 看看包里是不是有这个函数 newExs <- smote.exs(data[minExs, ], ncol(data), perc.over, k) ## 再按照原数据集列的顺序调整回去 if (tgt < ncol(data)) { newExs <- newExs[, cols] data <- data[, cols] } ## 多数类可重复抽样,抽取样本数为perc.under/100*少数类新增的样本数 selMaj <- sample((1:NROW(data))[-minExs], as.integer((perc.under/100) * nrow(newExs)), replace = T) ## 合并数据集 newdataset <- rbind(data[selMaj, ], data[minExs, ], newExs) ## 如果learner参数为空,返回处理之后的数据集。否则调用指定的分类模型,返回模型结果 if (is.null(learner)) return(newdataset) else do.call(learner, list(form, newdataset, ...))}# smote.exs ---------------------------------------------------------------newExs <- smote.exs(data[minExs, ], ncol(data), perc.over,k)## 参数 data少数类样本,tgt目标变量所在列,perc.over欠采样参数,k近邻数function (data, tgt, N, k){ nomatr <- c() ## 生成一个空矩阵,行数是少数类的行数,列为原数据框列数-1 T <- matrix(nrow = dim(data)[1], ncol = dim(data)[2] - 1) ## for循环是为了将少数类样本中的字符型或者因子型变量转换为数值型 ## 遍历每一个列,如果是因子型或者字符型,转换成数值型 ## nomatr 为因子or字符型变量所在的列 for (col in seq.int(dim(T)[2])){ if (class(data[, col]) %in% c("factor", "character")) { T[, col] <- as.integer(data[, col]) nomatr <- c(nomatr, col) } else T[, col] <- data[, col] } ## 欠采样参数如果小于100,不重复简单随机抽样抽取as.integer((N / 100) * nT)个样本 if (N < 100) { nT <- NROW(T) idx <- sample(1:nT, as.integer((N / 100) * nT)) T <- T[idx,] N <- 100 } p <- dim(T)[2] nT <- dim(T)[1] ## 求每一列的值域,不包括目标变量列 ranges <- apply(T, 2, max) - apply(T, 2, min) nexs <- as.integer(N / 100) ## 生成新的矩阵,行数为 as.integer(N / 100)*nT,即perc.over/100 * 原来少数类样本的行数 ## 相当于每一个少数类样本新生成perc.over/100新样本 new <- matrix(nrow = nexs * nT, ncol = p) ## 对每一个少数类样本进行操作 ## xd是标准化之后的矩阵。标准化方法为极差标准化 ## 但是不是减去均值,而是减去指定的矩阵行数据,最后除以极差 for (i in 1:nT) { xd <- scale(T, T[i,], ranges) ## 遍历所有字符串列,判断元素是否为0,返回TRUE or FALSE 覆盖原值 ## 矩阵元素平方,行求和,drop转换成向量 for (a in nomatr) xd[, a] <- xd[, a] == 0 ## 不知道这个是干嘛的 dd <- drop(xd ^ 2 %*% rep(1, ncol(xd))) ## 排序取最近 ## order函数有小到大返回相关数字的索引 ## 取出第2小-k+1个小的索引 kNNs <- order(dd)[2:(k + 1)] ## nexs = as.integer(perc.over/100) ## 每次随机抽取 for (n in 1:nexs) { neig <- sample(1:k, 1) ex <- vector(length = ncol(T)) ## 选取一个随机确定的邻居,得到邻居和该少数类样本的差 difs <- T[kNNs[neig],] - T[i,] ## 构造出新样本,构造逻辑真奇怪,还要看下论文 new[(i - 1) * nexs + n,] <- T[i,] + runif(1) * difs for (a in nomatr) new[(i - 1) * nexs + n, a] <- c(T[kNNs[neig], a], T[i, a])[1 + round(runif(1), 0)] } } newCases <- data.frame(new) for (a in nomatr) newCases[, a] <- factor(newCases[, a], levels = 1:nlevels(data[, a]), labels = levels(data[, a])) newCases[, tgt] <- factor(rep(data[1, tgt], nrow(newCases)), levels = levels(data[, tgt])) colnames(newCases) <- colnames(data) newCases}
Ref
DMwR帮助文档
- Learning R---SMOTE
- R语言中的SMOTE算法的参数解释
- R中的数据抽样SMOTE (谢佳标老师讲课笔记)
- R语言:SMOTE - Supersampling Rare Events in R:用R对非平衡数据的处理方法
- R语言DMwR包中的SMOTE函数中perc.over和perc.under的含义。
- machine learning in R
- Learning R学习笔记
- R learning -Base Graphics
- deep learning with R
- Learning R---stringr
- Learning R---dummy
- Learning R---Rwordseg
- Learning R---dplyr
- Learning R---randomForest
- 【Deep Learning】R-CNN
- Learning R---animation
- smote算法
- Learning Time Series with R
- Hopscotch(POJ, 穷竭搜索)
- 点云 中国激光
- java 中"\u767b\u5f55\u6210\u529f"编码转成明文
- 从双十一数据看微信小程序如何助传统企业发展
- Less中的Extend
- Learning R---SMOTE
- js获取当前时间戳的方法
- 纪念无穷小微积分放飞互联网五周年
- WebStorm 2016 高级开发工具
- python可变参数详解
- 二、shell
- ThinkPHP 文件上传到阿里云OSS上
- python3.6 爬虫例子
- 使用UIAutomator在Android6.0执行,无法向手机SD卡写入内容问题的解决