Improving Grouping Data

Grouping

Introducing group_by()

우리가 가진 데이터는 대개 그 내부에 그룹(group)을 식별할 수 있는 변수들 또한 가지고 있습니다. 예를 들어, 학생들에 관한 데이터가 있다고 할 때 그 학생들이 속한 학급을 나타내는 변수들이 있을 수 있습니다. 이 경우, 우리는 학생들 개개인에 대한 정보 뿐 아니라 학급별 정보를 알고싶을 수 있습니다. 이때, 우리는 학급과도 같은 그룹 변수를 이용하여 데이터를 그룹화하여 조작 및 요약할 수 있습니다.

  • summarize()는 요약하기 위해 티블을 단일 행으로 축소합니다(Excel의 합계 및 평균 함수를 상상해 보세요).

  • summarize()group_by()와 짝을 이룰 때 유용하게 사용할 수 있습니다.group_by()는 기존 티블을 가져와서 “그룹별로” 연산이 수행되는 그룹화된 티블로 변환합니다.

  • group_by()를 사용하면 대부분의 데이터 연산이 변수로 정의된 그룹에서 수행됩니다. group_by(), summarize()를 함께 사용하면 각 그룹에 대해 하나의 행을 생성합니다. group_by()summarize(){dplyr}로 작업할 때 가장 일반적으로 사용되는 도구 중 하나인 그룹화된 요약(grouped summaries)을 제공합니다.

  • summarize(data, ...)

    • … = 요약 함수의 이름-값 쌍(Name-value pairs)입니다. 이름은 결과에서 변수의 이름이 됩니다. 값은 min(x), n() 또는 sum(is.na(y))와 같이 단일 값을 반환하는 표현식이어야 합니다.
  • 요약 함수는 벡터를 입력으로 받아 단일 값을 출력으로 반환합니다.

## name = delay, value = mean(dep_delay, na.rm = TRUE)
flights |> summarize(delay_mean = mean(dep_delay, na.rm = TRUE), 
                     delay_sd = sd(dep_delay, na.rm = TRUE))
# A tibble: 1 × 2
  delay_mean delay_sd
       <dbl>    <dbl>
1       12.6     40.2

이번에는 group_by()summarize()를 함께 사용해보도록 하겠습니다. 연월일별 평균 출발지연 시간에 대해서 분석해보겠습니다.

flights |> 
  group_by(year, month, day) |> # 연원일로 그룹을 만들어줍니다.
  summarize(delay = mean(dep_delay, na.rm = T)) # 평균 출발 지연 시간 요약
# A tibble: 365 × 4
# Groups:   year, month [12]
    year month   day delay
   <int> <int> <int> <dbl>
 1  2013     1     1 11.5 
 2  2013     1     2 13.9 
 3  2013     1     3 11.0 
 4  2013     1     4  8.95
 5  2013     1     5  5.73
 6  2013     1     6  7.15
 7  2013     1     7  5.42
 8  2013     1     8  2.55
 9  2013     1     9  2.28
10  2013     1    10  2.84
# ℹ 355 more rows

irisR에 내장된 데이터 집합으로, 3가지 종(세토사, 버시컬러, 버지니카)의 붓꽃 50개에 대해 각각 꽃받침 길이와 너비, 꽃잎 길이와 너비 변수의 센티미터 단위 측정값을 제공합니다.

as_tibble(iris)
# A tibble: 150 × 5
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          <dbl>       <dbl>        <dbl>       <dbl> <fct>  
 1          5.1         3.5          1.4         0.2 setosa 
 2          4.9         3            1.4         0.2 setosa 
 3          4.7         3.2          1.3         0.2 setosa 
 4          4.6         3.1          1.5         0.2 setosa 
 5          5           3.6          1.4         0.2 setosa 
 6          5.4         3.9          1.7         0.4 setosa 
 7          4.6         3.4          1.4         0.3 setosa 
 8          5           3.4          1.5         0.2 setosa 
 9          4.4         2.9          1.4         0.2 setosa 
