데이터 전처리

2024. 9. 2. 20:06확률 통계/R 데이터 분석

결측값

  • 데이터의 값들을 다듬고 분석에 적합한 데이터를 확보하는 것을 데이터 전처리라고 한다. 이때 결측값을 처리하는 방법이 데이터 전처리에서 중요한 방법 중 하나이다.

결측값 이란?

  • 데이터를 수집하면서 그에 알맞는 값을 얻지 못한다면 결측값으로 남게 된다. 이러한 경우에는 결측값을 제거하거나 적당한 값으로 치환한 후에 데이터를 분석하는 방법이 있다.

벡터의 결측값 처리

  • NA: 숫자형, 문자형, 논리형 데이터는 결측값을 나타내는 용도로 사용된다.
x<-c(1,2,3,NA,5,NA)
sum(x)
is.na(x)
sum(is.na(x))
sum(x,na.rm=T)
> sum(x)
[1] NA

> is.na(x)
[1] FALSE FALSE FALSE  TRUE FALSE  TRUE

> sum(is.na(x))
[1] 2

> sum(x,na.rm=T)
[1] 11
  • x에는 NA값이 존재하기 때문에 na값이 있다면 정확한 총합을 구할 수 없다.
  • is.na: NA값이면 TRUE 아니면 FALSE를 출력한다.
  • sum(is.na(x)): NA값들의 개수를 구해준다.
  • na.rm을 사용하여서 na값들을 제외하고 합을 구해준다.

결측치 값 대체 및 제거

x<-c(1,2,3,NA,5,NA)
y<-c(1,2,NA,NA,4,6)
x[is.na(x)]<-0
z<-as.vector(na.omit(y))
z
> x<-c(1,2,3,NA,5,NA)

> y<-c(1,2,NA,NA,4,6)

> x[is.na(x)]<-0

> z<-as.vector(na.omit(y))

> z
[1] 1 2 4 6
  • x[is.na(x)]<-0: NA값의 위치에 직접적으로 접근하여서 0으로 변경해 준다.
  • z <-as.vector(na.omit(y)): na.omit을 사용하여서 NA값을 제거하고 백터를 생성한다.

매트릭스와 데이터프레임의 결측값 처리하기

  • 일단은 NA값을 대이터프레임에 넣어준다.
x<-iris
x[1,2]<-NA;x[1,3]<-NA
x[2,3]<-NA;x[3,4]<-NA
head(x)
> head(x)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1          NA           NA         0.2  setosa
2          4.9         3.0           NA         0.2  setosa
3          4.7         3.2          1.3          NA  setosa
4          4.6         3.1          1.5         0.2  setosa
.....

데이터프레임의 열별 결측값 확인

x<-iris
x[1,2]<-NA;x[1,3]<-NA
x[2,3]<-NA;x[3,4]<-NA
head(x)

for(i in 1:ncol(x)){
  y<-is.na(x[,i])
  cat(colnames(x)[i],"\t",sum(y),"\n")
}

z<-function(y){
  return (sum(is.na(y)))
}

f<-apply(x,2,FUN=z)
f
> for(i in 1:ncol(x)){
+   y<-is.na(x[,i])
+   cat(colnames(x)[i],"\t",sum(y),"\n")
+ }
Sepal.Length 	 0 
Sepal.Width 	 1 
Petal.Length 	 2 
Petal.Width 	 1 
Species 	 0 

> f
Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
           0            1            2            1            0
  • 첫 번째는 반복문을 활용하여서 열에 있는 NA값의 개수를 is.na를 활용하여서 탐색한다.
  • 두 번째는 z함수를 통해서 NA개수를 구해주고 apply함수를 활용하여서 데이터셋을 분석해 준다.

데이터프레임의 행별 결측값 확

x<-iris
x[1,2]<-NA;x[1,3]<-NA
x[2,3]<-NA;x[3,4]<-NA

rowSums(is.na(x))
sum(rowSums(is.na(x))>0)
sum(is.na(x))
> rowSums(is.na(x))
  [1] 2 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 [21] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 [41] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 [61] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 [81] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[101] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[121] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[141] 0 0 0 0 0 0 0 0 0 0

> sum(rowSums(is.na(x))>0)
[1] 3

> sum(is.na(x))
[1] 4
  • rowSums를 활용하여서 결측값을 모두 찾아준다.

결측값을 제외하고 새로운 데이터셋 만들기

x<-iris
x[1,2]<-NA;x[1,3]<-NA
x[2,3]<-NA;x[3,4]<-NA

