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

단순선형회귀분석 중 최소제곱법에 대하여 포스팅 하려고 한다.

 

이해를 돕고자 적다보니 표현이 다소 불편 할 수도 있다. 전공자는 스킵하면 되겠다.

 

두개의 변수X와 Y의 자료가 있고 이를 통해 이들간에 선형적인 관계를 알려고 한다. 

 

이를 가장 잘 설명할 수 있는 직선은 무엇일까? 에 대한 해답 중 하나로 

 

최소제곱법이 이에 해당한다.

 

최소제곱법은 관측값과 예측값의 오차를 최소로 하는 직선을 찾는 것을 목표로 한다.

 

우선 고등학교 때 배웠던 직선의 방정식을 생각해보자.

 

$$ y=ax+b$$의 형태를 가지고 있다.

 

즉, 최소제곱법은 실제 측정된 y값과 x에 대한 a와 b로 계산된 y값의 차이가 최소가 되는 직선을 의미한다.

 

직선에 방정식으로 x값에 의해 생성된 y를 아래와 같이 표기하겠다.

$$\hat{y}$$

 

 

 

우리가 최소화 하여야 하는 것을 다시한번 정의해보자.

 

관측된 x들이 다음과 같다고 하자.

$$X=\{x_1, x_2, ... , x_n\}$$

 

그러면 이 때 관측된 다른 변수 Y는 다음과 같이 나타내보자.

$$Y=\{y_1,y_2,..., y_n\}$$

 

우리는 x의 i 시점에 대해 예측한 y값과 y의 오차 합을 최소화 하는 것이 목표이다.

이를 수식으로 나타내면 다음과 같다.

$$\hat{y_i}-y_i$$

이처럼 우리는 모형에서 최종적으로 최소화 하고자 하는 함수를 cost function이라고 하며, 연산에서 최소화 하고자 하는 함수를 loss function이라 부른다.

 

$$\sum [\hat{y_i}-y_i]$$

을 최소화 하는 것이 목표다. 

 

이를 어떻게 계산할까?

 

우리는 고등학교 때 배운 미분이라는 개념을 가지고 오려고 한다.

 

위의 값이 최소가 되는 절편과 기울기를 구하는게 목표이므로, 이를 편미분을 통해 계산하는 것이다.

 

우리가 찾으려하는 식은 다음과 같다.

$$\hat{y_i}=\beta_0+\beta_1 x_i+e$$

 

그렇다면 최소화 하고자 하는 값은 이를 편의상 다음과 같이 나타내겠다.

 

$$S=\sum{[y_i-\hat{y_i}] ^2}$$

 

절편에 대하여 편미분해보자.

$$\frac{\partial{S}}{\partial{\beta_0}}=2 \times \sum{[y_i-\beta_0-\beta_1 x_i]}[-1]=-2\sum{y_i-\beta_0-\beta_1 x_i}$$

$$\frac{\partial{S}}{\partial{\beta_0}}=0 \rightarrow -2\sum{y_i-\beta_0-\beta_1 x_i}=0 \rightarrow \sum{y_i}=\sum{\beta_0}+\sum{\beta_1 x_i} \rightarrow \sum{y_i}= n \beta_0+\sum{\beta_1 x_i}$$

 

이제 기울기에 대하여 편미분해보자.

$$\frac{\partial{S}}{\partial{\beta_1}}=2 \times \sum{[y_i-\beta_0-\beta_1 x_i]}[-x_i]=-2\sum{x_i[y_i-\beta_0-\beta_1 x_i]}$$

$$\frac{\partial{S}}{\partial{\beta_1}}=0 \rightarrow -2\sum{x_i[y_i-\beta_0-\beta_1 x_i]}=0 \rightarrow \sum{x_i y_i}=\sum{\beta_0 x_i}+\sum{\beta_1 [x_i]^2}$$

 

절편을 편미분하여 구한 수식에 다음을 곱하여보자.

$$\sum x_i$$ 

 

$$\rightarrow \sum {x_i}[n \beta_0+\sum{x_i \beta_1}]=\sum{x_i}\sum{y_i}$$

방금 구한 식을 기울기에 대하여 편미분한 수식에 서 빼보자.

 

$$\beta_1[[\sum{x_i}]^2-n \sum{x_{i}^2}]=\sum x_i \sum y_i - n\sum x_i y_i$$

 

$$\beta_1=\frac{\sum x_i \sum y_i -n \sum x_i y_i}{[[\sum{x_i}]^2 -n \sum{x_i^2}]}$$

 

$$\sum x_i=n\bar{x}$$

따라서 분모는 다음과 같이 나온다.

$$n^2 \bar{x}^2-n \sum{x_i}^2=n [n \bar{x}^2 - \sum{x_i}^2]$$