10          4.9         3.1          1.5         0.1 setosa 
# ℹ 140 more rows

파이프(|> 또는 |>)를 이용하여 summarize_all() 함수로 평균을 구해보겠습니다.

iris |> 
  group_by(Species) |> 
  summarise_all(mean)
# A tibble: 3 × 5
  Species    Sepal.Length Sepal.Width Petal.Length Petal.Width
  <fct>             <dbl>       <dbl>        <dbl>       <dbl>
1 setosa             5.01        3.43         1.46       0.246
2 versicolor         5.94        2.77         4.26       1.33 
3 virginica          6.59        2.97         5.55       2.03 

결과를 보면 붓꽃 종별로 각 변수들 전체에 대한 평균값이 요약 및 계산된 것을 확인할 수 있습니다. 이번에는 across 함수를 이용해서 “Sepal”이라는 텍스트를 포함한 변수들에 대한 평균을 산출해보도록 하겠습니다.

iris |> 
  group_by(Species) |> 
  summarise(across(starts_with("Sepal"), mean))
# A tibble: 3 × 3
  Species    Sepal.Length Sepal.Width
  <fct>             <dbl>       <dbl>
1 setosa             5.01        3.43
2 versicolor         5.94        2.77
3 virginica          6.59        2.97

HSB 데이터셋은 {candisc} 패키지에 포함되어 있습니다. HSB 프로젝트는 1980년 미국 국립교육통계센터에서 수행한 미국 학생들에 대한 종단 연구입니다. 58,270명의 고등학생(3학년 28,240명, 2학년 30,030명)과 1,015개의 중등학교에서 데이터를 수집했습니다.

if (!require(candisc)) install.packages("candisc") # 만약 없으면 설치합니다.
library(candisc)
# data()는 특정한 데이터셋을 불러오는 함수입니다.
data(HSB)
head(HSB)
   id gender         race    ses    sch     prog locus concept  mot    career
1  55 female     hispanic    low public  general -1.78    0.56 1.00     prof1
2 114   male african-amer middle public academic  0.24   -0.35 1.00 operative
3 490   male        white middle public vocation -1.28    0.34 0.33     prof1
4  44 female     hispanic    low public vocation  0.22   -0.76 1.00   service
5  26 female     hispanic middle public academic  1.12   -0.74 0.67   service
6 510   male        white middle public vocation -0.86    1.19 0.33 operative
  read write math  sci   ss
1 28.3  46.3 42.8 44.4 50.6
2 30.5  35.9 36.9 33.6 40.6
3 31.0  35.9 46.1 39.0 45.6
4 31.0  41.1 49.2 33.6 35.6
5 31.0  41.1 36.0 36.9 45.6
6 33.6  28.1 31.8 39.6 35.6

HSB 데이터프레임을 티블로 저장해보도록 하겠습니다. 티블은 데이터셋의 각 변수들의 자료 유형, 그리고 전체 관측치와 변수의 개수 등에 대한 정보를 간단하게 제공합니다.

HSB_tbl <- as_tibble(HSB)
HSB_tbl
# A tibble: 600 × 15
      id gender race  ses   sch   prog    locus concept   mot career  read write
   <dbl> <fct>  <fct> <fct> <fct> <fct>   <dbl>   <dbl> <dbl> <fct>  <dbl> <dbl>
 1    55 female hisp… low   publ… gene… -1.78     0.560 1     prof1   28.3  46.3
 2   114 male   afri… midd… publ… acad…  0.240   -0.350 1     opera…  30.5  35.9
 3   490 male   white midd… publ… voca… -1.28     0.340 0.330 prof1   31    35.9
 4    44 female hisp… low   publ… voca…  0.220   -0.760 1     servi…  31    41.1
 5    26 female hisp… midd… publ… acad…  1.12    -0.740 0.670 servi…  31    41.1
 6   510 male   white midd… publ… voca… -0.860    1.19  0.330 opera…  33.6  28.1
 7   133 female afri… low   publ… voca… -0.230    0.440 0.330 school  33.6  35.2
 8   213 female white low   publ… gene…  0.0400  -0.470 0.670 cleri…  33.6  59.3
 9   548 female white midd… priv… acad…  0.470    0.340 0.670 prof2   33.6  43  