x[!complete.cases(x),]
y<-x[complete.cases(x),]
head(y)
> x[!complete.cases(x),]
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1          NA           NA         0.2  setosa
2          4.9         3.0           NA         0.2  setosa
3          4.7         3.2          1.3          NA  setosa

> y<-x[complete.cases(x),]

> head(y)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa
7          4.6         3.4          1.4         0.3  setosa
8          5.0         3.4          1.5         0.2  setosa
9          4.4         2.9          1.4         0.2  setosa
  • complete.cases: 데이터셋에서 NA를 포함하지 않은 완전한 행들을 찾아주는 역할을 한다.
  • ! complete.cases를 사용한다면 NA값이 포함된 값을 출력해 준다.

특이값

  • 특이값(이상치)은 정상 범위에서 벗어난 특별한 값들을 의미한다.
  • 특이값으로 인해서 데이터셋 전체에 오류를 발생시킬 수 있기 때문에 이러한 값들을 조정할 필요가 있다.

다음과 같은 부분을 통해서 확인해 볼 필요가 있다.

  1. 논리적으로 있을 수 없는 값이 존재하는지 확인한다.
  2. 상식을 벗어난 값이 존재하는지 확인한다.
  3. 상자그림을 통해서 특이값을 확인한다.

특이값 추출 및 제거

x<-data.frame(state.x77)
boxplot(x$Income)
boxplot.stats(x$Income)$out

결과

> boxplot.stats(x$Income)$out
[1] 6315
  • boxplot을 활용하여서 특이값을 시각적으로 확인해 준다.
  • boxplot.status를 활용하여 특이값이 무엇인지 확인해 준다. 여기서는 6315가 특이값이다.

특이값을 포함한 행 제거

x<-data.frame(state.x77)
y<-boxplot(x$Income)$out
x$Income[x$Income %in% y]<-NA
head(x)

z<-x[complete.cases(x),]
head(z)
> head(x)
           Population Income Illiteracy Life.Exp Murder HS.Grad Frost   Area
Alabama          3615   3624        2.1    69.05   15.1    41.3    20  50708
Alaska            365     NA        1.5    69.31   11.3    66.7   152 566432
Arizona          2212   4530        1.8    70.55    7.8    58.1    15 113417
Arkansas         2110   3378        1.9    70.66   10.1    39.9    65  51945
California      21198   5114        1.1    71.71   10.3    62.6    20 156361
Colorado         2541   4884        0.7    72.06    6.8    63.9   166 103766

> z<-x[complete.cases(x),]

> head(z)
            Population Income Illiteracy Life.Exp Murder HS.Grad Frost   Area
Alabama           3615   3624        2.1    69.05   15.1    41.3    20  50708
Arizona           2212   4530        1.8    70.55    7.8    58.1    15 113417
Arkansas          2110   3378        1.9    70.66   10.1    39.9    65  51945
California       21198   5114        1.1    71.71   10.3    62.6    20 156361
Colorado          2541   4884        0.7    72.06    6.8    63.9   166 103766
Connecticut       3100   5348        1.1    72.48    3.1    56.0   139   4862
  • 특이값을 y에 저장해 둔다.
  • % in%과 같은 경우는 하나의 값뿐만 아니라 벡터에 비교하고자 하는 값이 포함되는지 알기 위해서 사용한다. 만약 ==을 사용한다면 비교하는데 어려움이 있을 수 있다.

데이터 정렬

벡터의 정렬

  • 정렬은 크기에 따라서 데이터를 재배열하는 과정을 의미한다. 
x<-c(1,8,4,5,2,4,2)
order(x)

y<-sort(x)
y

z<-sort(x,decreasing=T)
z
> order(x)
[1] 1 5 7 3 6 4 2

> y<-sort(x)

> y
[1] 1 2 2 4 4 5 8

> z<-sort(x,decreasing=T)

> z
[1] 8 5 4 4 2 2 1
  • order: 정렬하였을 때 이전에 있던 위치를 출력해 준다.
  • sort: 기본적으로 오름차순으로 되어있다. decreasing=T로 한다면 내림차순으로 정렬된다.

매트릭스와 데이터프레임 정렬

