聰明不如鈍筆
총명불여둔필
assignment Kidult

최대한 친절하게 쓴 R로 데이터 깔끔하게 만들기(feat. tidyr)

access_time 2018.09.06 14:55

데이터 분석가들은 흔히 데이터를 정제하고 준비하는 데 전체 분석 시간 중 80%를 쓴다고 말한다(It is often said that 80% of data analysis is spent on the cleaning and preparing data).


tidyr 패키지 설명서는 이 문장으로 시작합니다. 거꾸로 이야기하면 현실에 존재하는 많은 데이터가 그만큼 컴퓨터로 처리하기 불편한 형태로 존재한다는 뜻입니다. 이런 데이터를 깔끔하게 정리하도록 도와주는 R 패키지가 바로 tidyr입니다.


R 초보자 분께는 바로 이 한 다락에도 참 어려운 낱말이 많이 들어 있습니다. 사실 R라는 이름부터 그렇습니다. tidyr라는 검색어를 인터넷 포털 사이트에 쳐서 들어오신 분이라면 물론 R가 뭔지 모르시지 않을 겁니다. 


그래도 한 번 더 확인하는 차원에서 R 홈페이지에 올라온 대로 설명드리면 R는 통계 계산과 그래픽에 활용하는 무료 소프트웨어 환경(R is a free software environment for statistical computing and graphics)"입니다.


R를 사용하고 싶으신 분은 누구든지 이 페이지에서 내려받아 설치한 뒤 사용하실 수 있습니다. 2018년 9월 현재 최신 버전은 3.5.1이며 MS 윈도용은 이 링크를 눌러 다운로드 받으시면 됩니다. 이 포스트는 '최대한 친절하게 쓴 R' 시리즈 일부지만 프로그램 설치법까지 모르시는 분이 아니 계실 것이라고 생각해 설명은 생략하겠습니다.


실제로 R를 실행하시면 아래처럼 막막한 화면이 나타납니다. 창 제목에 나온 것처럼 이 창을 흔히 'R 콘솔(Console)'이라고 부릅니다.



R 콘솔에서는 '>' 표시 뒤에 명령어를 입력하는 방식으로 코딩(컴퓨터 프로그래밍)을 진행합니다. 위에 "print('Hello, World!')라고 쓴 건 "Hello, World!"를 화면에 출력하고 싶다는 뜻입니다. 이렇게 자신이 어떤 결과를 얻고 싶다고 컴퓨터에게 알려주는 행위가 바로 코딩입니다. 이렇게 코딩을 할 수 있도록 도와주는 소프트웨어는 '프로그래밍 언어'라고 부릅니다.


이렇게 입력한 명령어는 코드(code)라고부르며, 코드를 입력하는 과정이 바로 코딩(coding)입니다. 코드를 각 프로그래밍 언어 문법에 맞도록 정리하면 프로그램을 만들 수 있습니다. 이 그림에 나온 "Hello, World!"는 코딩을 배울 때 제일 많이 쓰는 예제 프로그램입니다. 


프로그래밍 언어 가운데는 기본 기능 이외에 추가로 필요한 내용이 있을 때 이런 기능을 갖춘 '함수(명령어) 뭉치'를 내려받을 수 있도록 준비하고 있는 경우가 많습니다. 언어마다 이런 뭉치를 부르는 이름이 다른데 R에서는 이를 패키지라고 부릅니다.


우리가 이번 포스트에서 다룰 tidyr는 tidy라는 영어 낱말 뜻(깔끔한, 잘 정돈한…)처럼 자료 정제(精製)에 도움을 주는 패키지입니다. R에서 어떤 패키지를 설치하고 싶으실 때는 install.packages()라는 명령어를 쓰시면 됩니다. 우리는 tidyr를 내려받고 싶으니까 이렇게 치면 됩니다.

install.packages('tidyr')

그러면면 R는 어떤 (미러) 사이트에서 패키지를 다운받을 것인지 묻습니다. 기본적으로 어디서 받은 상관이 없으니 그냥 엔터를 치셔도 됩니다.


패키지 설치를 끝냈다고 곧바로 이 패키지에 들어 있는 함수를 활용할 수 있게 되는 건 아닙니다. 이 패키지를 메모리에 불러오는 과정이 한 번 더 필요합니다. 이때 쓰는 함수는 library()입니다.

