Lovetoken

저는 개발 취향을 가진 데이터 분석가 Jr. 입니다.

Navigation
 » Home
 » About Me
 » Github

R에서 readr package 의 guess_encoding() 함수를 이용한 Text 파일의 인코딩 타입 추론

07 Oct 2017 » R



파일을 읽어 들일 때 인코딩 타입에 대한 이슈는 상당히 짜증 나는 유형의 이슈 중 하나라고 생각된다.
분석환경이 단독 운영체계만을 이용하여 분석한다면 큰 문제는 없겠지만
Linux 머신이나 Mac, Windows 등으로 넘나들게 되는 순간 데이터의 인코딩 타입을 고려해야 할 것이다.
통상적으로 이럴 때는 UTF-8 인코딩으로 통일하여 관리하지만
이것이 어려울 때 2개 이상의 인코딩 타입으로 데이터가 존재하게 될 것이다.

그런데 인코딩 타입이 2개 이상 혼용되기 시작하면, 데이터를 읽어 들이고 내보내는 단계에서 인코딩타입까지 추가적으로 신경써야 한다는 점이 여러모로 피곤하게 느껴질 것이다.
데이터 I/O 단계에서 인코딩까지 신경써서 읽어들이는 것은 번거로운 일 일 수 있다.
애초에 이를 신경쓰는거 자체가 분석 본연에 있어 불필요한 요소일 수 있다.

이번 글에서는 R에서 readr package 에 있는 guess_encoding() 의 함수를 설명하고 소개할 것인데, R에서 데이터를 읽어 들이고 내보낼 시 인코딩 타입으로 인한 이슈들과 불편함을 겪는 사람들께 조금이나마 편의와 팁, 힌트를 주고자 작성한 글이다.



상황재현

d <- read.csv(text = 
  "이름, 점수
  홍길동, 80
  철수, 91
  영희, 99
  Steve, 85"
)

dir.create("data")
write.csv(d, "data/Testdata_EUC-KR.csv", fileEncoding = "EUC-KR")
write.csv(d, "data/Testdata_UTF-8.csv",  fileEncoding = "UTF-8")

위 코드는 “EUC-KR” 형과 “UTF-8” 형으로 작성된 간단한 데이터 테이블을 data 폴더안 csv 포맷으로 저장시키는 코드이다.
두개의 다른 인코딩 형의 똑같은 내용의 데이터가 2개 준비된 것이다.
이 데이터의 인코딩형의 정보를 모른다고 가정하고 R로 읽어 들일 때 어떠한 문제들이 있는지 보겠다.

csv 포맷의 데이터를 읽어들이는 방법은 여러가지가 있다.
가장 기본적인 read.csv()함수의 경우이다.

read.csv("data/Testdata_UTF-8.csv") # on Mac
##   X     이름 점수
## 1 1   홍길동   80
## 2 2     철수   91
## 3 3     영희   99
## 4 4    Steve   85

“UTF-8” 형인 데이터를 먼저 불러와 보았는데 필자는 Mac 으로 동작시켰기 때문에 정상적으로 읽어들여진다.
하지만 Windows 환경에서는 저렇게 읽어들여지지 않을 것이다.

read.csv("data/Testdata_UTF-8.csv") # on Windows
Error in make.names(col.names, unique = TRUE) : invalid multibyte string at '<ec><9d><b4>由<84>'

Windows 환경에선 이와 같은 에러가 나면서 정말 간단한 예제의 데이터 테이블임에도 불구하고 읽어들이지 못한다.
이는 read.csv() 함수가 동작할 때 내부적으로 fileEncoding 인자값이 Sys.getlocale("LC_CTYPE") 로 반환되는 환경변수값에 의존되어 실행된다.
Windows 환경에선 결과적으로 read.csv() 함수가 “CP949” 라는 인코딩형으로 읽어들이게 되고,
이 인코딩 형이 원본파일의 인코딩 형(“UTF-8”)과 불일치 하기 때문에,
한글인 변수명이 유효하지 않은 문자열로 일그러져 인식할 수 없기 때문이다.

