고동의 데이터 분석

[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 데이터프레임을 활용합니다.

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 패키지에 대해서 살펴보도록 하겠습니다.

 

그리고 기회가 된다면 보다 실용적이고 실무적인 활용 예시도 다뤄보겠습니다!

블로그의 정보

고동의 데이터 분석

소라고동_

활동하기