library('tidyr')

여기까지 아무 이상 없이 진행하셨다면 이제 진짜 tidyr 패키지에 들어 있는 각종 기능을 활용할 수 있게 됐습니다. 그럼 데이터를 청소하러 가보겠습니다.



데이터 불러오기

데이터를 청소하려면 먼저 데이터가 있어야겠죠? 이번에 우리는 최근 30년(1989~2018년) 6~8월 서울 지역 평균 기온 데이터를 청소할 계획입니다. 이 데이터는 아래 CSV(Comma Separated Value·쉼표로 구분한 값) 파일에 들어있습니다.


temperature.csv


CSV 파일은 기본적으로 텍스트 파일입니다. 표에서 열에 해당하는 내용을 (이게 아니면 뭐겠어요?) 쉼표로 구분했기 때문에 이런 이름이 붙었습니다. 행은 물론 행으로 구분합니다. 컴퓨터에 마이크로소프트(MS) 엑셀이 깔려 있다면 일반 엑셀 파일을 여는 것처럼 파일 내용을 확인해 보실 수 있습니다. 아니면 그냥 메모장에서 열어보셔도 됩니다. 저는 이렇게 구글 스프레드시트로 열어봤습니다.



물론 R에서도 CSV 파일을 불러올 수 있습니다. 이때 사용하는 명령어는 read.csv()입니다. 우리가 사용할 파일 이름은 temperature.csv이니까 이렇게 치면 파일을 불러올 겁니다.

read.csv('temperature.csv')

파일을 잘 불러왔나요? 혹시 아래처럼 에러가 뜨지는 않았나요?


Error in file(file, "rt") : cannot open the connection

In addition: Warning message:

In file(file, "rt") :

  cannot open file 'temperature.csv': No such file or directory


이상한 일이 아닙니다. 파일이 어디에 그러니까 어떤 폴더에 있는지 지정하지 않았으니까요. 따로 파일 위치를 지정하지 않으면 R는 작업 디렉토리(폴더)에서 파일을 불러오도록 돼 있습니다. 기본 작업 폴더는 '내 문서'입니다. 그러니까 한 번도 작업 폴더를 바꾸신 적이 없다면 저 CSV 파일을 내 문서 안으로 옮기셔야 합니다.


아니면 작업 폴더를 바꾸는 방법도 있습니다. 가장 기본적인 방법은 메뉴에서 File - Change dir...를 선택해 바꾸시는 겁니다. 이게 간단하고 제일 쉬운 방법입니다. 지금 파일을 내려받은 위치로 작업 폴더를 바꿔보세요. 만약 명령어를 사용하는 편을 선호하신다면 'setwd()' 함수를 통해 위치를 바꾸는 것도 가능합니다.


작업 폴더 설정을 모두 마치셨다면 이제 진짜 read.csv()를 사용할 차례입니다.

read.csv('temperature.csv')

이번에는 파일 내용이 잘 보였을 겁니다. CSV 파일에서는 601~831로 되어 있던 열 이름이 X601~X831로 바뀌었다는 것 확인하셨나요? R에서는 변수 이름을 숫자로 시작할 수 없기 때문에 이렇게 앞에 X가 붙은 겁니다. 이건 문제가 아닙니다.


대신 문제가 있습니다. read.csv()는 그저 CSV 파일을 읽어서 출력하라는 뜻이기 때문에 한번 내용을 출력하고 나면 다시 쓸 수가 없습니다. 그래서 컴퓨터 메모리에 빈 방을 만들어 이 내용을 담아둘 필요가 있습니다. 이런 빈방을 코딩에서는 '변수'라고 부릅니다.


R에서 변수에 어떤 값을 넣을 때는 '<-' 또는 '=' 기호를 씁니다. 이번 포스트에서는 t라는 변수를 쓰도록 하겠습니다. 이렇게 입력하시면 됩니다.

t <- read.csv('temperature.csv')

이번에는 아무 결과도 출력하지 않았을 겁니다. 만약 내용을 확인하고 싶으시면 print(t)라고 입력하시거나 아니면 그냥 t만 치셔도 처음 read.csv('temperature.csv')라고 입력하셨을 때하고 똑같은 출력 결과를 확인하실 수 있었을 겁니다.


