-
Notifications
You must be signed in to change notification settings - Fork 0
/
summarise.Rmd
216 lines (153 loc) · 6.83 KB
/
summarise.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# 要約値を作る:summarise {#summarise}
* 本章のポイント
+ パッケージ`dplyr`の関数`summarise()`
+ 結果をデータフレームとして出力するため,扱いが便利
+ データを知るうえで要約作業は頻繁に行うことが想定される
+ 便利な要約パッケージが色々あるものの,`summarise()`は柔軟な出力が可能なので使いこなせると役に立つ
## 基本 {#su-st}
* `summarise()`の中に出力したい変数名を書き,`=`の後に計算する関数を入れる
* 例:bill_length_mmの平均値を算出する
* データは\@ref(select-read)で読み込んだdfを使用
```{r}
# まだtidyverseパッケージを読み込んでない場合は以下の#を外して実行
# library(tidyverse)
df |>
summarise(blm_平均値 = mean(bill_length_mm, na.rm = TRUE))
```
## 複数の計算 {#su-st-multiple}
* 複数の変数について平均値と標準偏差(SD)と人数(n)を出したいときは,基本知識では全部書くので長くなる
+ SDは`sd()`関数,nは変数内の欠損のない行以外の数の合計で算出
+ `sum(!is.na(.x))`は,NAのない行の数を総計するので,平均値やSDの計算に用いた人数を取得できる
```{r}
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)))
```
### 【効率化】{#su-st-ef}
* \@ref(mu-kata-across)で出てきた`across()`がここでも有用
* `across()`の第一引数に指定したい変数名ベクトル,またはヘルパー関数を入れる
* 実行したい関数をlist内に名前(これが接尾辞になる)をつけて列挙し,関数の前に`~`をつける
```{r}
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()`ではヘルパー関数が使える
```{r}
df |>
summarise(across(starts_with("bill"),
list(mean = ~mean(.x, na.rm = TRUE),
sd = ~sd(.x, na.rm = TRUE),
n = ~sum(!is.na(.x)))))
```
* `list()`内に関数を並べている部分は,関数を名前付きリストにしているだけなので,外に出して1回オブジェクトとして指定すれば繰り返し使える
```{r}
fnlist <-
list(mean = ~mean(.x, na.rm = TRUE),
sd = ~sd(.x, na.rm = TRUE),
n = ~sum(!is.na(.x)))
df |>
summarise(across(ends_with("mm"),
all_of(fnlist)))
```
### 【並び替え】{#su-st-reorder}
* 上記の出力は横に長いため見にくい
* `tidyr::pivot_longer()`で,データフレームの行列入れ替えができる
* 引数を`names_pattern`と`names_to`を下記のように指定することで,変数の接尾辞を列名にできる
* 下記コードの`summarise()`部分の構造は前のチャンクと変数名以外同じ
```{r}
df |>
summarise(across(bill_length_mm:body_mass_g,
list(mean = ~mean(.x, na.rm = TRUE),
sd = ~sd(.x, na.rm = TRUE),
n = ~sum(!is.na(.x))))) |>
pivot_longer(everything(),
names_to = c("items", ".value"), # ".value"の部分を列名に
names_pattern = "(.*)_(.*)") # 正規表現
```
### [練習問題]
* dfデータの変数名に"length"を含む変数に対して平均値とSDとnを計算したデータフレームを作成して"res"オブジェクトに格納しよう
* 次に作成したデータフレームを`pivot_longer()`を使って見やすいように縦に変換しよう
```{r eval=FALSE, include=FALSE}
res <-
df |>
summarise(across(contains("length"),
list(mean = ~mean(.x, na.rm = TRUE),
sd = ~sd(.x, na.rm = TRUE),
n = ~sum(!is.na(.x)))))
res |>
pivot_longer(everything(),
names_to = c("items", ".value"), # ".value"の部分を列名に
names_pattern = "(.*)_(.*)") # 正規表現
# 確認
df |>
summarise(n = sum(!is.na(bill_length_mm)))
```
## 層別(グループ別)集計{#su-group}
* `group_by()`にグループを表す変数を指定するとできる
```{r}
df |>
group_by(species) |>
summarise(across(c(bill_length_mm, bill_depth_mm),
list(mean = ~mean(.x, na.rm = TRUE),
sd = ~sd(.x, na.rm = TRUE))))
```
* グループを重ねることも可能
```{r}
df |>
group_by(species, sex) |>
summarise(across(c(bill_length_mm, bill_depth_mm),
list(mean = ~mean(.x, na.rm = TRUE),
sd = ~sd(.x, na.rm = TRUE))))
```
### [練習問題]
* dfデータの変数"bill_length_mm", "bill_depth_mm"について,3変数(species, island, sex)の層別平均値(変数名に"_平均"の接頭辞をつける)を計算しよう
```{r eval=FALSE, include=FALSE}
df |>
group_by(species, island, sex) |>
summarise(across(c(bill_length_mm, bill_depth_mm),
list(平均 = ~mean(.x, na.rm = TRUE))))
```
## 【効率化】関数にする{#su-fun}
### 基本{#su-fun-st}
* 「`自分で名づける関数名 <- function(引数){ 計算式やコード }`」 で関数を定義できる
* 例:関数の引数に数値を入れると`+1`した値を返す関数`add_one()`を定義
```{r}
add_one <-
function(x){
x + 1
}
add_one(2)
```
### 複数変数の平均値とSDとnを計算する関数{#su-fun-meansdn}
* 「`{{ }}`」は`curly curly`と読み,関数を作成するときに,代入先の変数名の場所を指定する時などに活躍
+ 下記の例の場合,`{{ }}`を外すと動かない
* 例:引数にデータフレーム(data)と変数(vars)を入れると平均値とSDとnを返す関数`mean_sd_n()`を定義
```{r}
mean_sd_n <- function(data, vars){
data |>
summarise(across({{vars}},
list(mean = ~mean(.x, na.rm = TRUE),
sd = ~sd(.x, na.rm = TRUE),
n = ~sum(!is.na(.x)))))
}
```
* ここで定義した関数`mean_sd_n()`にデータフレームと変数を入れると結果が表示される
```{r}
mean_sd_n(df, bill_length_mm)
```
* vasの部分は`across()`の第一引数に入れるものと同じ指定ができるため,変数ベクトルやヘルパー関数が入る
```{r}
# 変数ベクトル
mean_sd_n(df, c(flipper_length_mm, body_mass_g))
# 文字でも可能
# mean_sd_n(df, c("flipper_length_mm", "body_mass_g"))
# ヘルパー関数
mean_sd_n(df, starts_with("bill"))
```