6 要約値を作る:summarise

  • 本章のポイント
    • パッケージdplyrの関数summarise()
    • 結果をデータフレームとして出力するため,扱いが便利
    • データを知るうえで要約作業は頻繁に行うことが想定される
    • 便利な要約パッケージが色々あるものの,summarise()は柔軟な出力が可能なので使いこなせると役に立つ

6.1 基本

  • summarise()の中に出力したい変数名を書き,=の後に計算する関数を入れる
  • 例:bill_length_mmの平均値を算出する
  • データは2.1で読み込んだdfを使用
# まだtidyverseパッケージを読み込んでない場合は以下の#を外して実行
# library(tidyverse)

df |> 
  summarise(blm_平均値 = mean(bill_length_mm, na.rm = TRUE))
## # A tibble: 1 × 1
##   blm_平均値
##        <dbl>
## 1       43.9

6.2 複数の計算

  • 複数の変数について平均値と標準偏差(SD)と人数(n)を出したいときは,基本知識では全部書くので長くなる
    • SDはsd()関数,nは変数内の欠損のない行以外の数の合計で算出
    • sum(!is.na(.x))は,NAのない行の数を総計するので,平均値やSDの計算に用いた人数を取得できる
df |> 
  summarise(blm_mean = mean(bill_length_mm, na.rm = TRUE),
            bdm_mean = mean(bill_depth_mm, na.rm = TRUE),
            blm_sd = sd(bill_length_mm, na.rm = TRUE),
            bdm_sd = sd(bill_depth_mm, na.rm = TRUE),
            blm_n  = sum(!is.na(bill_length_mm)),
            bdm_n  = sum(!is.na(bill_depth_mm)))
## # A tibble: 1 × 6
##   blm_mean bdm_mean blm_sd bdm_sd blm_n bdm_n
##      <dbl>    <dbl>  <dbl>  <dbl> <int> <int>
## 1     43.9     17.2   5.46   1.97   342   342

6.2.1 【効率化】

  • 5.3.2で出てきたacross()がここでも有用
  • across()の第一引数に指定したい変数名ベクトル,またはヘルパー関数を入れる
  • 実行したい関数を無名関数としてlist内に名前(これが接尾辞になる)をつけて列挙する
df |> 
  summarise(across(c(bill_length_mm, bill_depth_mm),
                   list(mean = \(x) mean(x, na.rm = TRUE),
                          sd = \(x)   sd(x, na.rm = TRUE),
                           n = \(x)  sum(!is.na(x)))))
## # A tibble: 1 × 6
##   bill_length_mm_mean bill_length_mm_sd bill_length_mm_n
##                 <dbl>             <dbl>            <int>
## 1                43.9              5.46              342
## # ℹ 3 more variables: bill_depth_mm_mean <dbl>,
## #   bill_depth_mm_sd <dbl>, bill_depth_mm_n <int>
# purrr 1.0.0より前のバージョンでの書き方
# df |> 
#   summarise(across(c(bill_length_mm, bill_depth_mm),
#                    list(mean = ~mean(.x, na.rm = TRUE),
#                           sd = ~sd(.x, na.rm = TRUE),
#                            n = ~sum(!is.na(.x)))))
  • across()ではヘルパー関数が使える
df |> 
  summarise(across(starts_with("bill"),
                   list(mean = \(x) mean(x, na.rm = TRUE),
                          sd = \(x)   sd(x, na.rm = TRUE),
                           n = \(x)  sum(!is.na(x)))))
## # A tibble: 1 × 6
##   bill_length_mm_mean bill_length_mm_sd bill_length_mm_n
##                 <dbl>             <dbl>            <int>
## 1                43.9              5.46              342
## # ℹ 3 more variables: bill_depth_mm_mean <dbl>,
## #   bill_depth_mm_sd <dbl>, bill_depth_mm_n <int>
  • list()内に関数を並べている部分は,関数を名前付きリストにしているだけなので,外に出して1回オブジェクトとして指定すれば記述がすっきりするし,後の同じ作業で繰り返し使える
# 関数のリストをオブジェクトfnlistに格納
fnlist <- 
  list(mean = \(x) mean(x, na.rm = TRUE),
         sd = \(x)   sd(x, na.rm = TRUE),
          n = \(x)  sum(!is.na(x)))


df |> 
  summarise(across(ends_with("mm"),
                   all_of(fnlist)))
## # A tibble: 1 × 9
##   bill_length_mm_mean bill_length_mm_sd bill_length_mm_n
##                 <dbl>             <dbl>            <int>
## 1                43.9              5.46              342
## # ℹ 6 more variables: bill_depth_mm_mean <dbl>,
## #   bill_depth_mm_sd <dbl>, bill_depth_mm_n <int>,
## #   flipper_length_mm_mean <dbl>, flipper_length_mm_sd <dbl>,
## #   flipper_length_mm_n <int>

6.2.2 【並び替え】

  • 上記の出力は横に長いため見にくい
  • tidyr::pivot_longer()で,データフレームの行列入れ替えができる
  • 引数をnames_patternnames_toを下記のように指定することで,変数の接尾辞を列名にできる
  • 下記コードのsummarise()部分の構造は前のチャンクと変数名以外同じ