이제 데이터를 불러들이는 데까지 성공했으니 데이터 청소를 시작하겠습니다.



넓게 혹은 길게

데이터를 청소한다는 건 뭘까요? 그건 데이터를 깔끔하게 만든다는 뜻입니다. 그러면 깔끔한 데이터는 어떤 상태일까요? tidyr는 깔끔한 데이터를 이렇게 정의합니다.

    1. 각 변수가 열이 된다(Each Variable is in column).
    2. 각 관측이 행이 된다(Each observation is a row).
    3. 각 결과는 한 셀에 들어간다(Each value is a cell).

무슨 말인지 잘 모르시겠죠? 원래 저렇게 선언적으로 쓰는 건 대부분 그런 법이니까 너무 짜증내실 필요 없습니다. 


저 정의에 다가가려면 우리가 어떤 표를 그릴 때 크게 두 가지 방식을 쓸 수 있다는 걸 생각하시면 도움이 됩니다. 예를 들어 다섯 사람이 서로 친구인지 아닌지 표를 그린다고 가정해 봅시다. 그러면 이렇게 두 가지 방식이 가능합니다.


   가  나  다  라  마
 가
 ○    ○  
 나  ○    ○    
 다    ○    ○  ○
 라  ○    ○    ○
 마      ○  ○  


 사람1  사람2  친구
 가  나  ○
 가  라  ○
 나  다  ○
 나  마  ○
 ⁝  ⁝  ⁝

기본적으로 한 쪽은 옆으로 넓게 퍼지는 형태고 다른 한 쪽은 아래로 길게 늘어지는 형태입니다. 이 둘을 각각 와이드(wide) 포맷과 롱(long) 포맷이라고 부릅니다. 왜 이렇게 부르는지 아시겠죠?


그러면 이 둘 가운데 어느 쪽이 더 깔끔할까요? 사람 눈에는 취향에 따라 와이드 포맷이 그렇게 보일 수도 있지만 컴퓨터는 롱 포맷을 그렇게 느낍니다. 제일 큰 이유는 유연하기 때문입니다. 그러니까 데이터를 더하거나 뺄 때 손이 덜 갑니다.


만약 이 표에 '바'라는 사람을 추가한다고 생각해 봅시다. 그러면 와이드 포맷은 표 구조 자체를 바꿔야 합니다. 반면 롱 포맷에서는 그냥 행을 추가하면 그만입니다. 물론 다양한 방식으로 데이터를 처리할 때도 롱 포맷 형태가 더 수월합니다. 잘 보시면 위에서 깔끔한 데이터라고 정의한 게 결국 롱 포맷 이야기라는 걸 아실 수 있을 겁니다.


우리가 t라는 함수에 불러들인 데이터는 어떤 형태인가요? 이 데이터는 행은 30개인데 열이 93개인 와이드 포맷 데이터입니다. 따라서 데이터를 청소한다는 건 데이터 형태를 롱 포맷으로 바꾼다는 뜻과 사실상 동의어라고 해도 과언이 아닙니다.



모으고(gather), 펼치고(spread), 전하고(%>%)

R 같은 소프트웨어를 프로그래밍 언어라고 부른다고 했던 거 기억하시죠? 프로그래밍 언어도 언어는 언어이기 때문에 문법도 있고 품사도 있습니다. 그런 이유로 우리가 여태 명령어 또는 함수라고 불렀던 개념을 동사라고 부르기도 합니다.


tidyr 패키지에서 제일 중요한 동사 두 가지는 gather()와 spread()입니다.  gather()는 와이드 포맷 데이터를 롱 포맷으로, spread()는 롱 포맷을 와이드 포맷으로  바꾸는 구실을 합니다. 이 포스트 맨 첫 이미지에서 tidyr 아이콘이 회전하는 느낌인 건 그런 까닭입니다.


t는 와이드 포맷이니까 롱 포맷으로 바꿔봐야겠죠? 그래서 그냥 이렇게 한번 쳐보겠습니다.

gather(t) %>% head()

##    key   value

## 1 연도  1989

## 2 연도  1990

## 3 연도  1991

## 4 연도  1992

## 5 연도  1993

## 6 연도  1994


신기한 게 많이 등장했습니다. 일단 gather(t)는 t라는 데이터를 롱 포맷으로 바꾸라는 뜻일 겁니다. 얼핏 그렇게 바꾼 것처럼 보입니다.


