본문 바로가기
## 오래된 게시글 (미관리) ##/R

23. Missing Data, 이상치

by #Glacier 2018. 11. 21.
반응형

안녕하세요. 오늘은 기초 분석 및 데이터 관리에 대해서 포스팅합니다.

바로 시작할게요. 


1. Missing Data 처리

-Missing Data 처리 방법은 전체 작업 시간에 많은 영향을 준다.

-R의 Missing Data처리 패키지는 Amelia II, Mice, mistools, Missing Data 처리방안, Missing Data를 포함한 관측치(record) 삭제

 해당 변수의 대푯값을 imputation, 변수간의 관계를 이용한 imputation이 있다.

# 여기서 imputation은 결측값 대체의 의미입니다.


#확인

-NA : Not Available (값이 없음)

-NaN : Not a Number, 불가능한 값 (Ex, infinite, 0/0)


#확인법

-NA로 입력

-is.na()로 확인


TIP ) Missing Data를 제외하느냐 대체하느냐, 또 어떻게 대체하느냐는 자신의 분석에 맞게 고려해야 한다. 절대 버리면 안되는 경우는 대체하거나,

      대체 방법도 고민해야 한다. missing을 대체한다는 것은 예측력을 높여줄 수도 있지만 되려 정확도가 떨어질 수도 있다는 것.


# 예제


Final4_team<-c("GER","ARG","NED","BRA", NA)

is.na(Final4_team) #NA 확인


[1] FALSE FALSE FALSE FALSE  TRUE


Final4<-data.frame(team=c("GER","ARG","NED","BRA", "GER","BRA","ARG","NED"), stage=c(rep("F",2),rep("34",2),rep ("QF", 4)),

           res=c("1","0","0","3","1","7","0(2)", "0(4)")) #데이터를 수작업으로 입력하는 과정

Final4


 Final4
  team stage  res
1  GER     F    1
2  ARG     F    0
3  NED    34    0
4  BRA    34    3
5  GER    QF    1
6  BRA    QF    7
7  ARG    QF 0(2)
8  NED    QF 0(4)


#요 수작업으로 만들어진 데이터에 대한 설명은 저번에 했기 때문에 언급하지 않겠습니다.

 (책에 있는 예제가 이해하기 쉬워서 안 해도 아실만한 데이터라고 생각)


Final4[Final4$stage=="QF", "res"] <- NA

#Final4의 stage내의 QF항목들의 res를 NA로 대체


Final4
  team stage  res
1  GER     F    1
2  ARG     F    0
3  NED    34    0
4  BRA    34    3
5  GER    QF <NA>
6  BRA    QF <NA>
7  ARG    QF <NA>
8  NED    QF <NA>


# 평균 산출 등 데이터 처리에서 missing 으로 인한 문제 해결 -> 해당 값을 제외

mean(as.numeric(as.character(Final4$res)))

[1] NA


mean(as.numeric(as.character(Final4$res)), na.rm=T)

[1] 1


#na.rm=TRUE는 NA 값을 제외시킵니다. 그렇다면 그 missing이 포함된 행 자체를 삭제해버리는 방법(record 자체)을 해보겠습니다.

# complete.cases()함수를 이용하고, missing이 넓게 분포된 경우 많은 데이터의 삭제로 문제가 발생할 수 있습니다.

# 아래에서 !는 부정의 의미입니다. Final4 행들이 완벽하게 되있지 않은 것들을 골라냅니다.


Final4[!complete.cases(Final4),] #확인작업

  team stage  res
5  GER    QF <NA>
6  BRA    QF <NA>
7  ARG    QF <NA>
8  NED    QF <NA>


#na.omit()함수를 이용해 행 전체가 삭제됩니다. #삭제 작업


na.omit(Final4)

  team stage res
1  GER     F   1
2  ARG     F   0
3  NED    34   0
4  BRA    34   3


#이렇게 제거되고 정상적인 것들만 남게됩니다.


2. Amelia를 이용한 Missing Data 처리 


install.packages("Amelia")

library(Amelia)

data(africa) # africa data는 1972년부터 1991년까지 아프리카 6개국의 경제와 정치 변수 data

head(africa)
 

  year      country gdp_pc  infl trade    civlib population
1 1972 Burkina Faso    377 -2.92 29.69 0.5000000    5848380
2 1973 Burkina Faso    376  7.60 31.31 0.5000000    5958700
3 1974 Burkina Faso    393  8.72 35.22 0.3333333    6075700
4 1975 Burkina Faso    416 18.76 40.11 0.3333333    6202000
5 1976 Burkina Faso    435 -8.40 37.76 0.5000000    6341030
6 1977 Burkina Faso    448 29.99 41.11 0.6666667    6486870


# 아참 여러분, 저렇게 명령어를 쓴 후에 # ~한글로 막 써도 명령어만 인식합니다!ㅎㅎ