order(iris$Sepal.Length)
iris[order(iris$Sepal.Length),]
iris[order(iris$Sepal.Length,decreasing=T),]
x<-iris[order(iris$Sepal.Length),]
head(x)
iris[order(iris$Species,-iris$Petal.Length, decreasing=T),]
> order(iris$Sepal.Length)
  [1]  14   9  39  43  42   4   7  23  48   3  30  12  13  25  31
 [16]  46   2  10  35  38  58 107   5   8  26  27  36  41  44  50
 [31]  61  94   1  18  20  22  24  40  45  47  99  28  29  33  60
 [46]  49   6  11  17  21  32  85  34  37  54  81  82  90  91  65
 .....
 
 > iris[order(iris$Sepal.Length),]
    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
14           4.3         3.0          1.1         0.1     setosa
9            4.4         2.9          1.4         0.2     setosa
39           4.4         3.0          1.3         0.2     setosa
43           4.4         3.2          1.3         0.2     setosa
42           4.5         2.3          1.3         0.3     setosa
4            4.6         3.1          1.5         0.2     setosa
......

> iris[order(iris$Sepal.Length,decreasing=T),]
    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
132          7.9         3.8          6.4         2.0  virginica
118          7.7         3.8          6.7         2.2  virginica
119          7.7         2.6          6.9         2.3  virginica
123          7.7         2.8          6.7         2.0  virginica
136          7.7         3.0          6.1         2.3  virginica
106          7.6         3.0          6.6         2.1  virginica
.......

> head(x)
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
14          4.3         3.0          1.1         0.1  setosa
9           4.4         2.9          1.4         0.2  setosa
39          4.4         3.0          1.3         0.2  setosa
43          4.4         3.2          1.3         0.2  setosa
42          4.5         2.3          1.3         0.3  setosa
4           4.6         3.1          1.5         0.2  setosa

> iris[order(iris$Species,-iris$Petal.Length, decreasing=T),]
    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
107          4.9         2.5          4.5         1.7  virginica
127          6.2         2.8          4.8         1.8  virginica
139          6.0         3.0          4.8         1.8  virginica
122          5.6         2.8          4.9         2.0  virginica
124          6.3         2.7          4.9         1.8  virginica
.......
  • order를 활용하여서 오름 차순과 내림 차순을 진행해 준다. 
  • x에는 오름차순 정렬을 한 값을 저장해 준다. 
  • iris [order(iris$Species,-iris$Petal.Length, decreasing=T),]: Species를 기준으로 하여서 내림 차순을 진행해 준다. 또한 decreasing과 반대되는 작업을 하기 위해서 -를 붙여서 Petal.Length를 오름차순 정렬을 해준다. 

데이터의 분리와 선택

데이터 분리

x<-split(iris, iris$Species)
x
summary(x)
x$setosa
> x
$setosa
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1           5.1         3.5          1.4         0.2  setosa
2           4.9         3.0          1.4         0.2  setosa
3           4.7         3.2          1.3         0.2  setosa
4           4.6         3.1          1.5         0.2  setosa
5           5.0         3.6          1.4         0.2  setosa
......
$versicolor
    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
51           7.0         3.2          4.7         1.4 versicolor
52           6.4         3.2          4.5         1.5 versicolor
53           6.9         3.1          4.9         1.5 versicolor
54           5.5         2.3          4.0         1.3 versicolor
55           6.5         2.8          4.6         1.5 versicolor
56           5.7         2.8          4.5         1.3 versicolor
......
$virginica
    Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
101          6.3         3.3          6.0         2.5 virginica
102          5.8         2.7          5.1         1.9 virginica
103          7.1         3.0          5.9         2.1 virginica
104          6.3         2.9          5.6         1.8 virginica
105          6.5         3.0          5.8         2.2 virginica
......

> summary(x)
           Length Class      Mode
setosa     5      data.frame list
versicolor 5      data.frame list
virginica  5      data.frame list

> x$setosa
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1           5.1         3.5          1.4         0.2  setosa
2           4.9         3.0          1.4         0.2  setosa
3           4.7         3.2          1.3         0.2  setosa
4           4.6         3.1          1.5         0.2  setosa
5           5.0         3.6          1.4         0.2  setosa
......
  • split: 데이터셋을 분리할 때 사용한 함수로, 위에서는 Species를 기준으로 하여서 iris데이터를 종류별로 분류하였다.
  • summary를 통해서 열의 개수와 자료형을 확인할 수 있다. 

데이터 선택

subset(iris,Species=="setosa")
subset(iris, Sepal.Length>7.5)
subset(iris, Sepal.Length>5.1&Sepal.Width>3.9)
subset(iris, Sepal.Length>7.6, select=c(Petal.Length, Petal.Width))
> subset(iris,Species=="setosa")
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1           5.1         3.5          1.4         0.2  setosa
2           4.9         3.0          1.4         0.2  setosa
3           4.7         3.2          1.3         0.2  setosa
4           4.6         3.1          1.5         0.2  setosa
5           5.0         3.6          1.4         0.2  setosa
......