10   309 female white high  publ… gene…  0.320    0.900 0.670 prof2   33.6  51.5
# ℹ 590 more rows
# ℹ 3 more variables: math <dbl>, sci <dbl>, ss <dbl>

티블로 변환한 HSB_tbl 데이터셋에 어떠한 변수가 있는지 알아봅시다. HSB 예제 데이터셋에 대한 자세한 정보를 얻고 싶다면 콘솔창에 ?HSB라고 입력하면 됩니다.

names(HSB_tbl)
 [1] "id"      "gender"  "race"    "ses"     "sch"     "prog"    "locus"  
 [8] "concept" "mot"     "career"  "read"    "write"   "math"    "sci"    
[15] "ss"     

이번에는 HSB_tbl 티블의 특성을 살펴보도록 하겠습니다.

HSB_tbl |> glimpse()
Rows: 600
Columns: 15
$ id      <dbl> 55, 114, 490, 44, 26, 510, 133, 213, 548, 309, 180, 322, 1, 32…
$ gender  <fct> female, male, male, female, female, male, female, female, fema…
$ race    <fct> hispanic, african-amer, white, hispanic, hispanic, white, afri…
$ ses     <fct> low, middle, middle, low, middle, middle, low, low, middle, hi…
$ sch     <fct> public, public, public, public, public, public, public, public…
$ prog    <fct> general, academic, vocation, vocation, academic, vocation, voc…
$ locus   <dbl> -1.78, 0.24, -1.28, 0.22, 1.12, -0.86, -0.23, 0.04, 0.47, 0.32…
$ concept <dbl> 0.56, -0.35, 0.34, -0.76, -0.74, 1.19, 0.44, -0.47, 0.34, 0.90…
$ mot     <dbl> 1.00, 1.00, 0.33, 1.00, 0.67, 0.33, 0.33, 0.67, 0.67, 0.67, 0.…
$ career  <fct> prof1, operative, prof1, service, service, operative, school, …
$ read    <dbl> 28.3, 30.5, 31.0, 31.0, 31.0, 33.6, 33.6, 33.6, 33.6, 33.6, 33…
$ write   <dbl> 46.3, 35.9, 35.9, 41.1, 41.1, 28.1, 35.2, 59.3, 43.0, 51.5, 54…
$ math    <dbl> 42.8, 36.9, 46.1, 49.2, 36.0, 31.8, 40.9, 44.7, 41.0, 41.9, 41…
$ sci     <dbl> 44.4, 33.6, 39.0, 33.6, 36.9, 39.6, 29.3, 47.1, 49.8, 49.8, 41…
$ ss      <dbl> 50.6, 40.6, 45.6, 35.6, 45.6, 35.6, 25.7, 45.6, 35.6, 50.6, 50…

자, 이번에는 인종별로 데이터셋 내에 몇 명이 존재하는지를 살펴보도록 하겠습니다. summarise() 함수에서 n() 이라는 함수는 현재 그룹의 크기를 계산하여 보여줍니다.

HSB_tbl |> 
  group_by(race) |>   # 인종 별로 그룹화하고
  summarise(n = n())  # n이라는 변수를 만들어 정보를 요약
# A tibble: 4 × 2
  race             n
  <fct>        <int>
1 hispanic        71
2 asian           34
3 african-amer    58
4 white          437
                      # 이때 요약할 정보는 n(), 그룹의 크기

count() 함수는 변수의 고유한 값을 계산합니다. 따라서 위와 동일한 결과가 산출됩니다.

HSB_tbl |> 
  count(race)
# A tibble: 4 × 2
  race             n
  <fct>        <int>
1 hispanic        71
2 asian           34
3 african-amer    58
4 white          437

그렇다면 이번에는 인종-성별 별 그룹의 크기를 계산해보도록 하겠습니다.

HSB_tbl |> 
  count(race, gender)