# 아프리카 데이터를 보니까~ 1972년부터 쭉~ 있고, 부르키나파소 country가 보이고.. 

  GDP. 물가상승률. 무역.. 등 여러가지 지표가 있군요

# 저번에 봤듯이 summary()함수를 사용하면 NA의 개수를 세줍니다.


summary(africa)


      year              country       gdp_pc            infl        
 Min.   :1972   Burkina Faso:20   Min.   : 376.0   Min.   : -8.400  
 1st Qu.:1977   Burundi     :20   1st Qu.: 513.8   1st Qu.:  4.760  
 Median :1982   Cameroon    :20   Median :1035.5   Median :  8.725  
 Mean   :1982   Congo       :20   Mean   :1058.4   Mean   : 12.753  
 3rd Qu.:1986   Senegal     :20   3rd Qu.:1244.8   3rd Qu.: 13.560  
 Max.   :1991   Zambia      :20   Max.   :2723.0   Max.   :127.890  
                                        NA's   :2                         
     trade            civlib         population      
 Min.   : 24.35   Min.   :0.0000   Min.   : 1332490  
 1st Qu.: 38.52   1st Qu.:0.1667   1st Qu.: 4332190  
 Median : 59.59   Median :0.1667   Median : 5853565  
 Mean   : 62.60   Mean   :0.2889   Mean   : 5765594  
 3rd Qu.: 81.16   3rd Qu.:0.3333   3rd Qu.: 7355000  
 Max.   :134.11   Max.   :0.6667   Max.   :11825390  
 NA's   :5                                       


# 복사하면 밀려서보기 좀 그렇긴 한데 ~ㅎㅎ;

# gdp_pc에 NA가 2개 , trade에 5개가 있는걸 확인할 수 있습니다.

# 이제 amelia에 들어가기 앞서서 변수들의 관계를 이용한 imputation을 하기 위해 몇 가지 알아야 할 사항이 있습니다.

# m : 몇 개의 imputation dataset을 만들지를 결정하는 값

# ts : 시계열에 대한 정보 ( 연도 )

# cs : cross-sectional 분석에 포함될 정보 ( 국가, country )

# 여기서는 시계열에 대한 정보는 연도가 있고, cross-sectional 분석에 포함될 정보는 국가로 설정합니다.


a.out <- amelia ( africa, m=3, ts="year", cs= "country")

-- Imputation 1 --

  1  2  3

-- Imputation 2 --

  1  2  3

-- Imputation 3 --

  1  2  3


                         # Imputation 전                                                             # Imputation 후

                           missmap(a.out)                                                             africa$trade<-a.out$imputation[[3]]$trade

                                                                                                            missmap(africa)




#  이렇게 보면, Before에서 trade의 결측값이 싹 대체된 것을 볼 수 있습니다!
# 이렇게 간단하게 알아보았는데요~ Amelia는 bootstrap방식을 쓰는 것 같군요!


3. Outlier Detection

# 이상치라고도 합니다. Outlier가 있으면 전체적인 통계가 제대로 안나올 수 있습니다. 

   따라서 Outlier를 어떻게 탐지하는지에 알아보겠습니다.


 1) Outlier를 찾는 것은?

 Outlier를 찾는 것은 분석에서 전처리를 어떻게 할지를 결정하는 데 사용.

 Fraud Detection에서 규칙을 발견하는 데 사용


 2) Outlier 분류

 a1. 의도되지 않은 경우로 잘못 입력된 경우

 a2. 의도되지 않은 현상이 그대로 입력되었으나 분석 목적에 부합되지 않아 제거해야 하는 경우

 a3. 의도되지 않은 현상이나 분석에 포함되어야 하는 경우

 b1. 의도된 Oulier는 대부분 Fraud(엉터리)

 # a1. a2는 bad data라 하고, a3, b1은 outlier라고 한다.

 # 즉 잘못 입력되었거나, 제거해야하는 의도되지 않은 현상은 BAD DATA,

    의도되지 않았지만 분석에 포함되어야 하는 경우와 엉터리 데이터는 outlier.


 3) 관련 알고리즘

  -ESD(Extreme Studentized Deviation) : maen으로부터 t-standard deviation 떨어져 있는 값들은 outlier고 t는 3, 

                                       그러나 이 방법조차도 outlier로 부터 매우 민감한 단점이 있다.

  -MADM


 4) 투입 시간

 -실전에서 Outlier를 찾기 위해 많은 시간을 쓰지 말 것

 -summary를 통해 Mean과 Median값을 본 다음에 Q1, Q3를 보고 1차 판단

 -주요 dimension별로 plot을 해보면 특성 파악 가능

 - 단, fraud detection project에서는 많은 시간을 투자해야 한다.


# R에서의 실행


data(wine, package="HDclassif")

head(wine)


  class    V1   V2   V3   V4  V5   V6   V7   V8   V9  V10  V11  V12  V13
