[SMOTE] 알고리즘
SMOTE 알고리즘은 크게 오버 샘플링, 언더 샘플링, 취합 순으로 진행된다.
[오버 샘플링]
문자형이나 범주형 자료를 KNN에 사용하기위해 숫자형으로 변경
빈도가 가장 작았던 자료의 관측치수( rare : 50 -> nT)
300 개에 대해서 관측치별로 KNN 진행 #default 옵션은 5개 분류로 진행
자료를 6배 해야하므로 KNN 5개중 랜덤하게 1개를 뽑고 I 번째 값과의 차이(difs)에 랜덤균등분포(min=0, max=1)을 뽑아서 I 번째 자료에 더하여 자료를 생성하는 작업을 6번 함.
이렇게 300개의 빈도가 가장 작았던 자료를 KNN기반으로 오버샘플링을 진행
[언더샘플링]
빈도가 제일 작은 범주를 제외한 자료를 중복을 포함하여 언더샘플링 진행
[최종 아웃풋]
아래는 참고한 R 코드다.
빈도가 낮은 경우가 많은 다범주에서 비율을 맞추기에는 다소 부적합해보인다.
data(iris)
data <- iris[, c(1, 2, 5)]
data$Species <- factor(ifelse(data$Species == "setosa","rare","common"))
## checking the class distribution of this artificial data set
table(data$Species)
50
600
## now using SMOTE to create a more "balanced problem"
newData <- SMOTE(Species ~ ., data, perc.over = 600,perc.under=100)
table(newData$Species)
"위 코드 실행 코드"
#옵션 설정
form=formula('Species ~ .');data=data;perc.over = 600; perc.under = 100;
k = 5;learner = NULL#default
#target colum을 맨 마지막으로 정렬
## target column 위치(Species의 컬럼 위치 ==3)
tgt <- which(names(data) == as.character(form[[2]]))
## 빈도가 가장 작은 범주
minCl <- levels(data[, tgt])[which.min(table(data[, tgt]))]
## 빈도가 가장 작은 범주의 행의 index
minExs <- which(data[, tgt] == minCl)
## target colum의 위치가 마지막 컬럼이 아니면 마지막으로 위치 변경
if (tgt < ncol(data)) {
cols <- 1:ncol(data)
cols[c(tgt, ncol(data))] <- cols[c(ncol(data), tgt)]
data <- data[, cols]
}#newExs <- DMwR::smote.exs(data[minExs, ], ncol(data), perc.over, k)
Idata=data[minExs, ];tgt=ncol(data);N=perc.over;k=k
# INPUTS:
#비율이 가장 작은 변수 자료를 넣어서
# data are the rare cases (the minority "class" cases)
# tgt is the name of the target variable
# N is the percentage of over-sampling to carry out;
# and k is the number of nearest neighours to use for the generation
# OUTPUTS:
# The result of the function is a (N/100)*T set of generated
# examples with rare values on the target
# 문자열이나 범주형 자료를 KNN을 사용하기위해 숫자로 변경
nomatr <- c()
# 빈도가 가장 작은 범주 table 이 n by m 이라면 NA로 된 n by m-1의 행렬 T 생성
T <- matrix(nrow=dim(Idata)[1],ncol=dim(Idata)[2]-1)
for(col in seq.int(dim(T)[2])){
if (class(Idata[,col]) %in% c('factor','character')) {
T[,col] <- as.integer(Idata[,col])
nomatr <- c(nomatr,col)
} else T[,col] <- Idata[,col]
}
# over sample의 비율인 N이 100보다 작다면 케이스를 줄여라# 본 분석에는 600이라 해당 없음
# 만약 50이였다면 N=50 (50/100)*150 150 개의 절반인 75개를 추출
if (N < 100) { # only a percentage of the T cases will be SMOTEd
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)
#6 배로 sampling하게 조절 nrow=900
nexs <- as.integer(N/100) # this is the number of artificial exs generated
# for each member of T
new <- matrix(nrow=nexs*nT,ncol=p) # the new cases
for(i in 1:nT) {
# the k NNs of case T[i,]
xd <- scale(T,T[i,],ranges) #min max scaling
for(a in nomatr){
xd[,a] <- xd[,a]==0
}
#distance
dd <- drop(xd^2 %*% rep(1, ncol(xd)))
#현재 i 번째 값과 가까운 5개 knn
kNNs <- order(dd)[2:(k+1)]
#6 배 할 것이므로
for(n in 1:nexs) {
# select randomly one of the k NNs
neig <- sample(1:k,1)
ex <- vector(length=ncol(T))
# the attribute values of the generated case
# 해당값과 샘플링한 가까운 값의 차이를 컬럼별로 계산
difs <- T[kNNs[neig],]-T[i,]
#최소가 0 최대가 1인 균등분포 1개를 곱함 - 화이트노이즈의 개념인 듯
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)]
}
}
}#새로운 데이터를 통해 900 개 생성됨
newCases <- data.frame(new)
for(a in nomatr){
newCases[,a] <- factor(newCases[,a],levels=1:nlevels(Idata[,a]),labels=levels(Idata[,a]))
}
newCases[,tgt] <- factor(rep(Idata[1,tgt],nrow(newCases)),levels=levels(Idata[,tgt]))
colnames(newCases) <- colnames(Idata)
}#return newCases
newExs=newCases
if (tgt < ncol(data)) {
newExs <- newExs[, cols]
data <- data[, cols]
}
#빈도가 제일 작았던 범주를 제외한 자료를 중복허용해서 언더셈플링 비율*아까 오버샘플링 row
selMaj <- base::sample(x=(1:NROW(data))[-minExs],
size=as.integer((perc.under/100) * nrow(newExs)), replace = TRUE)
newdataset <- rbind(data[selMaj, ], data[minExs, ], newExs)
'언더샘플링/100* 오버샘플링 관측치 수=900'
'비율이 제일 작았던 범주 관측치 수 50'
'비율이 가장 작았던 자료를 KNN기반 오버샘플링 한 자료=900'
#1850
if (is.null(learner))
return(newdataset)
else do.call(learner, list(form, newdataset, ...))
}#######