[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, ...))
}#######
'통계' 카테고리의 다른 글
기초통계분석 (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
'통계 > time series' 카테고리의 다른 글
시계열 용어 정리 (0) | 2020.07.15 |
---|
'통계' 카테고리의 다른 글
[SMOTE] 알고리즘 (0) | 2021.02.14 |
---|---|
감마분포 & 균일분포 (0) | 2019.05.29 |
가설검정& 최강력검정 (0) | 2019.04.25 |
R에서 일반화 가법모형(설명X) (0) | 2019.04.13 |
감마분포 & 균일분포
'통계' 카테고리의 다른 글
[SMOTE] 알고리즘 (0) | 2021.02.14 |
---|---|
기초통계분석 (0) | 2019.07.07 |
가설검정& 최강력검정 (0) | 2019.04.25 |
R에서 일반화 가법모형(설명X) (0) | 2019.04.13 |