R) 전처리 - 변수 속성 변환

R) 전처리 - 변수 속성 변환

데이터프레임을 다룰 때 특정 속성을 가지는 변수를 원하는 속성으로 변환하고 싶을때는 코드를 어떻게 작성해야 할까? 초급/중급/고급으로 나누어서 살펴보도록 하자.

데이터는 ggplot2 패키지의 diamonds를 쓰도록 한다.

1
2
3
4
5
6
7
8
9
10
library("ggplot2")
df2 = as.data.frame(diamonds)
head(df2)
## carat cut color clarity depth table price x y z
## 1 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43
## 2 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31
## 3 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31
## 4 0.29 Premium I VS2 62.4 58 334 4.20 4.23 2.63
## 5 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75
## 6 0.24 Very Good J VVS2 62.8 57 336 3.94 3.96 2.48

apply 계열 함수를 활용하여 각 변수의 속성을 확인하면 다음과 같다.

1
2
3
unlist(lapply(sapply(df2, FUN = "class"), FUN = "[", 1))
## carat cut color clarity depth table price x y z
## "numeric" "ordered" "ordered" "ordered" "numeric" "numeric" "integer" "numeric" "numeric" "numeric"

위 코드 관련 해설은 다음의 포스팅을 참고하도록 한다.
※ 변수 속성 확인 포스팅 바로가기 -> [클릭]

위에서 확인하였듯이 연속형 변수가 아닌 cut, color, clarity 변수를 대상으로 변환을 실시해보겠다.


초급

속성을 바꾸는 함수는 as 접두사가 붙어있다. 문자가 아닌 것을 문자로 바꾸는 함수는 as.character() 숫자가 아닌 것을 숫자로 바꾸는 함수는 as.numeric() 함수를 사용한다. 사용예는 다음과 같다.

1
2
3
4
as.character(123)
## [1] "123"
as.numeric("234")
## [1] 234

as.character() 함수를 알았으니 각 변수에 적용해볼 차례이다.

1
2
3
4
5
6
class(df$cut)
## [1] "ordered" "factor"

df[, "cut"] = as.character(df$cut)
class(df$cut)
## [1] "character"

일단 하나를 적용해본 결과는 다음과 같다. 이제 세 변수를 모두 처리하려면 다음과 같이 작성할 수 있다.

1
2
3
df[, "cut"    ] = as.character(df$cut)
df[, "color" ] = as.character(df$color)
df[, "clarity"] = as.character(df$clarity)

직접 문자로 지정하는 방법 말고 숫자로 하면 다음과 같이 할 수 있겠다.

1
2
3
df[, 2] = as.character(df[, 2]) # cut
df[, 3] = as.character(df[, 3]) # color
df[, 4] = as.character(df[, 4]) # clarity

중급

초급 부분에서 마지막으로 작성한 코드를 다시 확인해보고 오자. 해당 코드는 숫자만 바꿔주면 되기 때문에 다음과 같이 반복문으로도 바꿀 수 있다.

1
2
3
for(n_col in 2:4){
df[, n_col] = as.character(df[, n_col])
}

sapply() 함수를 활용하면 다음과 같이 할 수 있다.

1
df[, 2:4] = sapply(df[, 2:4], FUN = "as.character")

그래도 데이터를 다루는데 dplyr 패키지가 빠질수는 없다. 다음과 같은 다양한 방법으로 접근할 수 있다.

1
2
3
4
5
6
7
df %>% 
select(cut:clarity) %>%
sapply("as.character") -> df[, 2:4] # 1

df %>%
select(cut:clarity) %>%
mutate_all("as.character") -> df[, 2:4] # 2

첫 번째 코드는 dplyr 함수 중 변수를 선택하는 select() 함수만 사용하였고, 두 번째 코드는 온전히 dplyr 패키지 함수를 기본으로 사용하였다.

그런데 위 코드는 이미 2~4번째의 변수가 대상이라는 것을 인지하고 있기 때문에 작성할 수 있는 것이며, 좀 더 응용하면 다음과 같이 작성할 수 있다.

1
2
3
4
5
6
df_classes = unlist(lapply(sapply(df2, FUN = "class"), FUN = "[", 1))
for(n_col in 1:ncol(df)){
if(df_classes[n_col] != "numeric"){
df[, n_col] = as.character(df[, n_col])
}
}

전체 변수의 속성을 훑으면서 특정 변수가 수치형(numeric)이 아닐 경우 변환하는 코드이다. 물론 수치형이 아니라 다른 조건을 넣으면 원하는대로 수정할 수 있겠다.


고급

기본함수를 활용하여 범주형 자료를 한 번에 문자형으로 바꾸는 예제는 다음과 같다.

1
2
df[, sapply(df, FUN = "is.factor")] = sapply(df[, sapply(df, FUN = "is.factor")],
FUN = "as.character")

dplyr 패키지 버전은 다음과 같다.

1
2
df %>% 
mutate_at(vars(cut, color, clarity), as.character) -> df

이 경우는 대상 변수를 알고 있을 때 사용하는 방법이다.

이번에는 mutate_if() 함수를 활용해보자. 해당 함수는 각 변수가 범주형일 경우 is.factor() 함수의 결과 값이 TRUE가 되는데 이 위치에 .fun 인자에 할당된 함수를 적용한다. 마치 sapply() 함수와 ifelse() 함수를 조합한 느낌의 함수가 되겠다.

1
2
3
4
5
6
7
8
9
df %>% 
mutate_if(is.factor, .funs = "as.character") -> df_mut
sapply(df_mut, "class")
## carat cut color clarity
## "numeric" "character" "character" "character"
## depth table price x
## "numeric" "numeric" "integer" "numeric"
## y z
## "numeric" "numeric"

비슷한 함수로는 purrr 패키지의 map_if() 함수가 있으며 예제는 다음과 같다.

1
2
3
4
library("purrr")
df %>%
map_if(is.factor, as.character) %>%
as.data.frame() -> df

여기서 좀 아쉬운 점은 map_if() 함수를 통과한 결과가 list 객체로 출력이 되기 때문에 이를 다시 as.data.frame() 함수를 사용하여 data.frame으로 바꿔야 하는 번거로움이 있다.

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×