[R/R Studio] tidyverse 생태계 체험하기 : #1 dplyr
by 소라고동_이번 포스팅은 tidyverse 생태계 중 하나인 dplyr 에 대해서 빠르게 훑어보는 것을 목적으로 하는 게시글입니다.
0. dplyr 이란?
dplyr은 R 의 tidyverse 생태계 안에 들어있는 하나의 패키지입니다.
tidyverse 안에는 여러 패키지들이 들어있지만 dplyr은 데이터 추출, 필터링, 계산, 열 추가, 요약, 그룹화를 편리하게 할 수 있는 함수들을 제공합니다.
이러한 편리함뿐만 아니라 dplyr 에서는 연산의 상당부분을 C++ 을 이용하여 기존의 R 패키지들이 가진 속도의 문제를 해결했다고 합니다.
그렇기 때문에 dplyr 패키지를 활용한다면 보다 빠르고 편리하게 데이터를 처리할 수 있다는 장점이 있습니다.
그럼 이러한 장점을 활용하기 위해 먼저 dplyr 패키지엔 어떤한 주요 함수가 존재하는지를 살펴봅시다.
0.1. dplyr 의 주요 함수
보통 주로 사용하는 dplyr 의 주요 함수는 아래와 같습니다.
주요 함수 | 기능 | 설명 |
select | 열 선택 | 원하는 열을 선택하여 가져옵니다. |
filter | 행 필터링 | 조건을 충족하는 행의 값만 필터링하여 가져옵니다. |
gruop_by | 그룹화 | 그룹화할 열들을 지정합니다. |
summarize | 요약 | 그룹화된 열을 기준으로 합계, 평균 등의 다양한 계산을 합니다. |
mutate | 열 추가 | 그룹화, 요약된 값을 하나의 열으로 추가합니다. |
arrange | 정렬 | 오름차순/내림차순으로 정렬합니다. |
이렇게 주요 함수들을 조합하고 활용하여 데이터 처리를 하며 dplyr 패키지를 활용하게 됩니다.
이러한 함수들을 활용하기 전에 하나의 혁신적인(?) 기능을 먼저 살펴볼텐데요.
파이프라인이라고 불리는 기능에 대해 살펴보겠습니다.
0.2. 파이프라인, %>%
tidyverse 생태계를 경험하다 보면 반드시 쓰이는 기능이 있습니다.
바로 '파이프라인(%>%)'이라고 불리는 연산자인데요. (단축키 : ctrl + shift + M)
파이프라인은 tidyverse 생태계에 있는 magrittr 패키지에 들어있는 연산자입니다.
그리고 이 연산자는 R 을 굉장히 직관적으로 활용할 수 있도록 도와준다는 장점이 있습니다.
예를 들면 이런식이죠.
CO2 라는 R 기본 내장 데이터의 일부를 확인하려고 할 때, head() 라는 함수를 사용하게 됩니다.
파이프라인을 활용하지 않았을 때와 활용했을때의 차이는 아래와 같습니다.
기존의 R 코드는 head() 함수 안에 확인할 데이터프레임을 넣어주는 방식으로 이루어져있는데요.
파이프라인을 사용한다면 CO2 %>% head() 의 형태로 데이터를 확인합니다.
이 부분을 문장으로 이야기해본다면 이렇습니다.
< 기존의 R 코드 >
1. CO2 라는 데이터프레임의 첫 6개 행을 보여줘!
< 파이프라인을 활용한 R 코드 >
1. CO2 라는 데이터프레임을 기준으로
2. 첫 6개 행을 보여줘
얼핏보면 기존의 코드가 더 단순한거 아닌가? 라는 생각을 할 수 있지만 그렇지 않습니다.
파이프라인을 활용한 R 코드를 살펴보면 파이프라인 연산자로 연결된 명령어들이 순서에 따라 함수를 적용하며 원하는 결과를 도출한다는 것을 알 수 있습니다.
즉, 아무리 많은 함수를 적용한다고 하더라도 함수를 하나씩, 하나씩 덧붙이며 직관적으로 원하는 결과물을 만들어낼 수 있다는 것입니다.
이러한 장점은 코드를 작성하는 입장에서도, 코드를 해석하는 입장에서도 '직관적'이라는 느낌을 받게 되어 코드 작성 및 공유에 효율성도 높일 수 있는 기능입니다.
그렇기 때문에 우리도 tidyverse 생태계를 활용할 땐 파이프라인을 적극적으로 활용할 예정입니다.
그러면 dplyr 패키지의 주요 함수와 파이프라인을 활용하여 데이터를 정제하는 과정을 살펴봅시다.
1. dplyr 의 주요함수 기능 살펴보기
dplyr 패키지와 파이프라인 연산자에 대해 대략적으로 알게 되었다면 이 함수들을 어떻게 활용할 것인지 실습을 통해 살펴보도록 합시다.
실습에 활용한 데이터는 R 내장데이터인 CO2 데이터프레임을 활용합니다.
총 5개의 컬럼이 존재하며 Plant, Type, Treatment 를 기준으로 conc, uptake 값이 존재합니다.
단순히 dplyr 의 기능이 어떻게 적용되는지를 살펴보기 위한 단계이므로 각 컬럼이 어떤 의미를 가지는지는 고려하지 않을 예정입니다.
1.1. select()
select() 함수는 원하는 컬럼을 추출할 때 사용합니다.
< 기본적인 구조 >
- select(데이터프레임, 컬럼1, 컬럼2, .... , 컬럼n)
< 파이프라인을 활용한 구조 >
- 데이터프레임 %>% select(컬럼1, 컬럼2, ... , 컬럼n)
그래서 만약 CO2 테이블에서 Plant, Type, conc 라는 컬럼만을 가져오고 싶다면 아래와 같이 코드를 작성하면 됩니다.
CO2 %>% select(Plant, Type, uptake) %>% head()
그리고 연속된 컬럼의 경우 : 를 활용하여 더욱 간단하게 컬럼을 추출할 수 있습니다.
CO2 %>% select(2:4) %>% head()
1.2. filter()
다음으로는 원하는 행을 가져올 수 있는 filter() 함수입니다.
< 기본적인 구조 >
- filter(데이터프레임, 조건식)
< 파이프라인을 활용한 구조 >
- 데이터프레임 %>% filter(조건식)
예를들어 CO2 에서 Type 이 Quebec 인 행들만 가져오고 싶다면 아래와 같이 코드를 작성할 수 있습니다.
CO2 %>% filter(Type == 'Quebec')
그리고 중복된 조건을 적용하고 싶다면 &, | 연산자를 활용할 수 있습니다.
만약 and 조건을 적용하고 싶다면 단순하게 filter() 함수를 여러번 사용하면서 원하는 값을 만들어낼수도 있습니다.
# and, or 연산자 활용
CO2 %>% filter(Type == 'Quebec' & conc >= 500)
# filter() 함수 여러번 활용
CO2 %>%
filter(Type == 'Quebec') %>%
filter(conc >= 500)
위 두 코드는 같은 결과값을 만들어냅니다.
1.3. group_by() 와 summarize()
goupr_by() 함수는 컬럼을 기준으로 그룹화를 할 때 사용하는 함수입니다.
< 기본적인 구조 >
- group_by(데이터프레임, 그룹화 할 컬럼1, 그룹화 할 컬럼2, ... , 그룹화 할 컬럼n)
< 파이프라인을 활용할 때의 구조>
- 데이터프레임 %>% group_by(그룹화 할 컬럼1, 그룹화 할 컬럼2, ... , 그룹화 할 컬럼n)
그럼 CO2 데이터의 Type 컬럼별로 그룹화 하기 위해서 아래와 같은 코드를 작성했다고 해봅시다.
CO2 %>% group_by(Type)
그랬더니 그룹화가 된것같진 않고 기존의 CO2 데이터와 똑같이생긴 tibble 이라는 녀석이 등장합니다.
tibble 에 대해서는 차후에 설명하도록 하고 결과가 이렇게 나타난 이유에 대해 알아봅시다.
이렇게 변화없이 데이터가 출력된 이유는 당연하게도 아래와 같은 부분을 명시하지 않았기 때문입니다.
그룹화를 해서 뭘 할건데?
group_by() 함수를 이용해서 그룹화를 할 땐 어떻게 집계를 할지에 대한 부분을 명시해야 합니다.
그리고 우리는 summarize() 함수를 통해 이 부분을 명시할 수 있습니다.
summarize() 함수는 그룹화된 컬럼을 기준으로 어떠한 계산을 수행해주는 역할을 합니다.
< 기본적인 구조 >
- summarize(그룹화된 tibble, 집계함수 및 기준 컬럼)
< 파이프라인을 활용할 때의 구조>
- 데이터프레임 %>% group_by(그룹화 할 컬럼 , ...) %>% summarize(집계함수 및 기준 컬럼)
예를 들어 CO2 데이터에서 Type 컬럼을 기준으로 그룹화하여 uptake 합계를 구하는 코드를 작성했다고 합시다.
# 기존 R 코드
summarize(group_by(CO2, Type),sum(uptake))
# 파이프라인을 활용한 R 코드
CO2 %>%
group_by(Type) %>%
summarize(sum(uptake))
위의 코드에서 확인할 수 있듯 파이프라인을 사용한 코드는 굉장히 직관적입니다.
왼쪽에서 오른쪽으로, 위에서 아래로 진행되는 코드들을 순서대로 읽어나가며 코드가 어떤 의미를 가지는지 확인할 수 있기 때문입니다.
1.4. mutate()
mutate() 함수는 데이터프레임에 새로운 컬럼을 추가할 때 사용합니다.
< 기본적인 구조 >
- mutate(데이터프레임, 새로운 컬렴명 = 계산식)
< 파이프라인을 활용할 때의 구조>
- 데이터프레임 %>% mutate(새로운 컬럼명 = 계산식)
예를들어 CO2 데이터에서 uptake/conc 를 계산한 새로운 uptake_per_conc 라는 컬럼을 만드는 경우엔 아래와 같이 코드를 작성할 수 있습니다.
# 기존의 R 코드
mutate(CO2, uptake_per_conc = uptake/conc)
# 파이프라인을 활용한 R 코드
CO2 %>% group_by(Type) %>% mutate(uptake_per_conc = uptake/conc)
그 결과 이렇게 새로운 열을 간단하게 추가할 수 있습니다.
1.5. arrange()
마지막으로 arrange() 함수는 원하는 기준으로 데이터값을 정렬(오름차순, 내림차순)할 때 활용됩니다.
< 기본적인 구조 >
- arrange(데이터프레임, 정렬할 컬럼명)
< 파이프라인을 활용할 때의 구조>
- 데이터프레임 %>% arrange(정렬할 컬럼명)
예를 들어 위에서 만든 uptake_per_conc 컬럼을 기준으로 데이터를 정렬할 경우 아래와 같이 코드를 작성할 수 있습니다.
# 기존 R 코드 (오름차순)
arrange(mutate(CO2, uptake_per_conc = uptake/conc), uptake_per_conc)
# 기존 R 코드 (내림차순)
arrange(mutate(CO2, uptake_per_conc = uptake/conc), desc(uptake_per_conc))
# 파이프라인을 활용한 R 코드 (오름차순)
CO2 %>%
group_by(Type) %>%
mutate(uptake_per_conc = uptake/conc) %>%
arrange(uptake_per_conc)
# 파이프라인을 활용한 R 코드 (내림차순)
CO2 %>%
group_by(Type) %>%
mutate(uptake_per_conc = uptake/conc) %>%
arrange(desc(uptake_per_conc))
역시나 가독성과 해석력의 측면에서 파이프라인은 굉장한 효율을 보여줍니다.
2. 정리하며
이렇게 dplyr 의 주요 함수들과 파이프라인에 대해서 알아봤는데요.
결국 dplyr 의 주요 함수들은 각각 활용되는 것이 아니라 데이터 정제를 위해 함께 결합하여 활용되기 때문에 가독성을 높일 수 있는 파이프라인과 함께 사용하는 것이 효율적이라고 생각이 됩니다.
이번 포스팅에서는 아주 단순하게 dplyr 의 기능을 약간의 흐름에 따라 보여줬는데요.
다음 포스팅에서는 tidyverse 생태계의 패키지 중 tidyr 패키지에 대해서 살펴보도록 하겠습니다.
그리고 기회가 된다면 보다 실용적이고 실무적인 활용 예시도 다뤄보겠습니다!
블로그의 정보
고동의 데이터 분석
소라고동_