> subset(iris, Sepal.Length>7.5)
    Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
106          7.6         3.0          6.6         2.1 virginica
118          7.7         3.8          6.7         2.2 virginica
119          7.7         2.6          6.9         2.3 virginica
123          7.7         2.8          6.7         2.0 virginica
132          7.9         3.8          6.4         2.0 virginica
136          7.7         3.0          6.1         2.3 virginica

> subset(iris, Sepal.Length>5.1&Sepal.Width>3.9)
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
15          5.8         4.0          1.2         0.2  setosa
16          5.7         4.4          1.5         0.4  setosa
33          5.2         4.1          1.5         0.1  setosa
34          5.5         4.2          1.4         0.2  setosa

> subset(iris, Sepal.Length>7.6, select=c(Petal.Length, Petal.Width))
    Petal.Length Petal.Width
118          6.7         2.2
119          6.9         2.3
123          6.7         2.0
132          6.4         2.0
136          6.1         2.3
  • subset(데이터 셋, 조건): 조건에 맞춰서 데이터셋을 추출한다.
  • 두 번째 같은 경우는 Sepal.Length가 7.5보다 큰 경우의 데이터 셋을 출력하도록 설정하였다.
  • 네 번째 같은 경우는 select를 통해서 특정 열의 값들만 추출하도록 설정해 주었다. 

데이터 샘플링과 조합

데이터 샘플링

  • 샘플링은 통계 용어로 사용되는데, 보통 특정 집단에서 무작위 하게 값들을 추출하는 것을 의미한다.
  • 이때 추첨함에서 쪽지를 뽑는 경우에 쪽지를 뽑고 나서 다시 넣지 않는 경우를 비복원 추출이라고 하고 다시 넣을 때는 복원 추출이라고 한다.
x<-1:50
y<-sample(x,size=10, replace=F)
y
> y
 [1] 26  4 40 45 24  2  9 29 25 37
  • sample: 특정 데이터의 샘플을 추출해 주는 함수
  • size를 통해서 데이터의 개수(범위)를 정해주고 replace를 TRUE로 해준다면 복원 추출을 하고 FALSE로 하면 비복원 추출을 한다.

행을 임의로 추출하기

x<-sample(1:nrow(iris),size=50, replace=FALSE)
y<-iris[x,]
dim(y)
head(y)
> dim(y)
[1] 50  5

> head(y)
    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
109          6.7         2.5          5.8         1.8  virginica
135          6.1         2.6          5.6         1.4  virginica
9            4.4         2.9          1.4         0.2     setosa
70           5.6         2.5          3.9         1.1 versicolor
120          6.0         2.2          5.0         1.5  virginica
125          6.7         3.3          5.7         2.1  virginica
  • nrow: 행의 계수를 알아내는 함수이다.
  • sample함수에서 의미하는 것은 행 1~150까지 50개의 데이터를 비복원 추출하는 것이다.
  • dim: 행과 열의 개수를 보여준다.

set.seed 함수 이해하기

set.seed(100)
sample(1:20,size=5)
set.seed(99)
sample(1:20,size=5)
set.seed(100)
sample(1:20,size=5)
> set.seed(100)

> sample(1:20,size=5)
[1] 10  6 16 14 12

> set.seed(99)

> sample(1:20,size=5)
[1] 16  1 12  3 10

> set.seed(100)

> sample(1:20,size=5)
[1] 10  6 16 14 12
  • set.seed: sample함수 실행 이전에 실행하여서 만약 매개변수의 값과 동일하다면 동일한 결과를 출력한다.
  • 위와 같은 경우에는 set.seed를 100으로 설정해 둔 것과 99로 해둔 것은 다르지만 다시 100으로 설정하였을 때에는 동일한 것을 볼 수 있다.

데이터 조합

  • 조합은 짝을 만들어서 데이터 값들을 추출하는 작업을 의미한다.
x<-c(1,2,3,4)
combn(x,3)

y<-c("a","b","c","d")
z<-combn(y,3)

for(i in 1:ncol(z)){
  cat(z[,i],"\n")
}
> combn(x,3)
     [,1] [,2] [,3] [,4]
[1,]    1    1    1    2
[2,]    2    2    3    3
[3,]    3    4    4    4