# A tibble: 8 × 3
  race         gender     n
  <fct>        <fct>  <int>
1 hispanic     male      37
2 hispanic     female    34
3 asian        male      15
4 asian        female    19
5 african-amer male      24
6 african-amer female    34
7 white        male     197
8 white        female   240

데이터셋에서 독해(reading), 작문(writing), 수학(math), 사회과학(social science) 점수에 대한 평균값을 계산해보도록 하겠습니다. 이때, 평균을 계산하기 위해 mean() 함수를 사용하지만 그 외에도 다른 요약 정보를 보여줄 수 있는 함수들을 사용할 수도 있습니다: median(), sum(), min(), max(), sd(), var()

HSB_tbl |> 
  summarise(readm = mean(read), 
            writem = mean(write), 
            mathm = mean(math), 
            ssm = mean(ss))
# A tibble: 1 × 4
  readm writem mathm   ssm
  <dbl>  <dbl> <dbl> <dbl>
1  51.9   52.4  51.8  52.0

이번에는 성별에 따른 해당 과목들의 점수 평균을 살펴보도록 하겠습니다. 성별로 나누어 살펴보아야 하니 group_by(gender)를 추가해줍니다.

# the means of reading, writing, math, and social science scores by gender
HSB_tbl |> 
  group_by(gender) |>
  summarise(readm = mean(read), 
            writem = mean(write), 
            mathm = mean(math), 
            ssm = mean(ss))
# A tibble: 2 × 5
  gender readm writem mathm   ssm
  <fct>  <dbl>  <dbl> <dbl> <dbl>
1 male    52.4   49.8  52.3  51.4
2 female  51.5   54.6  51.4  52.6

마지막으로 성별에 더해 인종까지도 고려해봅시다.

HSB_tbl |> 
  group_by(gender, race) |>
  summarise(readm = mean(read), 
            writem = mean(write), 
            mathm = mean(math), 
            ssm = mean(ss))
# A tibble: 8 × 6
# Groups:   gender [2]
  gender race         readm writem mathm   ssm
  <fct>  <fct>        <dbl>  <dbl> <dbl> <dbl>
1 male   hispanic      47.7   45.1  47.7  45.9
2 male   asian         55.7   54.7  58.9  50.3
3 male   african-amer  46.6   44.7  44.2  47.2
4 male   white         53.7   50.9  53.7  53.0
5 female hispanic      44.0   48.5  43.6  49.0
6 female asian         52.7   56.5  56.7  53.8
7 female african-amer  47.4   47.5  46.8  49.2
8 female white         53.1   56.3  52.8  53.5

이번에는 성별에 따라 모든 숫자형 변수들의 평균을 요약하여 나타내 봅시다.

HSB_tbl |> 
  group_by(gender) |>
  summarise(across(where(is.numeric), mean, na.rm = TRUE))
# A tibble: 2 × 10
  gender    id  locus concept   mot  read write  math   sci    ss
  <fct>  <dbl>  <dbl>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 male    305. 0.0134  0.102  0.624  52.4  49.8  52.3  53.2  51.4
2 female  297. 0.166  -0.0762 0.692  51.5  54.6  51.4  50.5  52.6

이때, mean() 함수는 값에 NA가 포함되어 있을 경우 결과로 NA를 반환하기 때문에, NA는 제거하고 평균을 계산하라는 옵션인 na.rm = TRUE를 추가해줍니다.

그리고 인종 중에서 아시안과 히스페닉의 경우만 필터링해서 사회경제적 조건에 따른 과목 평균을 계산해보도록 하겠습니다.

HSB_tbl |>
  dplyr::filter(race %in% c("asian", "hispanic")) |>
  group_by(ses) |>
  summarise(across(where(is.numeric), mean, na.rm = TRUE))
# A tibble: 3 × 10
  ses       id  locus concept   mot  read write  math   sci    ss
  <fct>  <dbl>  <dbl>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 low     44.8 -0.142 -0.189  0.537  44.7  45.9  45.8  43.0  45.5