이어서 등장하는 '%>%'는 파이프(pipe) 연산자라고 부릅니다. 현실 세계에 존재하는 파이프는 액체나 기체를 한 곳에서 다른 곳으로 전달하는 구실을 합니다. 코딩에서도 한 데이터를 다른 데이터로 전달하면 편리할 때가 있습니다. 그럴 때 쓰는 기능이 바로 파이프이고, R에서는(정확하게는 tidyr 패키지를 포함하는 tidyverse 생태계에서는) 이를 %>%로 표시하는 겁니다. 그래서 위에 있는 코드는 gather(t)를 한 데이터를 'head()'라는 함수로 전달하라는 뜻이 됩니다.


파이프가 없다면 이 코드는 이렇게 쓰면 됩니다.

head(gather(t))

이번에는 코드가 간단해서 파이프를 쓰는 게 오히려 더 복잡해 보일지도 모르는 게 사실. 그래도 코드가 길어지면 길어질수록 파이프가 훨씬 편하다는 걸 느끼게 되실 겁니다. 직관적으로 코드를 이해할 수 있다는 점에서도 파이프는 좋은 도구입니다.  


head()는 어떤 데이터가 있을 때 처음 여섯 줄(행)만 보여달라는 뜻입니다. 위에서 여섯 줄만 나온 이유입니다. 이 함수는 원래 head(데이터, 보고 싶은 행 숫자) 형태로 씁니다. 보고 싶은 행 숫자를 따로 입력하지 않으면 기본적으로 여섯 줄이 나오는 방식입니다.


거꾸로 'tail()'이라는 함수도 있습니다. 이건 뒤에서 몇 번째 행까지 보여달라는 뜻입니다. 이번에는 다섯 줄만 볼까요? 위에서는 파이프를 쓸 때 첫 번째 함수에는 그 안에 데이터를 넣어줬지만 처음부터 이렇게 쓸 수도 있습니다.

t %>% gather() %>% tail(5)

##           key     value

## 2786 X831  24.1

## 2787 X831  25.9

## 2788 X831  17.7

## 2789 X831  22.2

## 2790 X831  25.6


뭔가 이상한 것 눈치채셨나요? 앞 부분에는 value 열에 연도가 들어 있는데 뒷 부분에는 기온이 들어 있습니다. 이러면 코드가 잘못됐다는 뜻입니다.


또 gather를 쓰면 key와 value라는 열로 데이터를 정리한다는 걸 알 수 있습니다. 이번에는 자동으로 나왔지만 어떤 변수가 key가 되고 어떤 변수가 value가 될지 따로 지정할 수도 있습니다. 우리는 날짜별 평균 기온을 롱 포맷으로 정리하고 싶은 거니까 이렇게 쓸 수 있습니다.

t %>% gather(key='날짜', value='온도') %>% head()

##    날짜  온도

## 1 연도 1989

## 2 연도 1990

## 3 연도 1991

## 4 연도 1992

## 5 연도 1993

## 6 연도 1994


열 이름이 날짜와 온도로 바뀌기는 했지만 문제는 그대로입니다. 이런 일이 생기는 건 X603~X831 열에 들어 있는 자료만 정리해야 한다는 사실을 tidyr에게 알려주지 않았기 때문입니다.


R에서는 어떤 자료를 연속으로 표시할 때 ':' 기호를 씁니다. 지금 콘솔에 '1:5'라고 한번 입력해 보세요. 그러면 '[1] 1 2 3 4 5'라고 결과가 뜰 겁니다. 그러면 X601~X831은 'X601:X831'이라고 쓰면 될 겁니다. 이 내용을 넣어주도록 하겠습니다.

t %>% gather(날짜, 온도, X601:X831) %>% head()

##     연도   날짜   온도

## 1 1989 X601 20.5

## 2 1990 X601 15.0

## 3 1991 X601 19.6

## 4 1992 X601 22.0

## 5 1993 X601 24.7

## 6 1994 X601 20.4


드디어 원하는 결과가 나왔습니다. 이번에는 코드가 처음 쓴 것하고 또 다릅니다. "key='날짜'"라고 썼던 걸 그냥 "날짜"라고만 썼고, "온도"도 마찬가지입니다. 순서만 지켜주면 굳이 저런 속성을 다 쓸 필요가 없던 겁니다.


