R 데이터 전처리

  • R

데이터 사이언스 영역에서 흔히 이런 얘기가 있다.

작업 시간의 80%는 raw 데이터를 수집하여 분석할 수 있는 형태로 만드는 데 쓰고, 실제로 데이터를 분석하거나 모델을 구축하는 데 사용하는 시간은 20% 정도 밖에 안 된다고.

데이터 전처리는 정말 성가시고 많은 공이 들어가는 작업이다. 대충 이런 거.

  • 여러 개 파일에서 데이터 병합하기
  • 깔끔한(tidy) 데이터인지 진단하고, 데이터프레임 변형하기
  • 중복값 처리하기 – 확인 및 제거
  • 문자열 조작하기 – 인덱싱, 분리
  • 데이터 유형(type) 변환하기 – 예: from 문자열 to 숫자

지금부터 R로 데이터 전처리 할 때 사용하는 방법을 간략히 알아보자.

준비

데이터 전처리는 tidyverse 패키지의 dplyrtidyr을 주로 사용한다.

일단 필요한 라이브러리를 불러오자.

library(readr)
library(dplyr)
library(tidyr)

위 세 개는 일단 무조건 깔아놓고 시작하는 게 좋다.

만약 문자열 인덱싱을 하려면 stringr도 필요하다.

library(stringr)

여러 개 파일에서 데이터 병합하기

1) 규칙에 맞는 파일명 모으기 : list.files()

base R의 기본 함수 list.files()를 사용하면 동일한 이름 형식을 가진 파일명을 모을 수 있다.

예를 들어 ‘file_1.csv’, ‘file_2.csv’ 이런 식으로 파일들이 나눠져 있다면 아래와 같이 조건을 만족하는 모든 파일명을 리스트(벡터)로 저장하는 게 가능하다.

files <- list.files(pattern = "file_.*csv")

여기서 pattern에는 정규식을 사용한 거다. 현재 디렉토리에서 ‘file_’로 시작하고 확장자가 csv인 파일들을 찾으라는 뜻이다. 정규식은 너무 어려우니 깊이 들어가진 말자.

2) 각 파일에 함수 적용 : lapply()

base R의 기본 함수 lapply()를 사용하면 위에서 모아놓은 파일명 리스트에 동일한 함수 read_csv를 적용할 수 있다. 각각의 csv 파일로부터 각각의 데이터프레임을 읽어놓는 거다.

df_list <- lapply(files, read_csv)

3) 데이터프레임 병합 : lapply()

dplyr의 bind_rows() 함수를 사용하면 위에서 모아놓은 데이터프레임을 하나로 합칠 수 있다.

bind_rows(df_list)

이렇게 하면 여러 파일에 흩어진 데이터 프레임을 하나로 모을 수 있다.


깔끔한 데이터인지 진단(diagnose) 및 변형하기(reshape)

데이터를 분석하거나 시각화하기 좋으려면, 일단 데이터가 깔끔(tidy)해야 한다.

깔끔하다는 게 무슨 뜻이냐면…

  • 변수(variable)들이 각각의 열(column)에 할당되어 있다.
  • 관찰된 값(observation)들이 각각의 행(row)에 할당되어 있다.

위 기준에 따르면 이런 데이터프레임보다는

이런 데이터프레임이 더 깔끔한 거다.

데이터프레임에 head(), summary(), colnames() 혹은 names()와 같은 함수를 사용해서 쭉 훑어보면 감이 올 거다.

데이터프레임을 훑어봤을 때 tidy하지 않다면 tidy한 형태로 변형해야 하는데 이때는 gather() 함수를 사용한다. (파이썬 라이브러리 pandas의 melt와 비슷한 거라 생각하면 된다.)

df %>%
  gather('Checking','Savings', key='Account Type', value='Amount')

gather() 함수 안에는 변수로 바꿔줄 열 이름이 들어가고, key에는 변수들이 들어갈 열 이름, value에는 값들이 들어갈 열 이름을 적어주면 된다.


중복값 처리하기

1) 중복값 확인하기 : duplicated()

중복값 확인은 base R 함수인 duplicated()로 한다. 아래와 같이 써주면

df %>% duplicated()

모든 행에 대해 TRUE 혹은 FALSE로 구성된 벡터를 돌려준다. TRUE가 중복값이다.

그리고 여기서 의미하는 중복값은 모든 열(변수)에 대해 같은 값을 가진 행을 말한다. 변수 하나라도 다른 값이 있으면 중복으로 보지 않는다.

이렇게 얻은 벡터에다가 고유값의 개수(빈도)를 돌려주는 table() 함수를 사용하면 중복값이 몇개 있는지도 확인할 수 있다.

