Chapter 4 데이터 변환

이 장에서는 정돈 형식의 데이터를 변환하는 방법을 배운다.

4.1 정돈 데이터 (tidy data)

4.1.1 정돈 데이터 형식의 조건

정돈 데이터란 다음 조건을 만족하는 데이터 행렬(R에서는 데이터 프레임)의 형식을 의미한다.

  • 데이터 행렬의 각 행과 관측(대상)(observations)은 일대일의 관계이다.
  • 데이터 행렬의 각 열과 변수(variables)는 일대일의 관계이다.
  • 측정값(values)은 각 셀과 일대일의 관계이다.

정돈 데이터 형식을 그림 4.1처럼 표현할 수 있다.

정돈 데이터

Figure 4.1: 정돈 데이터

4.1.2 비정돈 데이터 형식

현실에서 만나는 많은 데이터가 정돈 데이터 형식이지만, 그렇지 않은 데이터도 자주 볼 수 있다. 그림 4.2의 왼쪽 데이터는 어떤 가상의 감염병에 대해 세 나라의 발생 사례를 월별로 정리한 데이터이다. 이 데이터는 감염 사례라는 변수와 관련된 데이터가 3개의 열에 흩어져 있으므로 비정돈 형식이다. 월별, 년도별 매출처럼 시계열 데이터는 종종 이런 형식으로 데이터가 표현된다. 이러한 방식의 표현은 데이터를 매우 압축적인 방식으로 표현할 수 있고 같은 시간대의 데이터를 비교하기 쉬운 장점이 있다.

그림 4.2의 오른쪽 데이터는 왼쪽 데이터를 정돈 형식으로 변환한 결과이다. 이러한 변환을 하는 방법에 대해서는 6.3 절에서 다룰 것이다.

비정돈 데이터

Figure 4.2: 비정돈 데이터

4.1.3 정돈 데이터를 사용하는 이유

그림 4.2를 보면 정돈 형식 데이터가 오히려 비효율적인 방식으로 보이며, 데이터를 한 눈에 비교하기도 어려워 보인다. 그럼에도 정돈 형식의 데이터를 사용하는 이유는 표준화된 데이터 변환 작업을 하기 위해서이다.

한 행이 하나의 관측 대상을, 한 열이 하나의 변수를, 한 셀이 한 값을 나타낸다는 가정이 성립하면, 데이터 변환이나 데이터를 이용한 그래픽 작업을 데이터의 내용에 무관하게 항상 일정한 형식으로 수행할 수 있다.

4.2 tidyverse 패키지

tidyverse 패키지는 정돈 데이터 패러다임을 따른 R 패키지들을 한번에 설치하고 적재할 수 있도록 돕는 패키지이다.

4.2.1 tidyverse 패키지 설치

tidyverse 패키지를 설치하려면 다음 명령을 실행하면 된다. 패키지의 이름은 문자열이므로 따옴표 안에 기술해야 한다.

> install.packages("tidyverse")

또는 RStudio의 Packages 탭에서 [Install]을 클릭한 후 tidyverse라고 입력을 하면 된다. 패키지 설치는 한 번만 수행하면 된다.

4.2.2 tidyverse 패키지 적재

tidyverse 패키지가 설치되었으면 패키지를 사용할 때마다 네임스페이스를 적재하고 검색 리스트에 패키지를 포함하는 작업이 필요하다.3 다음은 tidyverse 패키지를 적재하는 명령어이다. 이번에는 패키지 이름에 따옴표가 없음에 주의한다.

> library(tidyverse)

앞의 명령을 실행하면 정돈 데이터 패러다임을 따르는 여러 개의 패키지가 동시에 적재된다. 그리고 R 기본 패키지와 정돈 데이터 패키지 중에서 이름이 충돌이 나는 것에 대해 보고를 한다. 만약 R 기본 패키지에서 이 함수를 사용하는 경우에는 패키지이름::함수() 형식으로만 사용할 수 있다. 자세한 내용은 R 관련 책을 참조하기 바란다.

4.3 dplyr 패키지와 정돈 데이터의 변환

4.3.1 dplyr 패키지

정돈 데이터의 변환에는 tidyverse 패키지가 포함하고 있는 dplyr 패키지가 이용된다. 앞에서 tidyverse를 적재하였으면 이미 dplyr이 적재되어 있으므로 다시 적재할 필요가 없다.

4.3.2 정돈 데이터 변환의 종류

dplyr 패키지가 수행하는 정돈 데이터의 변환은 크게 5가지 변환 작업이 있다.

  • filter(): 데이터에서 관측(대상)을 측정값을 기준으로 선택한다.
  • arrange(): 관측(대상)을 기준으로 데이터를 정렬한다.
  • select(): 열 이름으로 일부 열만 데이터에서 선택한다.
  • mutate(): 기존 열을 사용하여 새로운 열을 데이터에 추가한다.
  • summarize(): 여러 측정치를 하나의 통계량으로 요약한다.

그리고 위의 작업은 group_by() 함수와 같이 사용되어 전체 데이터에서 작업이 수행되는 것이 아니라 관측(대상)의 그룹별로 수행되도록 조정할 수 있다. Figure 4.3dplyr 패키지가 수행하는 정돈 데이터의 변환의 예를 보여준다.

정돈데이터의 변환

Figure 4.3: 정돈데이터의 변환

일반적으로 데이터의 변환 작업은 위의 6가지 작업이 여러 차례 순서대로 결합하여 진행된다.

4.3.3 mpg 데이터

이 장에서는 ggplot2 패키지에서 제공하는 mpg 데이터를 이용하여 정돈 데이터를 변환하는 함수를 설명한다.

다음 명령을 이용하여 mpg 데이터를 출력해 보자. 화면의 크기에 따라 출력되는 내용이 책과는 조금 다를 수 있다.