df |> 
  summarise(across(bill_length_mm:body_mass_g,
                   list(mean = \(x) mean(x, na.rm = TRUE),
                          sd = \(x)   sd(x, na.rm = TRUE),
                           n = \(x)  sum(!is.na(x))))) |> 
  pivot_longer(everything(),
               names_to = c("items", ".value"), # ".value"の部分を列名に
               names_pattern = "(.*)_(.*)")    # 正規表現
## # A tibble: 4 × 4
##   items               mean     sd     n
##   <chr>              <dbl>  <dbl> <int>
## 1 bill_length_mm      43.9   5.46   342
## 2 bill_depth_mm       17.2   1.97   342
## 3 flipper_length_mm  201.   14.1    342
## 4 body_mass_g       4202.  802.     342

6.2.3 [練習問題]

  • dfデータの変数名に”length”を含む変数に対して平均値とSDとnを計算したデータフレームを作成して”res”オブジェクトに格納しよう
  • 次に作成したデータフレームをpivot_longer()を使って見やすいように縦に変換しよう

6.3 層別(グループ別)集計

  • group_by()にグループを表す変数を指定するとできる
df |> 
  group_by(species) |> 
  summarise(across(c(bill_length_mm, bill_depth_mm),
                   list(mean = \(x) mean(x, na.rm = TRUE),
                          sd = \(x)   sd(x, na.rm = TRUE))))
## # A tibble: 3 × 5
##   species   bill_length_mm_mean bill_length_mm_sd
##   <fct>                   <dbl>             <dbl>
## 1 Adelie                   38.8              2.66
## 2 Chinstrap                48.8              3.34
## 3 Gentoo                   47.5              3.08
## # ℹ 2 more variables: bill_depth_mm_mean <dbl>,
## #   bill_depth_mm_sd <dbl>
  • グループを重ねることも可能
df |> 
  group_by(species, sex) |> 
  summarise(across(c(bill_length_mm, bill_depth_mm),
                   list(mean = \(x) mean(x, na.rm = TRUE),
                          sd = \(x)   sd(x, na.rm = TRUE))))
## # A tibble: 8 × 6
## # Groups:   species [3]
##   species   sex    bill_length_mm_mean bill_length_mm_sd
##   <fct>     <fct>                <dbl>             <dbl>
## 1 Adelie    female                37.3              2.03
## 2 Adelie    male                  40.4              2.28
## 3 Adelie    <NA>                  37.8              2.80
## 4 Chinstrap female                46.6              3.11
## 5 Chinstrap male                  51.1              1.56
## 6 Gentoo    female                45.6              2.05
## 7 Gentoo    male                  49.5              2.72
## 8 Gentoo    <NA>                  45.6              1.37
## # ℹ 2 more variables: bill_depth_mm_mean <dbl>,
## #   bill_depth_mm_sd <dbl>

6.3.1 [練習問題]

  • dfデータの変数”bill_length_mm”, “bill_depth_mm”について,3変数(species, island, sex)の層別平均値(変数名に”_平均”の接頭辞をつける)を計算しよう

6.4 【効率化】関数にする

  • 関数作成の基本は(1.4.2.2参照)

6.4.1 複数変数の平均値とSDとnを計算する関数

  • {{ }}」はcurly curlyと読み,関数を作成するときに,代入先の変数名の場所を指定する時などに活躍
    • 下記の例の場合,{{ }}を外すと動かない
  • 例:引数にデータフレーム(data)と変数(vars)を入れると平均値とSDとnを返す関数mean_sd_n()を定義
mean_sd_n <- function(data, vars){
  data |> 
    summarise(across({{vars}},
                     list(mean = \(x) mean(x, na.rm = TRUE),
                            sd = \(x) sd(x, na.rm = TRUE),
                             n = \(x) sum(!is.na(x)))))
}
  • ここで定義した関数mean_sd_n()に引数としてデータフレームと変数を入れると結果が表示される
mean_sd_n(df, bill_length_mm)
## # A tibble: 1 × 3
##   bill_length_mm_mean bill_length_mm_sd bill_length_mm_n
##                 <dbl>             <dbl>            <int>
## 1                43.9              5.46              342
  • 引数varsの部分はacross()の第一引数に入れるものと同じ指定ができるため,変数ベクトルやヘルパー関数が入る
# 変数ベクトル
mean_sd_n(df, c(flipper_length_mm, body_mass_g))
## # A tibble: 1 × 6
##   flipper_length_mm_mean flipper_length_mm_sd flipper_length_mm_n
##                    <dbl>                <dbl>               <int>
## 1                   201.                 14.1                 342
## # ℹ 3 more variables: body_mass_g_mean <dbl>,
## #   body_mass_g_sd <dbl>, body_mass_g_n <int>
# 文字でも可能
# mean_sd_n(df, c("flipper_length_mm", "body_mass_g"))

# ヘルパー関数
mean_sd_n(df, starts_with("bill"))
## # A tibble: 1 × 6
##   bill_length_mm_mean bill_length_mm_sd bill_length_mm_n
##                 <dbl>             <dbl>            <int>
## 1                43.9              5.46              342
## # ℹ 3 more variables: bill_depth_mm_mean <dbl>,
## #   bill_depth_mm_sd <dbl>, bill_depth_mm_n <int>