duplicates <- df %>% duplicated() %>% table()

FALSE는 몇 개, TRUE는 몇 개 있는지 돌려준다.

2) 중복값 제거하기 : distinct()

dplyr의 함수인 distinct()를 사용하면 중복값을 제거할 수 있다.

df %>% distinct()

이 방법은 위에서 소개한, 즉 모든 변수가 일치하는 중복값을 제거한다.

만약 특정 열(변수)에서 중복이 일어난 경우를 제거하고 싶다면 subset을 명시해주면 된다.

예를 들어 id라는 열에서 중복이 나타난 값을 제거하고 싶다면 이렇게.

df %>% distinct(id, .keep_all=TRUE))

문자열 조작하기

1) 문자열 인덱싱 : str_sub()

stringr 패키지의 str_sub() 함수를 활용하면 인덱스를 기준으로 문자열을 쪼갤 수 있다. 이런 식으로.

str_sub(string, starting_index, ending_index)

참고로 R은 0이 아니라 1이 첫 인덱스다.

그래서 기존에 값이 문자로 이루어진 열에서 일부를 쪼개서 새로운 열을 만들고 싶다면 mutate() 함수 안에 str_sub()를 넣어서 이런식으로 써볼 수 있겠다.

df %>%
  mutate(new_col = str_sub(string, starting_index, ending_index))

2) 문자열 나누기 : separate()

특정 문자를 기준으로 문자열을 분리, 즉 기존에 문자로 이루어진 열을 여러 개의 열로 분리하려면 tidyr의 separate() 함수를 사용하면 된다.

사용법은 아래와 같다.

df %>%
  separate(col_to_separate, c('new_col_name_1','new_col_name_2'), 'character_to_split_on')

만약 name이라는 열을 공백문자(띄어쓰기)를 기준으로 fist_name과 last_name이라는 2개의 열로 나누려면 아래와 같이 쓸 수 있겠다.

df %>%
  separate(name, c('fist_name','last_name'), ' ')

그런데 만약 띄어쓰기가 두 개 이상 들어갔다면? middle name을 가진 사람도 있을 수 있으니까.

아무튼 특정문자를 기준으로 문자열을 나누고 보니 2개 이상인 경우, 그 뒷 부분을 어떻게 처리할지 생각해봐야 한다. extra ='merge'를 적어주면 나머지는 병합해준다. 이렇게.

df %>%
  separate(name, c('fist_name','last_name'), ' ', extra ='merge')

3) 문자열 파싱 : gsub()

base R의 gsub() 함수를 사용하면 정규표현식을 사용해서 문자열을 조작할 수 있다.

예를 들어 price열에 있는 $기호를 모두 삭제(”로 대체)하고 싶다면 이렇게 써줄 수 있다.

df %>%
  mutate(price = gsub('\\$', '', price))

정규식에 대해 너무 깊게 파고들면 어려우니까… 일단은 필요할 때 여기저기 참고해서 쓰자.


데이터 유형(type) 변경하기

데이터프레임은 다양한 유형의 데이터를 담고 있을 수 있다. 문자열, 실수, 정수, 논리값 등. 예를 들면 문자 ‘2’와 숫자 2는 전혀 다른 거다.

분석을 위해서는 값을 내가 원하는 유형으로 변경해야 하는 경우가 있다.

1) 데이터 유형 확인하기 : str()

str() 함수는 R 객체의 내부 속성을 돌려준다. 그래서 만약 데이터프레임에 포함된 데이터의 유형을 확인하고 싶다면 이렇게 쓸 수 있다.

str(df)

그러면 아래와 같이 결과가 나온다.

#> $ item: chr
#> $ price: chr
#> $ calories: num

item, price는 문자, calories는 숫자라는 걸 알 수 있다. (실제로 찍어보면 각 변수에 들어있는 값들을 예시로 보여주기도 한다.)

2) 데이터 유형 변환하기 : as.numeric()

위 예시에서 price는 가격인데 그게 문자(character)로 되어 있다. 이를 숫자로 변환해야 계산을 하든 뭘 할 거니까 숫자로 바꿔주는 게 좋다. 이럴 때는 as.numeric()을 사용한다.

df %>% mutate(price = as.numeric(price))

반대로 숫자를 문자로 바꿔주고 싶다면 as.character()를 사용하면 되겠다.


일단 데이터 전처리 작업에 대한 기초는 여기까지.

데이터 전처리는
정말 성가신 일이다.

애초에 깔끔하게 수집하면 얼마나 좋겠냐마는

추천 글


댓글 남기기