> mpg
# A tibble: 234 x 11
   manufacturer model    displ  year   cyl trans   drv     cty   hwy fl    class
   <chr>        <chr>    <dbl> <int> <int> <chr>   <chr> <int> <int> <chr> <chr>
 1 audi         a4         1.8  1999     4 auto(l… f        18    29 p     comp…
 2 audi         a4         1.8  1999     4 manual… f        21    29 p     comp…
 3 audi         a4         2    2008     4 manual… f        20    31 p     comp…
 4 audi         a4         2    2008     4 auto(a… f        21    30 p     comp…
 5 audi         a4         2.8  1999     6 auto(l… f        16    26 p     comp…
 6 audi         a4         2.8  1999     6 manual… f        18    26 p     comp…
 7 audi         a4         3.1  2008     6 auto(a… f        18    27 p     comp…
 8 audi         a4 quat…   1.8  1999     4 manual… 4        18    26 p     comp…
 9 audi         a4 quat…   1.8  1999     4 auto(l… 4        16    25 p     comp…
10 audi         a4 quat…   2    2008     4 manual… 4        20    28 p     comp…
# … with 224 more rows

mpg는 1999년과 2008년에 미국 EPA에서 조사하여 발표한 자동차 주요 모델별 연비 데이터이다. 데이터는 234 개의 행이 있으며, 각 행은 다음과 같은 열로 구성되어 있다.

  • manufacturer: 자동차 제조사
  • model: 자동차 모델명
  • displ: 자동차 배기량
  • year: 제조년도
  • cyl: 엔진 실린더 수
  • trans: 자동차 트랜스미션 종류
  • drv: 자동차 구동 방식. f=전륜구동, r=후륜구동, 4=사륜구동
  • cty: 도심 연비 (마일/갤론)
  • hwy: 고속도로 연비 (마일/갤론)
  • fl: 연료 종류
  • class: 자동차 분류

4.4 filter()로 행 선택하기

4.4.1 선택 조건이 하나인 경우

선택 조건이 하나인 경우 다음 형식으로 filter()를 사용한다.

filter(데이터프레임, 조건)

’데이터프레임’에는 filter()를 적용할 데이터 프레임을 ’조건’에는 행 선택 조건을 기술한다. ’조건’은 논리값 벡터이어야 한다. 많은 경우 ’조건’은 다음처럼 열과 어떤 값을 비교연산자로 비교한다.

> filter(mpg, manufacturer=="hyundai")
# A tibble: 14 x 11
   manufacturer model  displ  year   cyl trans   drv     cty   hwy fl    class  
   <chr>        <chr>  <dbl> <int> <int> <chr>   <chr> <int> <int> <chr> <chr>  
 1 hyundai      sonata   2.4  1999     4 auto(l… f        18    26 r     midsize
 2 hyundai      sonata   2.4  1999     4 manual… f        18    27 r     midsize
 3 hyundai      sonata   2.4  2008     4 auto(l… f        21    30 r     midsize
 4 hyundai      sonata   2.4  2008     4 manual… f        21    31 r     midsize
 5 hyundai      sonata   2.5  1999     6 auto(l… f        18    26 r     midsize
 6 hyundai      sonata   2.5  1999     6 manual… f        18    26 r     midsize
 7 hyundai      sonata   3.3  2008     6 auto(l… f        19    28 r     midsize
 8 hyundai      tibur…   2    1999     4 auto(l… f        19    26 r     subcom…
 9 hyundai      tibur…   2    1999     4 manual… f        19    29 r     subcom…
10 hyundai      tibur…   2    2008     4 manual… f        20    28 r     subcom…
11 hyundai      tibur…   2    2008     4 auto(l… f        20    27 r     subcom…
12 hyundai      tibur…   2.7  2008     6 auto(l… f        17    24 r     subcom…
13 hyundai      tibur…   2.7  2008     6 manual… f        16    24 r     subcom…
14 hyundai      tibur…   2.7  2008     6 manual… f        17    24 r     subcom…
> filter(mpg, cty > 28)
# A tibble: 3 x 11
  manufacturer model   displ  year   cyl trans   drv     cty   hwy fl    class  
  <chr>        <chr>   <dbl> <int> <int> <chr>   <chr> <int> <int> <chr> <chr>  
1 volkswagen   jetta     1.9  1999     4 manual… f        33    44 d     compact
2 volkswagen   new be…   1.9  1999     4 manual… f        35    44 d     subcom…
3 volkswagen   new be…   1.9  1999     4 auto(l… f        29    41 d     subcom…
> filter(mpg, cty >= 28)
# A tibble: 5 x 11
  manufacturer model   displ  year   cyl trans   drv     cty   hwy fl    class  
  <chr>        <chr>   <dbl> <int> <int> <chr>   <chr> <int> <int> <chr> <chr>  
1 honda        civic     1.6  1999     4 manual… f        28    33 r     subcom…
2 toyota       corolla   1.8  2008     4 manual… f        28    37 r     compact
3 volkswagen   jetta     1.9  1999     4 manual… f        33    44 d     compact
4 volkswagen   new be…   1.9  1999     4 manual… f        35    44 d     subcom…
5 volkswagen   new be…   1.9  1999     4 auto(l… f        29    41 d     subcom…

조건을 서술할 때 자주 틀리는 부분이 등호 기호로 =를 사용하는 것이다. R에서 두 값이 같은지를 비교할 때는 ==를 사용한다.

다음처럼 열에 연산을 수행한 후에 그 결과와 비교할 수도 있다.

> filter(mpg, cty * 2 > 60)
# A tibble: 2 x 11
  manufacturer model   displ  year   cyl trans   drv     cty   hwy fl    class  
  <chr>        <chr>   <dbl> <int> <int> <chr>   <chr> <int> <int> <chr> <chr>  
1 volkswagen   jetta     1.9  1999     4 manual… f        33    44 d     compact
2 volkswagen   new be…   1.9  1999     4 manual… f        35    44 d     subcom…
> filter(mpg, sqrt(cty) < 3.2)
# A tibble: 5 x 11
  manufacturer model      displ  year   cyl trans  drv     cty   hwy fl    class
  <chr>        <chr>      <dbl> <int> <int> <chr>  <chr> <int> <int> <chr> <chr>
1 dodge        dakota pi…   4.7  2008     8 auto(… 4         9    12 e     pick…
2 dodge        durango 4…   4.7  2008     8 auto(… 4         9    12 e     suv  
3 dodge        ram 1500 …   4.7  2008     8 auto(… 4         9    12 e     pick…
4 dodge        ram 1500 …   4.7  2008     8 manua… 4         9    12 e     pick…
5 jeep         grand che…   4.7  2008     8 auto(… 4         9    12 e     suv  

4.4.2 여러 조건을 만족하는 행 추출하기

두 개 이상의 조건을 모두 만족하는 행만 뽑아내려면 다음의 문법을 사용한다.

filter(데이터프레임, 조건1, 조건2, ..., 조건n)

다음은 현대에서 생산한 차 중 도심 연비가 20 마일 이상인 차만 추출한 결과이다.

> filter(mpg, manufacturer=="hyundai", cty >= 20)
# A tibble: 4 x 11
  manufacturer model  displ  year   cyl trans    drv     cty   hwy fl    class  
  <chr>        <chr>  <dbl> <int> <int> <chr>    <chr> <int> <int> <chr> <chr>  
1 hyundai      sonata   2.4  2008     4 auto(l4) f        21    30 r     midsize
2 hyundai      sonata   2.4  2008     4 manual(… f        21    31 r     midsize
3 hyundai      tibur…   2    2008     4 manual(… f        20    28 r     subcom…
4 hyundai      tibur…   2    2008     4 auto(l4) f        20    27 r     subcom…

앞의 조건에서 배기량이 2.4 이상인 차만 추출해 보자.

> filter(mpg, manufacturer=="hyundai", cty >= 20, displ >= 2.4)
# A tibble: 2 x 11
  manufacturer model  displ  year   cyl trans     drv     cty   hwy fl    class 
  <chr>        <chr>  <dbl> <int> <int> <chr>     <chr> <int> <int> <chr> <chr> 
1 hyundai      sonata   2.4  2008     4 auto(l4)  f        21    30 r     midsi…
2 hyundai      sonata   2.4  2008     4 manual(m… f        21    31 r     midsi…

4.4.3 논리 연산자로 복합 조건 만들기

지금까지는 하나의 조건이나 여러 조건을 동시에 만족하는 행을 추출하는 방법을 보았다. 어떤 경우에는 여러 조건 중 하나라도 만족하면 그 행을 추출해야 할 경우가 있다. 이러한 경우에는 2 장에서 배운 논리 연산자를 이용하여 복합 조건을 만들어야 한다.

다음은 OR 연자자인 |를 이용하여 두 조건 중 하나만 만족하여도 행이 추출되도록 하였다.

> filter(mpg, model=="sonata" | cty >= 28)
# A tibble: 12 x 11
   manufacturer model   displ  year   cyl trans   drv     cty   hwy fl    class 
   <chr>        <chr>   <dbl> <int> <int> <chr>   <chr> <int> <int> <chr> <chr> 
 1 honda        civic     1.6  1999     4 manual… f        28    33 r     subco…
 2 hyundai      sonata    2.4  1999     4 auto(l… f        18    26 r     midsi…
 3 hyundai      sonata    2.4  1999     4 manual… f        18    27 r     midsi…
 4 hyundai      sonata    2.4  2008     4 auto(l… f        21    30 r     midsi…
 5 hyundai      sonata    2.4  2008     4 manual… f        21    31 r     midsi…
 6 hyundai      sonata    2.5  1999     6 auto(l… f        18    26 r     midsi…
 7 hyundai      sonata    2.5  1999     6 manual… f        18    26 r     midsi…
 8 hyundai      sonata    3.3  2008     6 auto(l… f        19    28 r     midsi…
 9 toyota       corolla   1.8  2008     4 manual… f        28    37 r     compa…
10 volkswagen   jetta     1.9  1999     4 manual… f        33    44 d     compa…
11 volkswagen   new be…   1.9  1999     4 manual… f        35    44 d     subco…
12 volkswagen   new be…   1.9  1999     4 auto(l… f        29    41 d     subco…

만약 위의 결과에서 2008년도 데이터만 추출하고 싶다면 어떻게 해야 할까? 다음처럼 두 조건식을 사용하여 첫 번째 조건과 두 번째 조건을 모두 만족하는 결과만 추출할 수도 있고, 하나의 조건식에 AND 연산자인 &를 사용하여 복합 조건식을 사용하여 추출할 수도 있다.

> filter(mpg, model=="sonata" | cty >= 28, year==2008)
# A tibble: 4 x 11
  manufacturer model   displ  year   cyl trans    drv     cty   hwy fl    class 
  <chr>        <chr>   <dbl> <int> <int> <chr>    <chr> <int> <int> <chr> <chr> 
1 hyundai      sonata    2.4  2008     4 auto(l4) f        21    30 r     midsi…
2 hyundai      sonata    2.4  2008     4 manual(… f        21    31 r     midsi…
3 hyundai      sonata    3.3  2008     6 auto(l5) f        19    28 r     midsi…
4 toyota       corolla   1.8  2008     4 manual(… f        28    37 r     compa…
> filter(mpg, (model=="sonata" | cty >= 28) & year==2008)
# A tibble: 4 x 11
  manufacturer model   displ  year   cyl trans    drv     cty   hwy fl    class 
  <chr>        <chr>   <dbl> <int> <int> <chr>    <chr> <int> <int> <chr> <chr> 
1 hyundai      sonata    2.4  2008     4 auto(l4) f        21    30 r     midsi…
2 hyundai      sonata    2.4  2008     4 manual(… f        21    31 r     midsi…
3 hyundai      sonata    3.3  2008     6 auto(l5) f        19    28 r     midsi…
4 toyota       corolla   1.8  2008     4 manual(… f        28    37 r     compa…

단, 복합 조건식에서 AND 연산이 OR 연산보다 우선순위가 있으므로 괄호를 사용하여 연산의 순서가 제대로 되도록 하여야 한다. 괄호가 없으면 AND가 수행된 후 OR가 수행되어 모든 소타나 자동차의 결과가 추출되었음을 볼 수 있다.

> filter(mpg, model=="sonata" | cty >= 28 & year==2008)
# A tibble: 8 x 11
  manufacturer model   displ  year   cyl trans    drv     cty   hwy fl    class 
  <chr>        <chr>   <dbl> <int> <int> <chr>    <chr> <int> <int> <chr> <chr> 
1 hyundai      sonata    2.4  1999     4 auto(l4) f        18    26 r     midsi…
2 hyundai      sonata    2.4  1999     4 manual(… f        18    27 r     midsi…
3 hyundai      sonata    2.4  2008     4 auto(l4) f        21    30 r     midsi…
4 hyundai      sonata    2.4  2008     4 manual(… f        21    31 r     midsi…
5 hyundai      sonata    2.5  1999     6 auto(l4) f        18    26 r     midsi…
6 hyundai      sonata    2.5  1999     6 manual(… f        18    26 r     midsi…
7 hyundai      sonata    3.3  2008     6 auto(l5) f        19    28 r     midsi…
8 toyota       corolla   1.8  2008     4 manual(… f        28    37 r     compa…

4.4.4 결측치가 있는 경우

R에서는 데이터에 결측치가 있을 때 이를 NA 값으로 표시한다. 예를 들어 5 명의 학생의 키 데이터가 있는 데 마지막 학생의 데이터를 얻지 못하였다면, 그 학생의 데이터는 NA로 값을 입력한다.

is.na() 함수를 이용하면 결측치의 포함 여부를 확인할 수 있다. na.omit() 함수를 이용하면 결측치를 제외한 벡터를 만들 수 있다.

> z <- c(1:3, NA)
> z
[1]  1  2  3 NA
> is.na(z)
[1] FALSE FALSE FALSE  TRUE
> na.omit(z)
[1] 1 2 3
attr(,"na.action")
[1] 4
attr(,"class")
[1] "omit"

결측치가 있으면 sum()이나 mean() 같은 함수들의 결과는 NA가 출력된다. 결측치를 제외하고 이들 함수를 사용하려면 함수 인수에 na.rm=TRUE를 덧붙여야 한다. 그러면 결측치를 제외하고 결과를 계산하게 된다.

> sum(z)
[1] NA
> sum(z, na.rm=TRUE)
[1] 6

조건에 사용되는 열에 결측치가 있는 경우에 결측치가 있는 행을 추출하려면 is.na() 함수를 이용하여야 한다.

4.5 arrange()로 행 정렬하기

arrange()는 다음 문법을 사용하여 행을 정렬한다.

arrange(데이터프레임, 첫번째_정렬_기준_열, 두번째_정렬_기준_열, ....)

filter()와 마찬가지로 첫 번재 인수로 정렬할 데이터 프레임을 전달 받는다. 그리고 두번재 인수부터 정렬의 기준이 되는 열을 차례로 기술한다. 첫 번째 기준 열의 값이 같으면, 두 번째 기준 열을, 두 번째 기준 열의 값까지 같으면 그 다음 열을 기준으로 차례로 순서를 결정하여 정렬을 수행한다.

다음은 2008년도 현대의 자동차 모델만 filter()론 선택하여 a라는 변수에 저장한 후, 이 데이터에 대하여 여러 조건으로 정렬을 수행해본 예이다.

> a <- filter(mpg, manufacturer == "hyundai", year == 2008)
> a
# A tibble: 8 x 11
  manufacturer model  displ  year   cyl trans    drv     cty   hwy fl    class  
  <chr>        <chr>  <dbl> <int> <int> <chr>    <chr> <int> <int> <chr> <chr>  
1 hyundai      sonata   2.4  2008     4 auto(l4) f        21    30 r     midsize
2 hyundai      sonata   2.4  2008     4 manual(… f        21    31 r     midsize
3 hyundai      sonata   3.3  2008     6 auto(l5) f        19    28 r     midsize
4 hyundai      tibur…   2    2008     4 manual(… f        20    28 r     subcom…
5 hyundai      tibur…   2    2008     4 auto(l4) f        20    27 r     subcom…
6 hyundai      tibur…   2.7  2008     6 auto(l4) f        17    24 r     subcom…
7 hyundai      tibur…   2.7  2008     6 manual(… f        16    24 r     subcom…
8 hyundai      tibur…   2.7  2008     6 manual(… f        17    24 r     subcom…
> arrange(a, cyl)
# A tibble: 8 x 11
  manufacturer model  displ  year   cyl trans    drv     cty   hwy fl    class  
  <chr>        <chr>  <dbl> <int> <int> <chr>    <chr> <int> <int> <chr> <chr>  
1 hyundai      sonata   2.4  2008     4 auto(l4) f        21    30 r     midsize
2 hyundai      sonata   2.4  2008     4 manual(… f        21    31 r     midsize
3 hyundai      tibur…   2    2008     4 manual(… f        20    28 r     subcom…
4 hyundai      tibur…   2    2008     4 auto(l4) f        20    27 r     subcom…
5 hyundai      sonata   3.3  2008     6 auto(l5) f        19    28 r     midsize
6 hyundai      tibur…   2.7  2008     6 auto(l4) f        17    24 r     subcom…
7 hyundai      tibur…   2.7  2008     6 manual(… f        16    24 r     subcom…
8 hyundai      tibur…   2.7  2008     6 manual(… f        17    24 r     subcom…
> arrange(a, cyl, cty)
# A tibble: 8 x 11
  manufacturer model  displ  year   cyl trans    drv     cty   hwy fl    class  
  <chr>        <chr>  <dbl> <int> <int> <chr>    <chr> <int> <int> <chr> <chr>  
1 hyundai      tibur…   2    2008     4 manual(… f        20    28 r     subcom…
2 hyundai      tibur…   2    2008     4 auto(l4) f        20    27 r     subcom…
3 hyundai      sonata   2.4  2008     4 auto(l4) f        21    30 r     midsize
4 hyundai      sonata   2.4  2008     4 manual(… f        21    31 r     midsize
5 hyundai      tibur…   2.7  2008     6 manual(… f        16    24 r     subcom…
6 hyundai      tibur…   2.7  2008     6 auto(l4) f        17    24 r     subcom…
7 hyundai      tibur…   2.7  2008     6 manual(… f        17    24 r     subcom…
8 hyundai      sonata   3.3  2008     6 auto(l5) f        19    28 r     midsize
> arrange(a, model, trans)
# A tibble: 8 x 11
  manufacturer model  displ  year   cyl trans    drv     cty   hwy fl    class  
  <chr>        <chr>  <dbl> <int> <int> <chr>    <chr> <int> <int> <chr> <chr>  
1 hyundai      sonata   2.4  2008     4 auto(l4) f        21    30 r     midsize
2 hyundai      sonata   3.3  2008     6 auto(l5) f        19    28 r     midsize
3 hyundai      sonata   2.4  2008     4 manual(… f        21    31 r     midsize
4 hyundai      tibur…   2    2008     4 auto(l4) f        20    27 r     subcom…
5 hyundai      tibur…   2.7  2008     6 auto(l4) f        17    24 r     subcom…
6 hyundai      tibur…   2    2008     4 manual(… f        20    28 r     subcom…
7 hyundai      tibur…   2.7  2008     6 manual(… f        17    24 r     subcom…
8 hyundai      tibur…   2.7  2008     6 manual(… f        16    24 r     subcom…

4.5.1 desc()를 이용하여 내림차순으로 정렬하기

앞의 예에서 arrange()는 수치 열은 올림차순으로 문자 열은 알파벳 순으로 정렬하는 것을 볼 수 있다. 만약 위의 예에서 내림차순으로, 또는 알파벳 역순으로 정렬을 하고 싶으면 어떻게 하여야 할까? dplyr 패키지는 desc()를 이용하면 된다.

> arrange(a, desc(cyl))
# A tibble: 8 x 11
  manufacturer model  displ  year   cyl trans    drv     cty   hwy fl    class  
  <chr>        <chr>  <dbl> <int> <int> <chr>    <chr> <int> <int> <chr> <chr>  
1 hyundai      sonata   3.3  2008     6 auto(l5) f        19    28 r     midsize
2 hyundai      tibur…   2.7  2008     6 auto(l4) f        17    24 r     subcom…
3 hyundai      tibur…   2.7  2008     6 manual(… f        16    24 r     subcom…
4 hyundai      tibur…   2.7  2008     6 manual(… f        17    24 r     subcom…
5 hyundai      sonata   2.4  2008     4 auto(l4) f        21    30 r     midsize
6 hyundai      sonata   2.4  2008     4 manual(… f        21    31 r     midsize
7 hyundai      tibur…   2    2008     4 manual(… f        20    28 r     subcom…
8 hyundai      tibur…   2    2008     4 auto(l4) f        20    27 r     subcom…
> arrange(a, desc(cyl), cty)
# A tibble: 8 x 11
  manufacturer model  displ  year   cyl trans    drv     cty   hwy fl    class  
  <chr>        <chr>  <dbl> <int> <int> <chr>    <chr> <int> <int> <chr> <chr>  
1 hyundai      tibur…   2.7  2008     6 manual(… f        16    24 r     subcom…
2 hyundai      tibur…   2.7  2008     6 auto(l4) f        17    24 r     subcom…
3 hyundai      tibur…   2.7  2008     6 manual(… f        17    24 r     subcom…
4 hyundai      sonata   3.3  2008     6 auto(l5) f        19    28 r     midsize
5 hyundai      tibur…   2    2008     4 manual(… f        20    28 r     subcom…
6 hyundai      tibur…   2    2008     4 auto(l4) f        20    27 r     subcom…
7 hyundai      sonata   2.4  2008     4 auto(l4) f        21    30 r     midsize
8 hyundai      sonata   2.4  2008     4 manual(… f        21    31 r     midsize
> arrange(a, model, desc(trans))
# A tibble: 8 x 11
  manufacturer model  displ  year   cyl trans    drv     cty   hwy fl    class  
  <chr>        <chr>  <dbl> <int> <int> <chr>    <chr> <int> <int> <chr> <chr>  
1 hyundai      sonata   2.4  2008     4 manual(… f        21    31 r     midsize
2 hyundai      sonata   3.3  2008     6 auto(l5) f        19    28 r     midsize
3 hyundai      sonata   2.4  2008     4 auto(l4) f        21    30 r     midsize
4 hyundai      tibur…   2.7  2008     6 manual(… f        16    24 r     subcom…
5 hyundai      tibur…   2    2008     4 manual(… f        20    28 r     subcom…
6 hyundai      tibur…   2.7  2008     6 manual(… f        17    24 r     subcom…
7 hyundai      tibur…   2    2008     4 auto(l4) f        20    27 r     subcom…
8 hyundai      tibur…   2.7  2008     6 auto(l4) f        17    24 r     subcom…

desc()가 적용된 변수만 내림차순을 기준으로 정렬을 하는 것을 볼 수 있다.

4.6 select()를 이용하여 열 선택하기

4.6.1 열 이름을 나열하여 선택하기

select() 함수는 다음처럼 열 이름을 일일이 나열하여 원하는 열을 선택할 수 있다. R의 기본 문법을 알고 있는 사람들은 데이터 프레임의 인덱싱에서처럼 문자열로 이름을 나열하는 것이 아니라 변수를 사용하듯 따옴표 없이 이름을 나열하는 것에 주의한다.

select(데이터프레임, 열이름1, 열이름2, ....)
> select(a, model, year, cty, hwy)
# A tibble: 8 x 4
  model    year   cty   hwy
  <chr>   <int> <int> <int>
1 sonata   2008    21    30
2 sonata   2008    21    31
3 sonata   2008    19    28
4 tiburon  2008    20    28
5 tiburon  2008    20    27
6 tiburon  2008    17    24
7 tiburon  2008    16    24
8 tiburon  2008    17    24

4.6.2 열 범위를 선택하기

select() 함수는 다음처럼 열 이름으로 선택할 열의 범위를 지정할 수 있다.

select(데이터프레임, 범위시작_열이름:범위종료_열이름, ...)
> select(a, model:trans)
# A tibble: 8 x 5
  model   displ  year   cyl trans     
  <chr>   <dbl> <int> <int> <chr>     
1 sonata    2.4  2008     4 auto(l4)  
2 sonata    2.4  2008     4 manual(m5)
3 sonata    3.3  2008     6 auto(l5)  
4 tiburon   2    2008     4 manual(m5)
5 tiburon   2    2008     4 auto(l4)  
6 tiburon   2.7  2008     6 auto(l4)  
7 tiburon   2.7  2008     6 manual(m6)
8 tiburon   2.7  2008     6 manual(m5)
> select(a, model:trans, cty:hwy)
# A tibble: 8 x 7
  model   displ  year   cyl trans        cty   hwy
  <chr>   <dbl> <int> <int> <chr>      <int> <int>
1 sonata    2.4  2008     4 auto(l4)      21    30
2 sonata    2.4  2008     4 manual(m5)    21    31
3 sonata    3.3  2008     6 auto(l5)      19    28
4 tiburon   2    2008     4 manual(m5)    20    28
5 tiburon   2    2008     4 auto(l4)      20    27
6 tiburon   2.7  2008     6 auto(l4)      17    24
7 tiburon   2.7  2008     6 manual(m6)    16    24
8 tiburon   2.7  2008     6 manual(m5)    17    24

반대로 다음처럼 열 이름으로 선택하지 않을 열의 범위를 지정할 수 있다.

select(데이터프레임, -(범위시작_열이름:범위종료_열이름), ...)
> select(a, -(model:trans))
# A tibble: 8 x 6
  manufacturer drv     cty   hwy fl    class     
  <chr>        <chr> <int> <int> <chr> <chr>     
1 hyundai      f        21    30 r     midsize   
2 hyundai      f        21    31 r     midsize   
3 hyundai      f        19    28 r     midsize   
4 hyundai      f        20    28 r     subcompact
5 hyundai      f        20    27 r     subcompact
6 hyundai      f        17    24 r     subcompact
7 hyundai      f        16    24 r     subcompact
8 hyundai      f        17    24 r     subcompact
> select(a, -(model:trans), -manufacturer)
# A tibble: 8 x 5
  drv     cty   hwy fl    class     
  <chr> <int> <int> <chr> <chr>     
1 f        21    30 r     midsize   
2 f        21    31 r     midsize   
3 f        19    28 r     midsize   
4 f        20    28 r     subcompact
5 f        20    27 r     subcompact
6 f        17    24 r     subcompact
7 f        16    24 r     subcompact
8 f        17    24 r     subcompact

4.6.3 열 이름을 매칭하여 선택하기

dplyr 패키지는 다양한 형태로 열을 선택할 수 있도록 다음의 열 이름 매칭 함수를 제공한다.

  • starts_with("abs"): abc로 이름이 시작하는 모든 열
  • ends_with("abs"): abc로 이름이 끝나는 모든 열
  • contains("abs"): abc를 이름에 포함하고 있는 모든 열
  • matches("(.)\\1"): 정규 표현식을 만족하는 이름을 가진 모든 열
  • num_range("x", 1:3): “x1,” “x2,” “x3”이라는 이름의 열
> select(a, starts_with("c"))
# A tibble: 8 x 3
    cyl   cty class     
  <int> <int> <chr>     
1     4    21 midsize   
2     4    21 midsize   
3     6    19 midsize   
4     4    20 subcompact
5     4    20 subcompact
6     6    17 subcompact
7     6    16 subcompact
8     6    17 subcompact

4.6.4 열 이름 바꾸기

select() 함수에서 열 이름을 지정할 때, 새로운_열_이름=기존_열_이름 형식으로 지정하면 열의 이름을 바꿀 수 있다.

> select(a, model, city=cty, highway=hwy)
# A tibble: 8 x 3
  model    city highway
  <chr>   <int>   <int>
1 sonata     21      30
2 sonata     21      31
3 sonata     19      28
4 tiburon    20      28
5 tiburon    20      27
6 tiburon    17      24
7 tiburon    16      24
8 tiburon    17      24

만약 전체 데이터를 유지한 상태에서 열 이름만 변경하려면, rename() 함수를 이용한다. 문법은 select()와 같다.

> rename(a, city=cty, highway=hwy)
# A tibble: 8 x 11
  manufacturer model  displ  year   cyl trans   drv    city highway fl    class 
  <chr>        <chr>  <dbl> <int> <int> <chr>   <chr> <int>   <int> <chr> <chr> 
1 hyundai      sonata   2.4  2008     4 auto(l… f        21      30 r     midsi…
2 hyundai      sonata   2.4  2008     4 manual… f        21      31 r     midsi…
3 hyundai      sonata   3.3  2008     6 auto(l… f        19      28 r     midsi…
4 hyundai      tibur…   2    2008     4 manual… f        20      28 r     subco…
5 hyundai      tibur…   2    2008     4 auto(l… f        20      27 r     subco…
6 hyundai      tibur…   2.7  2008     6 auto(l… f        17      24 r     subco…
7 hyundai      tibur…   2.7  2008     6 manual… f        16      24 r     subco…
8 hyundai      tibur…   2.7  2008     6 manual… f        17      24 r     subco…

4.6.5 열 순서 바꾸기

select() 함수는 나열된 열의 순서에 따라 새롭게 만들어진 데이터 프레임의 열의 순서를 조정한다.

> select(a, cty, hwy)
# A tibble: 8 x 2
    cty   hwy
  <int> <int>
1    21    30
2    21    31
3    19    28
4    20    28
5    20    27
6    17    24
7    16    24
8    17    24
> select(a, hwy, cty)
# A tibble: 8 x 2
    hwy   cty
  <int> <int>
1    30    21
2    31    21
3    28    19
4    28    20
5    27    20
6    24    17
7    24    16
8    24    17

이러한 성질과 everything() 함수를 이용하면 열의 순서를 쉽게 바꿀 수 있다. everything()은 이미 선택된 열을 제외한 나머지 열을 의미한다.

> select(a, cty, hwy, everything())
# A tibble: 8 x 11
    cty   hwy manufacturer model  displ  year   cyl trans    drv   fl    class  
  <int> <int> <chr>        <chr>  <dbl> <int> <int> <chr>    <chr> <chr> <chr>  
1    21    30 hyundai      sonata   2.4  2008     4 auto(l4) f     r     midsize
2    21    31 hyundai      sonata   2.4  2008     4 manual(… f     r     midsize
3    19    28 hyundai      sonata   3.3  2008     6 auto(l5) f     r     midsize
4    20    28 hyundai      tibur…   2    2008     4 manual(… f     r     subcom…
5    20    27 hyundai      tibur…   2    2008     4 auto(l4) f     r     subcom…
6    17    24 hyundai      tibur…   2.7  2008     6 auto(l4) f     r     subcom…
7    16    24 hyundai      tibur…   2.7  2008     6 manual(… f     r     subcom…
8    17    24 hyundai      tibur…   2.7  2008     6 manual(… f     r     subcom…

4.7 mutate()로 새로운 열 만들기

mutate()는 기존 열을 이용하여 새로운 열을 만들어 데이터 프레임의 가장 마지막 열로 추가한다.

mutate(데이터프레임, 새로운_열=기존_열_연산식, ....)

다음은 도심 연비와 고속도로 연비의 합과, 평균, 그리고 고속도로 대비 도심 연비의 비율(%)을 계산하여 새로운 열을 만든 예이다.

> b <- select(a, -(cyl:drv), -(fl:class))
> b
# A tibble: 8 x 6
  manufacturer model   displ  year   cty   hwy
  <chr>        <chr>   <dbl> <int> <int> <int>
1 hyundai      sonata    2.4  2008    21    30
2 hyundai      sonata    2.4  2008    21    31
3 hyundai      sonata    3.3  2008    19    28
4 hyundai      tiburon   2    2008    20    28
5 hyundai      tiburon   2    2008    20    27
6 hyundai      tiburon   2.7  2008    17    24
7 hyundai      tiburon   2.7  2008    16    24
8 hyundai      tiburon   2.7  2008    17    24
> mutate(b, sum=cty + hwy)
# A tibble: 8 x 7
  manufacturer model   displ  year   cty   hwy   sum
  <chr>        <chr>   <dbl> <int> <int> <int> <int>
1 hyundai      sonata    2.4  2008    21    30    51
2 hyundai      sonata    2.4  2008    21    31    52
3 hyundai      sonata    3.3  2008    19    28    47
4 hyundai      tiburon   2    2008    20    28    48
5 hyundai      tiburon   2    2008    20    27    47
6 hyundai      tiburon   2.7  2008    17    24    41
7 hyundai      tiburon   2.7  2008    16    24    40
8 hyundai      tiburon   2.7  2008    17    24    41
> mutate(b, 
+        sum=cty + hwy, 
+        mean=(cty + hwy) / 2,
+        ratio= cty / hwy * 100)
# A tibble: 8 x 9
  manufacturer model   displ  year   cty   hwy   sum  mean ratio
  <chr>        <chr>   <dbl> <int> <int> <int> <int> <dbl> <dbl>
1 hyundai      sonata    2.4  2008    21    30    51  25.5  70  
2 hyundai      sonata    2.4  2008    21    31    52  26    67.7
3 hyundai      sonata    3.3  2008    19    28    47  23.5  67.9
4 hyundai      tiburon   2    2008    20    28    48  24    71.4
5 hyundai      tiburon   2    2008    20    27    47  23.5  74.1
6 hyundai      tiburon   2.7  2008    17    24    41  20.5  70.8
7 hyundai      tiburon   2.7  2008    16    24    40  20    66.7
8 hyundai      tiburon   2.7  2008    17    24    41  20.5  70.8

4.7.1 transmute()로 새로운 열만 남기기

만약 새롭게 만들어진 열만 데이터에 남기려면 mutate() 대신 transmute()를 사용한다. 문법은 두 함수가 동일하다.

> transmute(b, 
+        sum=cty + hwy, 
+        mean=(cty + hwy) / 2,
+        ratio= cty / hwy * 100)
# A tibble: 8 x 3
    sum  mean ratio
  <int> <dbl> <dbl>
1    51  25.5  70  
2    52  26    67.7
3    47  23.5  67.9
4    48  24    71.4
5    47  23.5  74.1
6    41  20.5  70.8
7    40  20    66.7
8    41  20.5  70.8

4.7.2 새로운 열을 만들 때 사용할 수 있는 함수들

새로운 열을 생성할 때, 기존 열과 관련된 수치, 논리, 문자열 연산을 수행할 수 있다. 다음처럼 제조사와 모델을 하나로 합쳐서 새로운 열을 만들수도 있고, 배기량이 3 이상인지 여부를 나타내는 열도 만들 수 있다.

> mutate(b, newName=paste(manufacturer, model, sep="-"), dis3=displ >= 3)
# A tibble: 8 x 8
  manufacturer model   displ  year   cty   hwy newName         dis3 
  <chr>        <chr>   <dbl> <int> <int> <int> <chr>           <lgl>
1 hyundai      sonata    2.4  2008    21    30 hyundai-sonata  FALSE
2 hyundai      sonata    2.4  2008    21    31 hyundai-sonata  FALSE
3 hyundai      sonata    3.3  2008    19    28 hyundai-sonata  TRUE 
4 hyundai      tiburon   2    2008    20    28 hyundai-tiburon FALSE
5 hyundai      tiburon   2    2008    20    27 hyundai-tiburon FALSE
6 hyundai      tiburon   2.7  2008    17    24 hyundai-tiburon FALSE
7 hyundai      tiburon   2.7  2008    16    24 hyundai-tiburon FALSE
8 hyundai      tiburon   2.7  2008    17    24 hyundai-tiburon FALSE

아울러 다음 함수가 새로운 열을 만들 때 자주 사용된다.

  • lead(): 기존 열을 한 행, 또는 여러 행 빠르게 시작하는 열
  • rag(): 기존 열을 한 행, 또는 여러 행 늦게 시작하는 열
  • cumsum(), cummean(): 누적 합과 평균
  • min_rank(): 가장 작은 것부터 차례대로 크기 순서로 등수를 매기는 함수. desc() 함수를 열에 적용한 후 등수를 매기면 가장 큰 것부터 순서를 매길 수 있다.
  • dense_rank(), percent_rank(), cume_dist(), ntile() 등도 사용될 수 있다. 자세한 내용은 도움말을 참조하기 바란다.
> mutate(b, cty_rank=min_rank(cty), hwy_rank=min_rank(desc(hwy)), desc_hwy=desc(hwy))
# A tibble: 8 x 9
  manufacturer model   displ  year   cty   hwy cty_rank hwy_rank desc_hwy
  <chr>        <chr>   <dbl> <int> <int> <int>    <int>    <int>    <int>
1 hyundai      sonata    2.4  2008    21    30        7        2      -30
2 hyundai      sonata    2.4  2008    21    31        7        1      -31
3 hyundai      sonata    3.3  2008    19    28        4        3      -28
4 hyundai      tiburon   2    2008    20    28        5        3      -28
5 hyundai      tiburon   2    2008    20    27        5        5      -27
6 hyundai      tiburon   2.7  2008    17    24        2        6      -24
7 hyundai      tiburon   2.7  2008    16    24        1        6      -24
8 hyundai      tiburon   2.7  2008    17    24        2        6      -24

4.8 summarize()로 열 요약하기

summarize(데이터프레임, 요약_열이름=요약함수(열이름), ....)

summarize() 함수는 열의 모든 값을 하나의 값으로 요약하는 함수를 이용하여 열을 요약한다. 대표적인 요약 함수는 다음과 같다.

  • n(): 열의 크기를 구한다.
  • sum(): 수치 열의 합을 구한다.
  • mean(): 수치 열의 평균을 구한다.
  • median(): 수치 열의 중위수를 구한다.
  • sd(): 수치 열의 표준편차를 구한다.
  • var(): 수치 열의 분산을 구한다.
  • min(): 수치 열의 최소값을 구한다.
  • max(): 수치 열의 최대값을 구한다.
  • quantile(열이름, probs): 수치 열의probs` 분위수를 구한다.

다음은 도심 연비의 데이터 수, 평균, 중위수, 최소값, 최대값을 구한 결과이다.

> summarize(b, count=n(), mean=mean(cty), med=median(cty), min=min(cty), max=max(cty))
# A tibble: 1 x 5
  count  mean   med   min   max
  <int> <dbl> <dbl> <int> <int>
1     8  18.9  19.5    16    21

4.9 group_by()로 그룹 별로 요약하기

group_by(데이터프레임, 그룹기준_열1, 그룹기준_열2, ...)

group_by() 함수는 기준이 되는 열의 구분되는 값에 따라 데이터를 그룹화한다. 그룹화된 결과를 summarize() 함수에 전달하면 그룹별로 요약된 결과를 출력한다.

> byModel <- group_by(b, model)
> summarize(byModel, count=n(), mean=mean(cty), sd=sd(cty))
# A tibble: 2 x 4
  model   count  mean    sd
  <chr>   <int> <dbl> <dbl>
1 sonata      3  20.3  1.15
2 tiburon     5  18    1.87

열을 여러 개를 조합하여 그룹화를 할 수도 있다.

> byModel <- group_by(a, model, cyl)
> summarize(byModel, count=n(), mean=mean(cty))
`summarise()` has grouped output by 'model'. You can override using the `.groups` argument.
# A tibble: 4 x 4
# Groups:   model [2]
  model     cyl count  mean
  <chr>   <int> <int> <dbl>
1 sonata      4     2  21  
2 sonata      6     1  19  
3 tiburon     4     2  20  
4 tiburon     6     3  16.7

4.10 %>% 파이프 연산자

4.10.1 여러 단계를 거쳐 데이터를 변환할 때

mpg 데이터에서 조사 연도와 모델 별로 데이터 수와 도심 연비의 평균을 구한 후, 평균이 22 이상인 모델로 이루어진 행을 추출하려고 한다. 이를 수행하려면 다음처럼 변수를 이용하여 결과를 차례로 전달하거나, 함수를 결합하여 한 문장에 사용하여야 한다.

> byModel <- group_by(mpg, model, year)
> meanCty <- summarize(byModel, count=n(), mean=mean(cty))
`summarise()` has grouped output by 'model'. You can override using the `.groups` argument.
> filter(meanCty, mean >= 22)
# A tibble: 5 x 4
# Groups:   model [3]
  model       year count  mean
  <chr>      <int> <int> <dbl>
1 civic       1999     5  24.8
2 civic       2008     4  24  
3 corolla     1999     3  24.7
4 corolla     2008     2  27  
5 new beetle  1999     4  26  
> filter(summarize(group_by(mpg, model, year), count=n(), mean=mean(cty)), mean >= 22)
`summarise()` has grouped output by 'model'. You can override using the `.groups` argument.
# A tibble: 5 x 4
# Groups:   model [3]
  model       year count  mean
  <chr>      <int> <int> <dbl>
1 civic       1999     5  24.8
2 civic       2008     4  24  
3 corolla     1999     3  24.7
4 corolla     2008     2  27  
5 new beetle  1999     4  26  

전자는 불피요하게 중간 결과를 저장할 변수를 만들어야 하고, 후자는 복잡하여 이 명령이 무엇을 하는 명령어인지 쉽게 파악하기 힘들다. 또한 중첩된 괄호 때문에 오류가 발생하기 쉽다.

4.10.2 파이프 연산자

파이프 연산자는 데이터 변환이 여러 단계를 거칠 때 불필요한 변수의 생성 없이도 함수 간에 중간 데이터를 전달할 수 있게 해 준다.

파이프 연산자는 앞의 함수의 결과를 뒤 함수의 첫 번째 인수로 전달해 준다. 파이프 연산자를 사용할 때는 그러므로 첫 번째 인수는 생략하여 기술한다. 다음은 앞의 예와 동일한 예를 파이프 연산자를 사용하여 수행한 결과이다.

> mpg %>% group_by(model, year) %>% 
+   summarize(count=n(), mean=mean(cty)) %>%
+   filter(mean >= 22)
`summarise()` has grouped output by 'model'. You can override using the `.groups` argument.
# A tibble: 5 x 4
# Groups:   model [3]
  model       year count  mean
  <chr>      <int> <int> <dbl>
1 civic       1999     5  24.8
2 civic       2008     4  24  
3 corolla     1999     3  24.7
4 corolla     2008     2  27  
5 new beetle  1999     4  26  

불필요하게 데이터를 기술하는 부분이 사라져서 각 단계에서 수행하는 작업이 무엇인지 명확하게 들어나고 불필요한 중간 변수를 만들지 않아도 되므로 파이프 연산자는 매우 편리하다.

그런데 파이프 연산자를 사용하려면 앞의 함수의 결과가 뒤의 함수의 첫 인수로 사용하기 적절한 형태이어야 한다. dplyr 패키지의 주요 함수들은 정돈 데이터 형식으로 데이터의 결과를 반환하고, 첫 인수가 정돈 데이터 형식의 데이터로 간주한다.

파이프 연산자를 사용할 때 주의할 점은 여러 줄로 명령을 기술할 때, 파이프 연산자로 중간 문장이 종료되어야 한다는 것이다. 그래야 아직 문장이 완료되지 않았다는 것을 이해하여 다음 단계의 명령이 입력되기를 기다린다. 다음처럼 기술하면 R은 명령 입력이 중간에 완료된 것으로 보고 잘못된 결과를 출력한다.

> b %>% group_by(model) %>% 
+   summarize(count=n(), mean=mean(cty)) 
+   %>% filter(mean >= 20)
Error: <text>:3:3: 예기치 않은 SPECIAL입니다
2:   summarize(count=n(), mean=mean(cty)) 
3:   %>%
     ^

4.10.3 ungroup()

파이프 연산자를 사용하여 데이터를 전달하다 보면 데이터가 그룹화 된 것을 중간 단계에서 해제하고 싶을 때가 있다. 이 경우에는 ungroup() 명령을 사용한다.

> byModel <- b %>% group_by(model) 
> byModel %>% summarize(count=n())
# A tibble: 2 x 2
  model   count
  <chr>   <int>
1 sonata      3
2 tiburon     5
> byModel %>% ungroup() %>% summarize(count=n())
# A tibble: 1 x 1
  count
  <int>
1     8

  1. 반드시 필요한 작업은 아니다. 그렇지만 실행하는 것이 작업할 때 매우 편리하므로 필수적인 작업으로 생각하는 것이 좋다.↩︎