이 코드를 조금 더 줄일 수도 있습니다. X601~X831 열에서만 자료를 뽑아 내라는 건 '연도' 열만 제외하고 자료를 가져가라는 것과 똑같은 뜻입니다. 이렇게 특정한 자료만 빼고 싶을 때는 열 이름 앞에 '-'를 붙이면 됩니다. 이번에는 뒤쪽을 볼까요?

t %>% gather(날짜, 온도, -연도) %>% tail()

##           연도    날짜   온도

## 2755 2013 X831 24.0

## 2756 2014 X831 24.1

## 2757 2015 X831 25.9

## 2758 2016 X831 17.7

## 2759 2017 X831 22.2

## 2760 2018 X831 25.6


이렇게 나온 결과도 새 데이터로 만들 수 있겠죠? 이 데이터를 tl이라는 변수에 넣어놓고 다시 펼쳐보는 연습을 하도록 하겠습니다.

tl <- t %>% gather(날짜, 온도, -연도)

펼칠 때 쓰는 동사는 spread()입니다. 이번에도 일단 그냥 동사 적용부터.

tl %>% spread()

Error in eval_tidy(enquo(var), var_env) : object '' not found


걱정하실 것 없습니다. tl에는 열이 세 개(연도, 날짜, 온도) 있는데 어떤 게 key고 어떤 게 value인지 알려주지 않아서 생긴 일입니다.

tl %>% spread(날짜, 온도)

이렇게 입력하시면 우리가 처음 본 것과 똑같은 데이터 포맷으로 돌아간 걸 확인하실 수 있을 겁니다. 


tidyr에는 gather()와 spread() 말고도 한 열을 여럿으로 나누는 separate() 그리고 반대로 한 열로 합치는 unite() 동사도 들어 있습니다. 경우에 따라 필요하신 분은 활용하시면 되겠습니다.



이렇게 바꾸는 게 뭐가 좋은데?

그런데 정말 와이프 포맷 데이터 롱 포맷으로 바꾸는 게 효과가 있을까요? 이 데이터를 가지고 날짜별 평균 기온 산포도(scatter plot)를 그린다고 해보겠습니다. 어떻게 그릴 수 있을까요?


R에서 제일 유명한 시각화 패키지는 (역시 tidyverse 생태계에 속한) ggplot2입니다. ggplot2가 익숙하지 않으신 분이라면 '최대한 친절하게 쓴 R로 그래프 그리기(feat. ggplot2)'를 한번 읽고 오셔도 좋습니다. 어떻게 그려야 할까요?


MS 엑셀에서는 문제가 되지 않습니다. 그냥 데이터를 전부 선택해서 그래프를 그리면 됩니다. 그런데 R에서 어떤 열이 x축에 와야 하고, 어떤 값이 y 축을 차지해야 하는지 알려주기가 쉽지 않습니다. 


롱 포맷일 때는 이런 고민이 없습니다. x축에는 날짜가 오면 되고, y축에는 온도가 오면 됩니다. 파이프까지 합쳐서 쓰면 그냥 이렇게 쓰면 우리가 원하는 산포도를 얻을 수 있습니다.

tl %>% ggplot() + geom_point(aes(x=날짜, y=온도))


이 코드를 응용하면 '2018년 더위, 1994년 여름에 TKO승' 포스트에 넣었던 이런 그래프도 그릴 수 있습니다. 



다시 본론으로 돌아가겠습니다. 만약 30년 동안 8월 15일 평균 기온이 어떻게 바뀌었는지 그래프를 그리려고 한다면 어떻게 하면 될까요? 한번 콘솔에 "t$X815"라고 쳐보시죠.

t$X815

##   [1] 26.6 26.4 28.6 21.0 22.4 30.3 29.1 26.3 27.4 24.1 28.8 28.3 25.2 24.2

## [15] 24.7 26.7 27.2 28.2 26.4 25.7 27.9 26.6 24.5 23.7 28.7 24.9 27.1 29.1

## [29] 21.9 31.7