> for(i in 1:ncol(z)){
+   cat(z[,i],"\n")
+ }
a b c 
a b d 
a c d 
b c d
  • combn(데이터셋, 크기): 데이터셋에서 크기만큼 조합의 경우의 수를 출력해 준다.

데이터 집계와 병합

데이터 집계

  • 데이터 그룹에 대해 합계나 평균을 계산하는 작업을 집계라고 한다. 
x<-aggregate(iris[,-5], by=list(data=iris$Species),FUN=mean)
x
> x
        data Sepal.Length Sepal.Width Petal.Length Petal.Width
1     setosa        5.006       3.428        1.462       0.246
2 versicolor        5.936       2.770        4.260       1.326
3  virginica        6.588       2.974        5.552       2.026
  • aggregate(데이터셋, 집계 기준, 함수): 데이터셋을 집계 기준에 맞춰서 함수에 알맞게 데이터셋을 출력한다. 
  • by=list(data=iris$Species): 데이터의 집계 기준을 의미하는데, 여기에서 data는 집계기준이 되는 열의 이름이다.
  • FUN=mean: 함수를 평균으로 지정해 준다.

표준 편차 출력하기 

x<-aggregate(iris[,-5], by=list(표준편차=iris$Species),FUN=sd)
x
> x
    표준편차 Sepal.Length Sepal.Width Petal.Length Petal.Width
1     setosa    0.3524897   0.3790644    0.1736640   0.1053856
2 versicolor    0.5161711   0.3137983    0.4699110   0.1977527
3  virginica    0.6358796   0.3224966    0.5518947   0.2746501
  • FUN=sd: 표준편차를 의미하는 함수 sd로 설정해 준다.

변수의 최댓값 출력

x<-aggregate(mtcars, by=list(mtcars$cyl,mtcars$vs),FUN=max)
x
> x
  Group.1 Group.2  mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1       4       0 26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
2       6       0 21.0   6 160.0 175 3.90 2.875 17.02  0  1    5    6
3       8       0 19.2   8 472.0 335 4.22 5.424 18.00  0  1    5    8
4       4       1 33.9   4 146.7 113 4.93 3.190 22.90  1  1    5    2
5       6       1 21.4   6 258.0 123 3.92 3.460 20.22  1  0    4    4
  • mtcars에서 cyl과 vs를 기준으로 하여서 다른 열들의 최댓값을 출력하는 코드

데이터 병합

  • 분석을 통해서 A와 B 파일을 합치는 경우를 병합이라고 한다.
x<-data.frame(name=c("a","b","c"), math=c(90,80,70))
y<-data.frame(name=c("a","b","c"), korean=c(90,80,60))

z<-merge(x,y,by=c("name"))
z
> z
  name math korean
1    a   90     90
2    b   80     80
3    c   70     60
  • merge(x, y): x와 y를 병합하는 함수
  • by=c("name"): name열을 기준으로 하여서 병합한다.
x<-data.frame(name=c("a","b","c"), math=c(90,80,70))
y<-data.frame(name=c("a","b","d"), korean=c(90,80,60))

merge(x,y,all.x=T)
merge(x,y,all.y=T)
merge(x,y,all=T)
> merge(x,y,all.x=T)
  name math korean
1    a   90     90
2    b   80     80
3    c   70     NA

> merge(x,y,all.y=T)
  name math korean
1    a   90     90
2    b   80     80
3    d   NA     60

> merge(x,y,all=T)
  name math korean
1    a   90     90
2    b   80     80
3    c   70     NA
4    d   NA     60
  • 위처럼 name이 c, d처럼 서로 다른 값이 출력될 수도 있다. 
  • 이런 경우에 name을 x를 기준으로 출력하고 싶다면 all.x=T라고 해주면 된다.
  • all을 사용한다면 비어있는 값은 NA로 출력해 준다.
x<-data.frame(name=c("a","b","c"), math=c(90,80,70))
y<-data.frame(sname=c("a","b","d"), korean=c(90,80,60))

merge(x,y,by.x=c("name"), by.y=c("sname"))
> merge(x,y,by.x=c("name"), by.y=c("sname"))
  name math korean
1    a   90     90
2    b   80     80
  • by.x, by.y: 각각의 열을 기준으로 하여서 병합해 준다.

'확률 통계 > R 데이터 분석' 카테고리의 다른 글

ggplot 패키지  (0) 2024.09.05
데이터 시각화1  (0) 2024.09.03
자료의 탐색  (0) 2024.09.01
다중변수 자료의 탐색  (0) 2024.08.30
단일변수 자료의 탐색  (0) 2024.08.29