1     1 14.23 1.71 2.43 15.6 127 2.80 3.06 0.28 2.29 5.64 1.04 3.92 1065
2     1 13.20 1.78 2.14 11.2 100 2.65 2.76 0.26 1.28 4.38 1.05 3.40 1050
3     1 13.16 2.36 2.67 18.6 101 2.80 3.24 0.30 2.81 5.68 1.03 3.17 1185
4     1 14.37 1.95 2.50 16.8 113 3.85 3.49 0.24 2.18 7.80 0.86 3.45 1480
5     1 13.24 2.59 2.87 21.0 118 2.80 2.69 0.39 1.82 4.32 1.04 2.93  735
6     1 14.20 1.76 2.45 15.2 112 3.27 3.39 0.34 1.97 6.75 1.05 2.85 1450


wine_od<- wine[,c(8,11,14,2)]

outlier.scores<-lofactor(wine_od, k=5)

plot(density(outlier.scores)) 


# 이렇게 서적에 적혀있는데, lofactor등에 대해서 전혀 언급이 없더군요.. 그래서 제가 직접 찾아본 결과,

  1) 카이제곱 분포를 이용해서, 데이터가 정규분포를 따른다고 가정하고, K개의 서로 독립적인 표준정규확률변수를 각각 제곱한 다음 합해서 얻어지는 분포에 의해

  97.5%이상인지 살펴본다고 합니다.

  2) lofactor는 Local outlier Factor이며, 샘플의 밀도를 측정해 가장 밀도에서 벗어나는 데이터 즉, LOF값이 가장 큰 데이터를 이상치로 추정합니다.


  위 두가지의 방법으로 검출되는 outlier가 서로 다르고, 따라서 데이터의 특성에 맞게 plot을 찍어보고 어떤 것이 적합한지 찾아야 한다고 합니다.

  (출처 : http://pubdata.tistory.com/53 )


# 책에서는 두 가지 모두 다루고 있지 않고. 2번 방식을 다루고 있습니다. 근데 패키지가 뭔지도 적혀있지 않았어요 ㅠㅠ 그러나 DMwR패키지를 사용하면 되는군요..


install.packages("DMwR")

library(DMwR)

wine_od<- wine[,c(8,11,14,2)]

outlier.scores<-lofactor(wine_od, k=5)

plot(density(outlier.scores))




# 요렇게 드디어 되었습니다. 찾는데 꽤나 애먹었군요. 그래프를 해석하는 법은, 오른쪽으로 꼬리가 긴 형태를 보이는데,

   이는 큰 값이 비정상적으로 있다는 것을 의미합니다 -> 이상 값의 존재 가능성


outliers <-order(outlier.scores, decreasing=T)[1:5]

print(outliers)

[1]  54  13 167 136  34


#이렇게 나왔습니다. 저것은 이상치의 값이 아닌 이상치가 존재하는 row의 번호입니다~! 대체 해야겠죠?

#n에 wine_od의 행수만큼 집어넣고, labels에 1부터 n까지 다 넣은 후 outliers를 제외한 모든 값들을 "."으로 대체합니다.

#그리고 biplot을 하고

n<-nrow(wine_od)

labels<- 1:n

labels[-outliers]<-"."


그러면 이런 형태가 됩니다.


  [1] "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."  
 [13] "13"  "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."  
 [25] "."   "."   "."   "."   "."   "."   "."   "."   "."   "34"  "."   "."  
 [37] "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."  
 [49] "."   "."   "."   "."   "."   "54"  "."   "."   "."   "."   "."   "."  
 [61] "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."  
 [73] "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."  
 [85] "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."  
 [97] "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."  
[109] "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."  
[121] "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."  
[133] "."   "."   "."   "136" "."   "."   "."   "."   "."   "."   "."   "."  
[145] "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "."  
[157] "."   "."   "."   "."   "."   "."   "."   "."   "."   "."   "167" "."  
[169] "."   "."   "."   "."   "."   "."   "."   "."   "."   "." 


biplot(prcomp(wine_od), cex=0.8, xlabs=labels)




# outlier외에 모두 "."으로 대치했으므로, 숫자가 표시되는 것은 Outlier입니다.


pch<-rep(".", n)

pch[outliers]<-"+"

col<-rep("black", n)

col[outliers]<-"red"

pairs(wine_od, pch=pch, col=col)


# pch에 "."을 n개만큼(wine_od의 행수) 반복시키고, pch의 outliers만 +로 표시합니다.

#그리고 col은 컬러지정을 미리 한건데요, 모두 검정으로 칠하고, outlier만 red표시를 한 후

#pairs plot그래프를 그립니다.




# 이렇게~ 검정 점들이 찍히고 +로 outlier가 찍힙니다. 뭔가 별같네요..ㅋㅋ


#오늘은 이상치 탐색과 그것을 plot으로 그려보았는데요~ 어떠셨을지.. 

 다음 시간에는 정형데이터마이닝 파트의 분류분석부터 알아보도록 하겠습니다.




반응형