2 middle  50.8 -0.122  0.0525 0.584  47.3  48.6  48.3  47.5  47.9
3 high    66.9  0.118  0.0619 0.705  55.6  55.9  56.6  54.0  55.0
## summarize_if를 사용해도 동일한 결과를 얻을 수 있습니다.

HSB_tbl |>
  dplyr::filter(race %in% c("asian", "hispanic")) |>
  group_by(ses) |>
  summarise_if(is.numeric, mean, na.rm = TRUE)
# A tibble: 3 × 10
  ses       id  locus concept   mot  read write  math   sci    ss
  <fct>  <dbl>  <dbl>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 low     44.8 -0.142 -0.189  0.537  44.7  45.9  45.8  43.0  45.5
2 middle  50.8 -0.122  0.0525 0.584  47.3  48.6  48.3  47.5  47.9
3 high    66.9  0.118  0.0619 0.705  55.6  55.9  56.6  54.0  55.0

Introducing rowwise

rowwise()는 행 단위로 연산을 수행합니다. group_by()와 유사하게 작동합니다. 데이터 프레임의 모양은 달라지지 않지만, 데이터 프레임으로 계산이 수행되는 방식은 다릅니다. 개인의 성과를 보여주는 가상의 데이터 프레임을 만들어보고 이 함수를 적용했을 때, 어떤 결과가 나오는지 확인해 보겠습니다:

(dframe <- tibble(
  name = c("Jakob", "Eliud", "Jamal", "Emily"),
  first = c(1, 4, 7, 10),
  second = c(2, 5, 8,11),
  third = c(3, 6, 9, 12)))
# A tibble: 4 × 4
  name  first second third
  <chr> <dbl>  <dbl> <dbl>
1 Jakob     1      2     3
2 Eliud     4      5     6
3 Jamal     7      8     9
4 Emily    10     11    12
dframe |> rowwise()
# A tibble: 4 × 4
# Rowwise: 
  name  first second third
  <chr> <dbl>  <dbl> <dbl>
1 Jakob     1      2     3
2 Eliud     4      5     6
3 Jamal     7      8     9
4 Emily    10     11    12

보시다시피 아무것도 달라지지 않습니다. 출력 결과는 Rowwise:라는 문구로 앞으로 행 별로 계산이 수행될 것임을 알려줄 뿐입니다. 이제 개인의 성과 평균을 계산하면 정확한 결과를 얻을 수 있습니다:

dframe |> rowwise() |> 
  mutate(mean_performance = mean(c(first, second, third)))
# A tibble: 4 × 5
# Rowwise: 
  name  first second third mean_performance
  <chr> <dbl>  <dbl> <dbl>            <dbl>
1 Jakob     1      2     3                2
2 Eliud     4      5     6                5
3 Jamal     7      8     9                8
4 Emily    10     11    12               11

rowwise()group_by()의 특수한 경우일 뿐이라는 것을 설명하기 위해 group_by() 함수를 사용하여 동일한 결과를 산출해보도록 하겠습니다:

dframe |>
  group_by(name) |>
  mutate(mean = mean(c(first, second, third)))
# A tibble: 4 × 5
# Groups:   name [4]
  name  first second third  mean
  <chr> <dbl>  <dbl> <dbl> <dbl>
1 Jakob     1      2     3     2
2 Eliud     4      5     6     5
3 Jamal     7      8     9     8
4 Emily    10     11    12    11

요약 통계를 계산하는 다른 모든 기본 R 함수에도 동일한 논리가 적용됩니다:

dframe |>
  rowwise() |>
  mutate(
    mean_performance = mean(c(first, second, third)),
    sum_performance = sum(c(first, second, third)),
    min_performance = min(c(first, second, third)),
    max_performance = max(c(first, second, third)),
    median_performance = median(c(first, second, third)))
# A tibble: 4 × 9
# Rowwise: 
  name  first second third mean_performance sum_performance min_performance
  <chr> <dbl>  <dbl> <dbl>            <dbl>           <dbl>           <dbl>