그러면 이렇게 연도별 기온이 나옵니다. '$' 표시는 데이터 프레임(Data Frame) 형태로 된 자료에서 특정 열을 뽑아 오라고 컴퓨터에게 알려주는 구실을 합니다. 데이터 프레임은 MS 엑셀이 자료를 다루는 것처럼 표 형태 데이터 구조라고 생각하시면 됩니다. 


이걸 그래프로 나타내려면 다시 각 연도에 해당하는 열을 만들어 결합해야 합니다. 롱 포맷에서는 이렇게 쓰면 끝입니다.

tl[tl$날짜=='X815', ] %>% head()
##           연도   날짜   온도
## 2251 1989 X815 26.6
## 2252 1990 X815 26.4
## 2253 1991 X815 28.6
## 2254 1992 X815 21.0
## 2255 1993 X815 22.4
## 2256 1994 X815 30.3


이렇게 쓰면 그래프까지 한번에 끝이 납니다.

tl[tl$날짜=='X815', ] %>% ggplot() + geom_line(aes(x=연도, y=온도))


또 이상한 게 등장했습니다. 어떤 데이터 프레임 이름 뒤에 '[행, 열]' 순서로 쓰면 해당 데이터만 뽑아내 알려줍니다. 아래에서 확인하실 수 있는 것처럼 tl이라는 데이터 프레임에서 첫 번째 행, 두 번째 열에 있는 데이터는 X601이고 tl[1, 2]라고 치면 바로 그 값을 출력합니다.

tl %>% head()

##     연도  날짜   온도

## 1 1989 X601 20.5

## 2 1990 X601 15.0

## 3 1991 X601 19.6

## 4 1992 X601 22.0

## 5 1993 X601 24.7

## 6 1994 X601 20.4

tl[1, 2]

[1] "X601"


이번에는 행에 "tl$날짜=='X815'"라고 썼습니다. 이건 날짜에 X815가 들어 있는 행만 골라달라는 뜻입니다. R에서 =는 어떤 변수에 값을 넣으라는 뜻이기 때문에 같다고 할 때 '=='라고 쓰는 겁니다.


롱 포맷이 확실히 더 편하지 않습니까? 이런 이유로 어떻게 보면 큰 기능을 갖추지도 않은 것처럼 보이는 tidyr 패키지가 세상에 존재할 수 있는 겁니다. 



tidyr 짝꿍 dplyr도 부르자

이게 전부라니 어쩐지 좀 심심한 느낌도 듭니다. 사실 tidyr는 데이터 처리를 담당하는 dplyr 패키지와 짝을 이룰 때 더 큰 위력을 발휘합니다. 아직 dplyr 패키지를 깔지 않으셨다면 설치하고 불러오는 과정부터 거쳐야겠죠?

install.packages('dplyr')
library('dplyr')

dplyr를 쓰면 위에서 설명 드린 코드를 더 직관적으로 쓸 수 있습니다. dplyr 패키지에서 특정한 행을 선택하는 동사는 filter()입니다. 위처럼 똑같이 8월 15일 평균 기온만 뽑아보고 싶으시면 이렇게 입력하시면 됩니다.

tl %>% filter(날짜=='X815') %>% head()

##           연도   날짜   온도

## 2251 1989 X815 26.6

## 2252 1990 X815 26.4

## 2253 1991 X815 28.6

## 2254 1992 X815 21.0

## 2255 1993 X815 22.4

## 2256 1994 X815 30.3


이번에는 dplyr 패키지 동사 가운데 행열 전체를 더하고 빼는 부분만 살펴볼 것이기 때문에 dplyr에서 쓰는 동사에 대해서는 자세히 말씀드리지 않겠습니다. dplyr에 대해 자세하고 알고 싶으신 분은 '최대한 친절하게 쓴 R로 데이터 뽑아내기(feat. dplyr)'를 참고하시면 도움이 될 수 있습니다. 


결론부터 말씀드리면  행을 더할 때는 bind_rows(), 열을 더할 때는 bind_cols()를  쓰시면 됩니다.


언제 이 두 동사를 쓸까요? 우리가 지금 쓰고 있는 데이터를 기준으로 말씀드리면 1988년 날짜별 평균 데이터를 추가할 때 bind_rows()를 쓰게 됩니다. 만약 기온 말고 습도도 추가하고 싶다면 이번에는 bind_cols()가 정답입니다.