$$=n(2n \bar{x}^2 - n\bar{x}^2-\sum{x_i}^2=n[2\bar{x}\sum{x_i}-\sum{\bar{x}^2}-\sum{x_i}^2]=n\sum{[x_i-\bar{x}]}$$

 

분자는 다음과 같다.

$$\sum x_i \sum y_i -n \sum x_i y_i =[n \bar{x}][n \bar{y}] -n \sum x_i y_i$$

$$=n[n\bar{x}\bar{y} -\sum x_i y_i ]=n[2n\bar{x}\bar{y}-n\bar{x}\bar{y}-\sum x_i y_i $$

$$=n[n[\sum x_i\bar{y} +\sum y_i\bar{x}]-\sum{\bar{x}\bar{y}}-\sum x_i y_i$$

$$=n\sum[x_i-\bar{x}][y_i-\bar{y}]$$

 

따라서 기울기는 

$$\beta_1=\frac{\sum{[x_i-\beta{x}][y_i-\bar{y}]}}{\sum{[x_i-\bar{x}]}^2}=\frac{S_xy}{S_xx}$$

이를 대입해 절편을 구하면

$$\beta_0=\bar{y}-\beta_1\bar{x}$$

 

우연변동 : 일정한 수준에서 머물며 random한 노이즈를 가지는 경우를 의미

$$\hat{Y_t} \alpha +e_t$$

 

계절변동 : 주기적으로 변화를 나타내는 경우를 의미하며, 이 주기는 f에 의해 조절 됨

$$\hat{Y_t}=\alpha +\beta_1 \sin \frac{2\pi t}{f}+\beta_2 \cos \frac{2\pi t}{f}+e_t [ f는 주기]$$

 

추세변동 : 시간에 따라 증가하거나 감소하는 경향을 보이는 시계열 자료의 형태

$$\hat{Y_t}=T_t+e_t$$

$$\hat{Y_t}=\alpha+\beta t+e_t$$

$$\hat{Y_t}=\alpha+\beta_1 t+\beta_2 t +e_t$$

 

순환변동 : 1년 이상의 장기적인 계절성을 띄는 시계열 자료의 형태

$$\hat{Y_t}=C_t+e_t$$

 

1차 차분

$$ \nabla Y_t=Y_t -Y_{t-1}$$

 

2차 차분

$$ \nabla^2 Y_t= \nabla y_t - \nabla y_{t-1}$$

 

계절변동차분

$$\nabla_{12} Y_t=\nabla Y_t - \nabla Y_{t-12}$$

 

Box Cox 변환 : 독립성과 등분산성을 동시에 만족시키기 위해 고안된 방법. 시계열 자료의 변환에 자주 사용됨.

 

$$f(x:\lambda) = \frac{x^\lambda -1}{\lambda} [ \lambda \ne 0]$$

$$f(x:0)=log(x) [\lambda=0]$$

 

 

 

 

 

 

'통계 > time series' 카테고리의 다른 글

조금 더 빠른 시계열 예측  (0) 2020.06.08

시계열 예측 관련 공부를 하며 walking forward validation을 사용하는 경우가 발생하게 되었는데, 기존 데이터가 너무 커서 시간이 너무 오래걸리는 문제를 느꼈다. 

 

그래서 과연 어떻게 하면 빨리 모델링을 할 수있을까? 확인해보고자 했다.

 

 

forecast 패키지를 활용하여 성능 비교를 해보자.

먼저 사용된 패키지는 data.table, zoo, forecast를 활용하였다. 

time3=system.time({
ls=list()
for(i in 1:25){
  message(i)
  ls[[i]]=data.frame(forecast(auto.arima(AirPassengers[1:(120+i-1)],ic='aicc',stepwise=F),12))[,1]
  temp3=t(bind_cols(ls))
}
})

먼저 for문을 통해 시간을 계산 한 결과 11초 정도가 나타났다.

 

다음은 lapply문을 활용한 결과 큰 차이는 나지 않으나 조금 빨라진 모습을 볼 수 있다.

time4=system.time({
ls2=list()
for(i in 1:25){
  ls2[[i]]=AirPassengers[1:(120+i-1)]
}
temp4=lapply(ls2,function(x){data.frame(forecast(auto.arima(x,ic='aicc',stepwise=F),12))[,1]})
})

다음은 zoo 패키지의 rollapply를 사용한 결과이다. 조금 더 빨라진 모습을 볼 수 있다.


library(forecast)
time1=system.time({
  dt=data.frame(temp=AirPassengers)
  setDT(dt)
temp1=dt[,rollapply(temp,120,function(x){data.frame(forecast(auto.arima(x,ic='aicc',stepwise=F),12))[,1]})]
})

다음은 data.table 패키지를 활용한 결과이다. 

time1=system.time({
  dt=data.frame(temp=AirPassengers)
  setDT(dt)
temp1=dt[,rollapply(temp,120,function(x){data.frame(forecast(auto.arima(x,ic='aicc',stepwise=F),12))[,1]})]
})

끝으로 아래 포스팅에서 본 여러개의 시계열 모델을 빠르게 예측하는 방법을 올리고 포스팅을 마치겠다. 

https://statkclee.github.io/statistics/stat-time-series-forecast.html

 

Software Carpentry: 데이터 과학 – 기초 통계

데이터 과학 – 기초 통계 시계열 데이터 예측(forecast) 학습 목표 시계열 데이터의 백미 예측을 살펴본다. 다양한 시계열 데이터 모형의 장단점을 비교한다. 자동 시계열 예측의 필요성을 이해한

statkclee.github.io

 

'통계 > time series' 카테고리의 다른 글

시계열 용어 정리  (0) 2020.07.15

기초통계분석

통계2019. 7. 7. 06:24
 

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

[SMOTE] 알고리즘  (0) 2021.02.14
감마분포 & 균일분포  (0) 2019.05.29
가설검정& 최강력검정  (0) 2019.04.25
R에서 일반화 가법모형(설명X)  (0) 2019.04.13

RPubs - gamma distribution


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

[SMOTE] 알고리즘  (0) 2021.02.14
기초통계분석  (0) 2019.07.07
가설검정& 최강력검정  (0) 2019.04.25
R에서 일반화 가법모형(설명X)  (0) 2019.04.13