1 Jakob     1      2     3                2               6               1
2 Eliud     4      5     6                5              15               4
3 Jamal     7      8     9                8              24               7
4 Emily    10     11    12               11              33              10
# ℹ 2 more variables: max_performance <dbl>, median_performance <dbl>

How to Use Tidyselect Functions with rowwise

mean이나 다른 함수 내에서 tidyselect 함수를 추가하여 사용할 수는 없습니다. 아래의 코드를 보면, 결과 값이 제대로 산출되지 않는 것을 확인할 수 있습니다.

dframe |>
  rowwise() |>
  mutate(mean_performance = mean(where(is.numeric)))
Warning: There were 4 warnings in `mutate()`.
The first warning was:
ℹ In argument: `mean_performance = mean(where(is.numeric))`.
ℹ In row 1.
Caused by warning in `mean.default()`:
! argument is not numeric or logical: returning NA
ℹ Run `dplyr::last_dplyr_warnings()` to see the 3 remaining warnings.
# A tibble: 4 × 5
# Rowwise: 
  name  first second third mean_performance
  <chr> <dbl>  <dbl> <dbl>            <dbl>
1 Jakob     1      2     3               NA
2 Eliud     4      5     6               NA
3 Jamal     7      8     9               NA
4 Emily    10     11    12               NA

이런 경우 c_across를 사용할 수 있습니다. 이 함수는 특히 rowwise()와 호환되게 개발되었으며 c()를 이용해 변환할 변수를 지정하고, 이를 감싸는 방식으로 사용할 수 있습니다. 먼저 tidyselect 함수 없이 사용해 보겠습니다:

dframe |>
  rowwise() |>
  mutate(
    mean_performance = mean(c_across(c(first, second, third))))
# A tibble: 4 × 5
# Rowwise: 
  name  first second third mean_performance
  <chr> <dbl>  <dbl> <dbl>            <dbl>
1 Jakob     1      2     3                2
2 Eliud     4      5     6                5
3 Jamal     7      8     9                8
4 Emily    10     11    12               11

예상한 대로의 결과를 얻었습니다. 이번에는 c() 대신 원하는 tidyselect 계열의 함수를 사용해보도록 하겠습니다.

dframe |>
  rowwise() |>
  mutate(
    mean_performance = mean(c_across(where(is.numeric))))
# A tibble: 4 × 5
# Rowwise: 
  name  first second third mean_performance
  <chr> <dbl>  <dbl> <dbl>            <dbl>
1 Jakob     1      2     3                2
2 Eliud     4      5     6                5
3 Jamal     7      8     9                8
4 Emily    10     11    12               11

아까 c_across 없이는 작동하지 않았던 함수가 이제 작동하는 것을 확인할 수 있습니다. 즉, c_across를 이용하면 요약 함수와 tidyselect 계열 함수들을 서로 조합하여 사용할 수 있습니다. 이는 많은 열에서 계산을 수행해야 하는 경우 유용합니다. 예를 들어, 빌보드 데이터 프레임을 한 번 살펴보도록 하겠습니다.

billboard |>
  rowwise() |>
  mutate(sum = sum(c_across(contains("wk")), na.rm = TRUE)) |> 
  dplyr::select(artist, track, sum)
# A tibble: 317 × 3
# Rowwise: 
   artist         track                     sum
   <chr>          <chr>                   <dbl>
 1 2 Pac          Baby Don't Cry (Keep...   598
 2 2Ge+her        The Hardest Part Of ...   270
 3 3 Doors Down   Kryptonite               1403
 4 3 Doors Down   Loser                    1342
 5 504 Boyz       Wobble Wobble            1012
 6 98^0           Give Me Just One Nig...   753
 7 A*Teens        Dancing Queen             485
 8 Aaliyah        I Don't Wanna            1041
 9 Aaliyah        Try Again                 533
10 Adams, Yolanda Open My Heart            1355
# ℹ 307 more rows

Don’t Forget to ungroup()

