data analysis & visualization

[SMOTE] 알고리즘

통계2021. 2. 14. 16:00

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의 비율인 N100보다 작다면 케이스를 줄여라# 본 분석에는 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 번째 값과 가까운 5knn

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, ...))

}#######

 

'통계' 카테고리의 다른 글

기초통계분석  (0) 2019.07.07
감마분포 & 균일분포  (0) 2019.05.29
가설검정& 최강력검정  (0) 2019.04.25
R에서 일반화 가법모형(설명X)  (0) 2019.04.13