실제 이런 방식으로 데이터를 결합하면 어떤 일이 벌어지는지 한번 알아보겠습니다. 아래는 같은 기간, 같은 지역 습도 데이터를 담은 CSV 파일입니다.


humidity.csv


이제 파일을 불러와서 롱 포맷으로 바꾸는 것까지는 잘 아시리라 믿고 쭉쭉 진행하겠습니다. 

h <- read.csv('humidity.csv')
hl <- h %>% gather(날짜, 습도, -연도)
tl %>% bind_cols(hl) %>% head()

##     연도   날짜   온도   연도1   날짜1  습도

## 1 1989 X601 20.5  1989  X601   56

## 2 1990 X601 15.0  1990  X601   89

## 3 1991 X601 19.6  1991  X601   63

## 4 1992 X601 22.0  1992  X601   54

## 5 1993 X601 24.7  1993  X601   53

## 6 1994 X601 20.4  1994  X601   51


비슷하기는 한데 원하는 결과하고는 다릅니다. 두 데이터 프레임을 통째로 더하다 보니 연도와 날짜가 중복해서 들어갔습니다. 이걸 빼주려면 어떻게 해야 할까요?


많은 방법이 있지만 우리는 dplyr를 다루고 있으니 원하는 열을 선택하는 select() 함수를 쓰겠습니다. 이렇게 입력하면 됩니다.


tl %>% bind_cols(hl) %>% select(-연도1, -날짜1) %>% head()

##     연도  날짜    온도   습도

## 1 1989 X601 20.5   56

## 2 1990 X601 15.0   89

## 3 1991 X601 19.6   63

## 4 1992 X601 22.0   54

## 5 1993 X601 24.7   53

## 6 1994 X601 20.4   51


이렇게 쓰고 나니까 데이터가 또 와이드 포맷으로 바뀐 느낌적인 느낌이 듭니다. 다시 롱 포맷으로 바꾸겠습니다.

tl %>% 
bind_cols(hl) %>%;
select(-연도1, -날짜1) %>%
gather(구분, 값, -연도, -날짜) %>%
head()

##    연도   날짜    구분    값

## 1 1989 X601 온도 20.5

## 2 1990 X601 온도 15.0

## 3 1991 X601 온도 19.6

## 4 1992 X601 온도 22.0

## 5 1993 X601 온도 24.7

## 6 1994 X601 온도 20.4


이번에는 코드도 롱 포맷으로 바꿔 봤습니다. 이렇게 쓰면 코드를 좀더 직관적으로 이해하는 데도 도움이 되지 않나요?



다 돌려놔~

어떤가요? tidyr와 dplyr를 합치니까 확실히 데이터를 처리하는 방식이 좀 더 이해 가능한 방향으로 변하지 않았나요? 그래도 여전히 복잡하다고요? 실전(?)은 더합니다. 이번에는 R 공부에 필요한 형태로 미리 데이터를 정리했기 때문에 그나마 수월하다고 할 수 있습니다.


만약 사람들에게 자기 전화번호를 적어 달라고 하면 대부분 '01X-####-####' 형태로 적어주겠지만 누군가는 01X####### 이렇게 적어줄 수도 있고 (01X) #### - #### 이런 식으로 적어주는 사람이 나올 수도 있습니다.


여기 더해서 주소까지 적어달라고 하면 같은 칸에 적는 사람, 다른 칸에 적는 사람이 따로 나올 거고, 누군가는 지번 주소를 쓰는 반면 누군가는 도로명 주소를 적어줄 겁니다. 이렇게 같은 내용을 담고 있는 데이터가 서로 다른 형태로 들어올 때 tidyr와 dplyr 도움을 받으면 그나마 문제를 조금 쉽게 해결할 수 있습니다.


이 포스트는 tidyr를 다루는 내용이었으니까 이렇게 결론을 내려도 무방할 겁니다. 데이터가 어떻게 들어오든 결국에는 모두 롱 포맷 형태로 돌려놓아야 다음 단계로 진행할 수 있게 된다고 말입니다.


긴 글 읽어주시느라 고생하셨습니다. 이 포스트에서 이해가 가지 않거나 잘못된 내용이 있다면 언제든 알려주세요. 함께 공부하면서 바로잡도록 하겠습니다.


댓글, 0

account_circle
vpn_key
web

security

mode_edit
Kidult | 카테고리 다른 글 더 보기