rowwise()를 사용할 때 주의하지 않으면 몇 가지 문제가 발생할 수 있는데, 가장 일반적인 실수는 데이터 프레임을 그룹 해제(ungroup())하는 것을 잊어버리는 것입니다. 앞서 말씀드렸듯이 rowwise()는 데이터를 그룹화하여 행 별로 계산이 수행되도록 할 뿐입니다. group_by()와 마찬가지로, rowwise()ungroup()을 사용하여 그룹을 해제할 수 있습니다. 그렇게 하지 않으면 다음과 같은 문제가 발생할 수 있습니다:

dframe |>
  rowwise() |>
  mutate(mean = mean(c(first, second, third))) |>
  summarise(mean_across_students = mean(mean))
# A tibble: 4 × 1
  mean_across_students
                 <dbl>
1                    2
2                    5
3                    8
4                   11

rowwise()를 해제하지 않았기 때문에 전체 학생에 대한 평균을 계산하는 대신 각 학생에 대해 평균값을 반복하여 계산합니다. 그 이유는 요약이 여전히 행 별로 계산을 수행하기 때문입니다. 이 논리적 오류를 수정하려면 데이터 프레임의 그룹을 해제해야 합니다:

dframe |>
  ungroup() |>
  mutate(mean = mean(c(first, second, third))) |>
  ungroup() |>summarise(mean_across_students = mean(mean))
# A tibble: 1 × 1
  mean_across_students
                 <dbl>
1                  6.5

따라서 rowwise()를 하고 난 이후 ungroup()을 하지 않으면 원하는 요약 데이터를 얻기 힘들며, 나아가 필요한 데이터를 머지 혹은 결합하기 어렵다는 점을 유의해야 합니다.

Calculating Proportions with rowwise()

rowwise()의 좋은 사용 사례는 값을 비율로 변환하는 것입니다. 비율을 계산하려면 먼저 모든 값의 합계를 계산해야 합니다. 데이터가 넓은 형식(wide-form)이므로 `rowwise()``로 이 작업을 수행할 수 있습니다:

(sums_per_row <- dframe |>
   rowwise() |>
   mutate(sum_per_row = sum(first, second, third)) |>
   ungroup())
# A tibble: 4 × 5
  name  first second third sum_per_row
  <chr> <dbl>  <dbl> <dbl>       <dbl>
1 Jakob     1      2     3           6
2 Eliud     4      5     6          15
3 Jamal     7      8     9          24
4 Emily    10     11    12          33

sum_per_row 열을 사용하면 모든 숫자 열을 비율로 변환할 수 있습니다:

sums_per_row |>
  mutate(
    first = first/sum_per_row,
    second = second/sum_per_row,
    third = third/sum_per_row)
# A tibble: 4 × 5
  name  first second third sum_per_row
  <chr> <dbl>  <dbl> <dbl>       <dbl>
1 Jakob 0.167  0.333 0.5             6
2 Eliud 0.267  0.333 0.4            15
3 Jamal 0.292  0.333 0.375          24
4 Emily 0.303  0.333 0.364          33

A Short Deep-dive into pmax and pmin

pminpmax는 주어진 하나 이상의 벡터에서 각각 최소값과 최대값을 찾는 함수입니다.

dframe |>
  mutate(
    max = pmax(first, second, third),
    min = pmin(first, second, third)
)
# A tibble: 4 × 6
  name  first second third   max   min
  <chr> <dbl>  <dbl> <dbl> <dbl> <dbl>
1 Jakob     1      2     3     3     1
2 Eliud     4      5     6     6     4
3 Jamal     7      8     9     9     7
4 Emily    10     11    12    12    10

안타깝게도 pmean, pmedian 또는 psum 함수는 없습니다. 하지만 행 별로 총합을 구하는 rowSums 함수가 있습니다.

dframe |>
  mutate(
    sum = rowSums(matrix(c(first, second, third), ncol = 3)))
# A tibble: 4 × 5
  name  first second third   sum
  <chr> <dbl>  <dbl> <dbl> <dbl>
1 Jakob     1      2     3     6
2 Eliud     4      5     6    15
3 Jamal     7      8     9    24
4 Emily    10     11    12    33