이러한 원리 때문에 반대로 “EUC-KR” 형 데이터를 Mac 환경에서 읽어 들일 경우 마찬가지이다.

read.csv("data/Testdata_EUC-KR.csv") # on Mac
Error in make.names(col.names, unique = TRUE) : invalid multibyte string at '<c0≯<a7>'

우선 에러없이 데이터를 R로 읽어들이는 해결방법은 이렇다.

  1. 일어들일 데이터의 텍스트 인코딩형을 알아낸다.
  2. read.csv() 함수의 fileEncoding 인자값을 알아낸 인코딩형으로 직접 입력한다.
  3. 예를 들면 read.csv("data/Testdata_UTF-8.csv", fileEncoding = "UTF-8") 이런 코드가 되겠다. 이 코드를 실행하여 정상적으로 일어졌는지 확인한다.

3단계 스텝을 통해 데이터를 읽어들이는데 성공한다.
굳이 세번째 스텝을 설명한 이유는 에러없이 데이터를 일어들였다 하더라도,
첫번째 스텝에 인코딩형을 제대로 알지 못하여 막장으로 일어들여질 가능성이 있기 때문에
확인하는 과정이 필요하므로 생겨난 부수적인 스텝이라 할 수 있겠다.

여하튼 (분석을 하기도 전에) 데이터를 일어들이기 위한 이 3단계는 많은 에너지를 소모하게 만든다.



readr::guess_encoding() 함수

이제 본 글의 주제인 readr package 의 guess_encoding() 함수를 소개한다.
함수명칭에서 볼 수 있듯이 이 함수의 쓰임은 인코딩형을 추론하는 함수인데
이를 잘 이용하면 위에서 설명한 번잡한 3단계 스텝을 1스텝으로 점프할 수 있다.

우선 guess_encoding() 함수를 살펴보자.

library(readr) # for guess_encoding()

guess_encoding("data/Testdata_EUC-KR.csv")
## # A tibble: 3 x 2
##     encoding confidence
##        <chr>      <dbl>
## 1     EUC-KR       1.00
## 2    GB18030       0.71
## 3 ISO-8859-1       0.21
guess_encoding("data/Testdata_UTF-8.csv")
## # A tibble: 1 x 2
##   encoding confidence
##      <chr>      <dbl>
## 1    UTF-8          1

guess_encoding() 함수사용법은 간단하다.
외부 텍스트 파일에 대한 경로를 입력하고 실행하면 된다.
그러면 외부 텍스트파일의 인코딩형이 무엇일지 자동적으로 추론하고 가능성(confidence) 이 높은 순으로 출력된다.
“EUC-KR” 형 csv 파일을 일어들여 인코딩을 추론한 결과를 보면 “EUC-KR” 형일 가능성이 가장 높고, 그다음 “GB18030”, “ISO-8859-1” 형을 추론하는것을 볼 수 있다.
위에서 설명한 3단계 스텝에서 첫번째 스텝을 자동적으로 더 정확하게 추론함으로써 수고를 덜어준다.

read.csv("data/Testdata_EUC-KR.csv", 
         fileEncoding = guess_encoding("data/Testdata_EUC-KR.csv")[1, 1] %>% as.character)
##   X     이름 점수
## 1 1   홍길동   80
## 2 2     철수   91
## 3 3     영희   99
## 4 4    Steve   85

아예 이런 식으로 내재화시켜버리면 3단계 스텝을 거치지 않고 어떠한 운영체계, 환경이든 융통성 있게 데이터를 잘 읽어 들일 것이다.
실제로 위 코드는 필자의 Mac 에서 동작했는데도 불구하고 인코딩이슈 없이 한글을 잘 읽어 들인 것을 볼 수 있다.



맺음말

본 글은 read.csv() 함수에서 예시로 들었지만 외부 텍스트형 데이터를 읽어들이는 방법은 이 함수 말고도 다양하다.
필자는 csv 포맷 파일을 읽어들일 때 data.table::fread(), readr::read_csv() 등의 함수를 즐겨쓰는 편인데, 이 때도 마찬가지로 guess_encoding() 함수를 이용해 인코딩 형을 신경쓰지 않고 최대한 분석에 집중하고 있다.



Reference