-
R과 데이터프레임(2) : dplyrR 이모저모 2019. 3. 14. 23:46
R에서의 데이터프레임 기초와 활용방법(2)
저번 포스팅에선 R에서 데이터프레임을 생성하고 살펴보는 것을 위주로 살펴보았습니다. 이번 포스팅에서는 dplyr이라는 패키지를 활용하여 실제 분석 업무를 진행하며 어떻게 활용할 수 있는지에 대해 얘기해보도록 하겠습니다.
1. dplyr 패키지
dplyr은 데이터를 자르고 붙이는데 유용하게 쓰던 plyr패키지를 dataframe 오브젝트에 보다 유연하게 사용하도록 만든 패키지로, R에서 데이터 사이언스를 위해 소개하는 패키지 묶음들인 Tidyverse의 패키지들 중 가장 흔히 볼 수 있는 패키지이기도 합니다.
이는 dplyr이 chain function이라는 것을 제공하기 때문인데요. %>%으로 사용하는 이 함수는 앞의 결과값을 뒤의 함수에 활용할 수 있도록 해주는 역할을 합니다. 예를 들어 a,b라는 두 열을 가지는 데이터프레임을 만든 후 구조를 보기위해 str()함수를 쓰려면 str(data.frame(a=1,b=’a’)) 이렇게 써야 했으나 체인 함수를 활용하면 data.frame(a =1, b= ‘a’) %>% str 로 보다 깔끔하게 쓸 수 있습니다. 이는 한번에 처리해야하는 과정이 복잡해질수록 불필요한 객체 할당을 줄일 수 있고 코드를 순차적으로 작성할 수 있어 분석을 위한 코드 관리에 매우 유용합니다.
chain function도 유용하지만, 이를 제하고서도 dplyr는 데이터 프레임을 보다 유연히 고치고 요약하는 유용한 기능을 제공하고 있습니다. 여러가지 기능들 중 데이터 분석 및 전처리와 관련해서 쓰는 기능은 크게 데이터 선별(조건에 따라 행/열 선택), 정제(변수 생성, 변환), 병합 그리고 요약(group_by와 관련 요약기능)이 있습니다. 각 함수들은 단독으로 사용하기도 하고 상호작용을 통해 단순 루프, 코드 반복 작성 등을 거치지 않고 R을 편리하게 사용하는데 큰 도움을 줍니다.
1.1 tip : chain function에서 앞의 객체 활용하는 법
앞서 언급한 체인 함수는 기본적으로 뒤 함수의 가장 첫번째 인풋에 앞의 객체를 사용합니다. 하지만 뒤의 함수가 앞의 함수를 처음이 아닌 다른 곳에 받아야 할 경우도 있습니다. Apple이란 글자를 지우고 싶어 gsub함수를 체인을 활용하여 사용하였더니 아래와 같은 결과가 나왔습니다.
분명 전 Apple이 지워진 ‘-Rbox provides R tips’란 결과를 원했는데 “”라는 결과만 나왔습니다. 왜 이렇게 된 걸까요?
이는 gsub함수가 (지우고자 하는 패턴, 패턴을 대체하는 글자, 찾고자 하는 글자) 순으로 받기 때문입니다. 즉 저는 앞의 문장을 3번째에 넣고 싶었지만 체인은 첫 인풋으로 넣어버린 것입니다.
다행히 체인 함수는 .을 이용해 앞 객체의 위치를 지정해 줄 수 있습니다. 위 코드를 고쳐보면 다음과 같이 올바른 결과가 나오게 됩니다.
2. 데이터 선별
지난 글에서는 조건에 맞는 데이터를 찾기 위해 which 함수를 활용하여 필요한 index를 대괄호에 집어넣는 식으로 진행을 하였습니다.(ex : df[which(df$a==1),]) 이 방법도 유용하지만 변수명을 df$a와 같은 식으로 계속 지정해줘야 하는 불편함이 있습니다. 이를 보다 직관적으로 필터링 후 작업을 쉽게 하기 위해서 filter 함수를 사용합니다.
R에서 복수의 조건문을 사용하기 위해서는 and(&) 혹은 or(|) 연산자를 사용해야 하지만, filter함수의 경우 ,로 and를 대체할 수 있습니다.(단, or는 |를 사용해야함)
필터링을 성공적으로 마쳤지만 이대로 끝내기는 뭔가 아쉽습니다. 해당 조건에 맞는 데이터 중 원하는 변수만 보고 싶다면 어떻게 해야 할까요? 변수 선택을 위해서는 select 함수를 사용해야 합니다.
Select는 변수의 이름으로 데이터에서 변수를 ‘선택’하는 함수입니다. 위의 filter에서도 나왔지만 dplyr의 함수들은 대괄호에서 직접 사용하는 인덱싱과는 다르게 string 처리(‘name‘ 같이 콤마 안에 글자를 넣는 것)를 하지 않아도 글자로 인식하여 편리합니다.
2.1 tip : select나 filter를 쓸 때 데이터를 맨 앞에 두는 이유
위 코드를 보면 제가 filter를 쓸 때 filter(iris, Sepal…) 대신 iris %>% filter(…)를 사용합니다. 왜 굳이 코드를 길게 작성할까요? 이유는 간단합니다. 앞의 경우는 제가 변수명을 칠 때 자동완성을 해주지 않지만 뒤의 경우는 데이터의 속성을 읽어와서 sp만 입력해도 Species라는 변수명을 띄워 주기 때문입니다.
3. 데이터 정제
데이터를 적절한 조건에 맞게 선별하는 것도 중요하지만, 가져온 데이터에서 새 변수를 만들거나 변환하는 작업 또한 중요합니다. 앞선 글에선 해당 데이터를 불러와서 직접 할당해주거나 cbind, rbind 함수를 활용하는 방식을 사용했지만, dplyr에서는 mutate라는 함수를 이용해서 이 작업을 진행할 것입니다.
이름에서 보는 것처럼 mutate는 데이터를 바꿔버리는 작업을 수행합니다. 기존의 변수를 재정의하여 덮어버릴 수도 있으며, 없는 변수를 기존 변수 혹은 글로벌 환경에 저장되어 있는 객체를 조합하여 만들어낼 수 있습니다. 위에서 예제로 들었던 iris 데이터에서 Sepal의 length와 width를 곱한 변수 k를 만들고 싶다고 생각해 봅시다. 방법 중 하나로는 iris$k = iris$Sepal.Length * iris$Sepal.width 로 직접 할당해보는 방법이 있겠습니다. 하지만 dplyr 패키지를 활용하여 연속된 체인 내에서 작업을 하다 보면 체인을 중간에 끊어야 하기에 굉장히 불편합니다. mutate를 활용하면 보다 깔끔하게 처리할 수 있습니다.
무엇보다 mutate의 장점은 원본 데이터를 훼손하지 않고 새로운 변수를 만들어 낼 수 있다는 것입니다. 위 사진의 코드를 실행해도 iris 데이터는 그대로 있기에 k란 변수를 만들었다가 다시 없애려고 코드를 추가로 작성할 필요가 없습니다. 이는 정제라는 하나의 작업만을 수행하는 것이 아니라 복수의 작업을 수행할 때 더 빛을 발하는 성질입니다.
3.1 tip : mutate에서 객체를 변수 이름으로 사용하기
R에서 shiny를 주로 쓰시는 분은 아마 한번쯤 겪어본 문제로, 위에서 언급된 자동으로 string 처리해주는 점이 독이 되는 경우입니다. 예를 들어 제가 vname이라는 객체에 ‘apple_var’이라는 값을 할당하고 mutate를 활용해 apple_var이라는 이름을 가진 변수를 만들고 싶어서 아래와 같은 코드를 작성했다고 생각해봅시다.
예상과는 다르게 vname이라는 변수가 생성되었습니다. 이는 mutate함수가 vname을 객체가 아닌 변수명으로 인식하여서 생기는 문제로, 여러 해결법이 있지만 가장 간단한 방법은 !!vname := 으로 코드를 변경하는 것입니다.
4. To be continued…
dplyr이 tidyverse 뿐만 아니라 R 패키지들 중에서 제일 범용적이고 방대한 패키지다보니 한 포스팅에 모든 내용을 다 넣으면 글이 길어지거나 자세한 내용을 담지 못할 것 같아 다음 포스팅에서 이어서 설명해 보도록 하겠습니다.
*관련 코드는 다음 포스팅에 추가되어 있습니다.
'R 이모저모' 카테고리의 다른 글
R과 병렬처리 (4) 2019.04.03 알고리즘 소개 : XGBoost (0) 2019.03.30 R과 데이터프레임(3) (0) 2019.03.24 각양각색의 R 질문들과 풀이 (0) 2019.03.21 R과 데이터프레임 (1) (0) 2019.03.10