<ポイント>
- データフレームを引数にとるものは purrr 0.2.2.1 から{purrrlyr}に引き継がれた
- {dplyr}の操作と類似した操作となるパッケージ化したもの
# 登録数
ls("package:purrrlyr") %>% length()
[1] 10
# 関数一覧
ls("package:purrrlyr") %>% print()
[1] "%>%" "by_row" "by_slice" "dmap" "dmap_at"
[6] "dmap_if" "invoke_rows" "map_rows" "slice_rows" "unslice"
・irisを150レコードから9レコードに縮小して使用
my_iris <- iris %>%
group_by(Species) %>%
do(head(., 3)) %>%
ungroup() %T>%
print()
## # A tibble: 9 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 7.0 3.2 4.7 1.4 versicolor
## 5 6.4 3.2 4.5 1.5 versicolor
## 6 6.9 3.1 4.9 1.5 versicolor
## 7 6.3 3.3 6.0 2.5 virginica
## 8 5.8 2.7 5.1 1.9 virginica
## 9 7.1 3.0 5.9 2.1 virginica
<処理内容>
・グループごとに何らかを処理を行う
--- 従来は{dplyr}の「group_by」でグループ化して「do」でグループ単位の処理
<モダン処理への進化>
・第1世代 dplyr: group_by + do
・第2世代 purrr: slice_rows + by_slice
・第3世代 tidyr: nest + map + unnest --- 現在最もモダンな処理
<ポイント>
・group_by()でグループ化して、do()でグループごとの処理
my_iris %>%
group_by(Species) %>%
do(head(., 2))
## Source: local data frame [6 x 5]
## Groups: Species [3]
##
## # A tibble: 6 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 7.0 3.2 4.7 1.4 versicolor
## 4 6.4 3.2 4.5 1.5 versicolor
## 5 6.3 3.3 6.0 2.5 virginica
## 6 5.8 2.7 5.1 1.9 virginica
<ポイント>
・slice_rows()でグループ化
--- dplyr::group_byと同じ
--- 列名を""で括る必要がある
my_iris %>%
purrrlyr::slice_rows("Species")
## Source: local data frame [9 x 5]
## Groups: Species [3]
##
## # A tibble: 9 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 7.0 3.2 4.7 1.4 versicolor
## 5 6.4 3.2 4.5 1.5 versicolor
## 6 6.9 3.1 4.9 1.5 versicolor
## 7 6.3 3.3 6.0 2.5 virginica
## 8 5.8 2.7 5.1 1.9 virginica
## 9 7.1 3.0 5.9 2.1 virginica
<ポイント>
・by_slice()でグループ化ごとの処理
--- 列名を""で括る必要がある
my_iris %>%
purrrlyr::slice_rows("Species") %>%
purrrlyr::by_slice(head, 2, .collate = 'rows')
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 setosa 5.1 3.5 1.4 0.2
## 2 setosa 4.9 3.0 1.4 0.2
## 3 versicolor 7.0 3.2 4.7 1.4
## 4 versicolor 6.4 3.2 4.5 1.5
## 5 virginica 6.3 3.3 6.0 2.5
## 6 virginica 5.8 2.7 5.1 1.9
<ポイント>
・tidyr::nest()でネスト化
--- グループ化に近い意味を持つ
--- ネスト化されたデータはリスト形式になっている
--- ネスト化されたデータには.key = "name"で名前を付けることができる
・ネスト化することで処理が俯瞰しやすくなる
my_iris %>%
tidyr::nest(-Species)
## # A tibble: 3 x 2
## Species data
## <fctr> <list>
## 1 setosa <tibble [3 x 4]>
## 2 versicolor <tibble [3 x 4]>
## 3 virginica <tibble [3 x 4]>
<ポイント>
・dplyr::mutate()で処理対象とする列を指定
・purrr::map()でリストごとの演算
--- map()内の「data」が忘れやすそうなので注意
my_iris %>%
tidyr::nest(-Species) %>%
dplyr::mutate(data= purrr::map(data, head, 2))
## # A tibble: 3 x 2
## Species data
## <fctr> <list>
## 1 setosa <tibble [2 x 4]>
## 2 versicolor <tibble [2 x 4]>
## 3 virginica <tibble [2 x 4]>
<ポイント>
・tidyr::unnest()でネストを解消
my_iris %>%
tidyr::nest(-Species) %>%
dplyr::mutate(data= purrr::map(data, head, 2)) %>%
tidyr::unnest()
## # A tibble: 6 x 5
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## <fctr> <dbl> <dbl> <dbl> <dbl>
## 1 setosa 5.1 3.5 1.4 0.2
## 2 setosa 4.9 3.0 1.4 0.2
## 3 versicolor 7.0 3.2 4.7 1.4
## 4 versicolor 6.4 3.2 4.5 1.5
## 5 virginica 6.3 3.3 6.0 2.5
## 6 virginica 5.8 2.7 5.1 1.9
<ポイント>
- データフレームの列ごとに関数を適用して、データフレーム形式で結果を返す
- `map()`だと出力結果をリスト形式で返す
- `dplyr::mutate_all()`や`dplyr::summarise_all()`に近い操作が可能
- 適用できるのは単一の関数のみ
- 関数を適用するのが目的であり、複数関数で要素を増やすものではない
<構文>
dmap(.d, .f, ...)
.d --- データフレーム
.f --- 適用する関数
<ポイント>
・適用する関数の性質に応じて以下の2パターンの動作となる
- 集約あり --- dplyr::summarise
- 集約なし --- dplyr::mutate
# 準備:データセットの作成
X <- my_iris %>%
slice_rows("Species") %>%
by_slice(head, 5, .collate = "rows") %T>%
print()
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 setosa 5.1 3.5 1.4 0.2
## 2 setosa 4.9 3.0 1.4 0.2
## 3 setosa 4.7 3.2 1.3 0.2
## 4 versicolor 7.0 3.2 4.7 1.4
## 5 versicolor 6.4 3.2 4.5 1.5
## 6 versicolor 6.9 3.1 4.9 1.5
## 7 virginica 6.3 3.3 6.0 2.5
## 8 virginica 5.8 2.7 5.1 1.9
## 9 virginica 7.1 3.0 5.9 2.1
# グループ化 + 集約関数
X %>% slice_rows("Species") %>% dmap(mean)
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 setosa 4.900000 3.233333 1.366667 0.200000
## 2 versicolor 6.766667 3.166667 4.700000 1.466667
## 3 virginica 6.400000 3.000000 5.666667 2.166667
# グループ化 + 個別演算
X %>% slice_rows("Species") %>% dmap(~ .x / max(.x))
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 setosa 1.0000000 1.0000000 1.0000000 1.0000000
## 2 setosa 0.9607843 0.8571429 1.0000000 1.0000000
## 3 setosa 0.9215686 0.9142857 0.9285714 1.0000000
## 4 versicolor 1.0000000 1.0000000 0.9591837 0.9333333
## 5 versicolor 0.9142857 1.0000000 0.9183673 1.0000000
## 6 versicolor 0.9857143 0.9687500 1.0000000 1.0000000
## 7 virginica 0.8873239 1.0000000 1.0000000 1.0000000
## 8 virginica 0.8169014 0.8181818 0.8500000 0.7600000
## 9 virginica 1.0000000 0.9090909 0.9833333 0.8400000
<ポイント>
・1つのベクトルに対して6つの要約データをtableクラスで返す
- 行番号に項目はついておらず、各要素が何を意味するかは配置で判断するしかない
# 列ごとに集計関数を適用
X <- my_iris[, 1:4] %>% dmap(summary) %T>% print()
## # A tibble: 6 x 4
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## <S3: table> <S3: table> <S3: table> <S3: table>
## 1 4.700 2.700 1.300 0.200
## 2 5.100 3.000 1.400 0.200
## 3 6.300 3.200 4.700 1.500
## 4 6.022 3.133 3.911 1.278
## 5 6.900 3.200 5.100 1.900
## 6 7.100 3.500 6.000 2.500
# 属性確認
X %>% attributes()
## $names
## [1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width"
##
## $class
## [1] "tbl_df" "tbl" "data.frame"
##
## $row.names
## [1] 1 2 3 4 5 6
<ポイント>
・1つのベクトルに対して6つの要約データをtableクラスで返す
# ベクトルデータへの適用
X <- my_iris$Sepal.Length %>% summary() %T>% print()
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 4.700 5.100 6.300 6.022 6.900 7.100
# データ構造の確認
X %>% attributes()
## $names
## [1] "Min." "1st Qu." "Median" "Mean" "3rd Qu." "Max."
##
## $class
## [1] "summaryDefault" "table"
<ポイント>
・dmap関数 --- 出力結果はデータフレーム形式
・map関数 --- 出力結果はリスト形式
# dmap関数
my_iris[, 1:4] %>% dmap(summary)
## # A tibble: 6 x 4
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## <S3: table> <S3: table> <S3: table> <S3: table>
## 1 4.700 2.700 1.300 0.200
## 2 5.100 3.000 1.400 0.200
## 3 6.300 3.200 4.700 1.500
## 4 6.022 3.133 3.911 1.278
## 5 6.900 3.200 5.100 1.900
## 6 7.100 3.500 6.000 2.500
# map関数
my_iris[, 1:4] %>% map(summary)
## $Sepal.Length
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 4.700 5.100 6.300 6.022 6.900 7.100
##
## $Sepal.Width
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2.700 3.000 3.200 3.133 3.200 3.500
##
## $Petal.Length
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.300 1.400 4.700 3.911 5.100 6.000
##
## $Petal.Width
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.200 0.200 1.500 1.278 1.900 2.500
<ポイント>
・dmap()の適用箇所を任意で指定する
・全ての列への適用を前提としていないので、結果は集約されない
<構文>
dmap_at(.d, .at, .f, ...)
.d --- データフレーム
.at --- 適応個所をベクトル形式で指定
.f --- 適用する関数
# 番号で指定
my_iris[, 1:4] %>% dmap_at(c(1:2), sum) %>% head(3)
## # A tibble: 3 x 4
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## <dbl> <dbl> <dbl> <dbl>
## 1 54.2 28.2 1.4 0.2
## 2 54.2 28.2 1.4 0.2
## 3 54.2 28.2 1.3 0.2
# 名前で指定
my_iris[1:4] %>% dmap_at(c("Sepal.Length", "Petal.Length"), sum) %>% head(3)
## # A tibble: 3 x 4
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## <dbl> <dbl> <dbl> <dbl>
## 1 54.2 3.5 35.2 0.2
## 2 54.2 3.0 35.2 0.2
## 3 54.2 3.2 35.2 0.2
<ポイント>
・dmap()の適用箇所を条件指定する
・全ての列への適用を前提としていないので、結果は集約されない
<構文>
dmap_if(.d, .p, .f, ...)
.d --- データフレーム
.p --- 条件指定
.f --- 適用する関数
<ポイント>
・is.関数のような条件判定関数で判定する
・TRUEの列のみ関数が適用される
# 条件指定
my_iris %>% dmap_if(is.numeric, sum) %>% head()
## # A tibble: 6 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 54.2 28.2 35.2 11.5 setosa
## 2 54.2 28.2 35.2 11.5 setosa
## 3 54.2 28.2 35.2 11.5 setosa
## 4 54.2 28.2 35.2 11.5 versicolor
## 5 54.2 28.2 35.2 11.5 versicolor
## 6 54.2 28.2 35.2 11.5 versicolor
<ポイント>
- `slice_rows()`はデータフレームにグループ情報を与える
- `dplyr::group_by()`に相当する関数
- 関数を適用してもデータに表面上の変化はない ("Groups:"が追加される)
- グループ情報はベクトル形式で与える
- 1段階グループの場合は「"列名"」として指定する
- 2段階以上の場合は「c("列名1", "列名2", )」で
- NULLでグループ化するとグループ解除ができる
- unslice()やdplyr::ungroup()と同様
<ポイント>
・列名はベクトル形式で指定するので「""」で括る必要がある
# グループ化
X <- my_iris %>% slice_rows("Species") %T>% print()
## Source: local data frame [9 x 5]
## Groups: Species [3]
##
## # A tibble: 9 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 7.0 3.2 4.7 1.4 versicolor
## 5 6.4 3.2 4.5 1.5 versicolor
## 6 6.9 3.1 4.9 1.5 versicolor
## 7 6.3 3.3 6.0 2.5 virginica
## 8 5.8 2.7 5.1 1.9 virginica
## 9 7.1 3.0 5.9 2.1 virginica
# グループごとに合計
X %>% dmap(sum)
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 setosa 14.7 9.7 4.1 0.6
## 2 versicolor 20.3 9.5 14.1 4.4
## 3 virginica 19.2 9.0 17.0 6.5
<ポイント>
・列名はベクトル形式で指定するので「c()」で括る必要がある
# データセットの確認
warpbreaks %>% glimpse()
## Observations: 54
## Variables: 3
## $ breaks <dbl> 26, 30, 54, 25, 70, 52, 51, 26, 67, 18, 21, 29, 17, 12...
## $ wool <fctr> A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,...
## $ tension <fctr> L, L, L, L, L, L, L, L, L, M, M, M, M, M, M, M, M, M,...
# グループ属性の確認
X <- warpbreaks %>% slice_rows(c("wool", "tension")) %T>% print()
## Source: local data frame [54 x 3]
## Groups: wool, tension [6]
##
## # A tibble: 54 x 3
## breaks wool tension
## <dbl> <fctr> <fctr>
## 1 26 A L
## 2 30 A L
## 3 54 A L
## 4 25 A L
## 5 70 A L
## 6 52 A L
## 7 51 A L
## 8 26 A L
## 9 67 A L
## 10 18 A M
## # ... with 44 more rows
# グループ化 + 合計
X %>% dmap(sum)
## wool tension breaks
## 1 A L 401
## 2 A M 216
## 3 A H 221
## 4 B L 254
## 5 B M 259
## 6 B H 169
<ポイント>
・NULLでグループ化するとグループ解除できる
- unslice()やdplyr::ungroup()と同様
・空白でグループ化してもグループ解除できる
# 準備:グループ属性の確認
X <- my_iris %>% slice_rows("Species") %>% head(3) %T>% print()
## Source: local data frame [3 x 5]
## Groups: Species [1]
##
## # A tibble: 3 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
# NULLでグループ化するとグループ解除
X %>% slice_rows(NULL) %>% head(3)
## # A tibble: 3 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
# 空白でグループ化してもグループ解除
X %>% slice_rows() %>% head(3)
## # A tibble: 3 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
<概要>
・グループ情報を削除する
<類似処理>
・slice_rows("引数なし")
・slice_rows(NULL)
・dplyr::ungroup()と同様
<ポイント>
・列名はベクトル形式で指定するので「""」で括る必要がある
# 準備:グループ属性の付与
X <- my_iris %>% slice_rows("Species") %T>% print()
## Source: local data frame [9 x 5]
## Groups: Species [3]
##
## # A tibble: 9 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 7.0 3.2 4.7 1.4 versicolor
## 5 6.4 3.2 4.5 1.5 versicolor
## 6 6.9 3.1 4.9 1.5 versicolor
## 7 6.3 3.3 6.0 2.5 virginica
## 8 5.8 2.7 5.1 1.9 virginica
## 9 7.1 3.0 5.9 2.1 virginica
# グループ化を解消
X %>% unslice()
## # A tibble: 9 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 7.0 3.2 4.7 1.4 versicolor
## 5 6.4 3.2 4.5 1.5 versicolor
## 6 6.9 3.1 4.9 1.5 versicolor
## 7 6.3 3.3 6.0 2.5 virginica
## 8 5.8 2.7 5.1 1.9 virginica
## 9 7.1 3.0 5.9 2.1 virginica
<概要>
・グループごとに関数を適用して、ネスト形式のデータフレームで出力される
- 1行ごとに関数を適用する場合はby_row()を使用する
- 行番号でグループ化することで類似処理が可能
<前提>
・グループ化されたデータフレームに使用することを前提とする
<類似処理>
・dplyr::do
# 準備:グループ化
X <- my_iris %>% slice_rows("Species") %T>% print()
## Source: local data frame [9 x 5]
## Groups: Species [3]
##
## # A tibble: 9 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 7.0 3.2 4.7 1.4 versicolor
## 5 6.4 3.2 4.5 1.5 versicolor
## 6 6.9 3.1 4.9 1.5 versicolor
## 7 6.3 3.3 6.0 2.5 virginica
## 8 5.8 2.7 5.1 1.9 virginica
## 9 7.1 3.0 5.9 2.1 virginica
# グループごとに行方向に集計
X %>% by_slice(dmap, mean, .collate = "rows")
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 setosa 4.900000 3.233333 1.366667 0.200000
## 2 versicolor 6.766667 3.166667 4.700000 1.466667
## 3 virginica 6.400000 3.000000 5.666667 2.166667
<概要>
- grouped_dfを受け取って`グループごと`に関数を適用する
- `dplyr::rowwise() %>% dplyr::do()`に相当する関数
<前提>
・特になし
- 予め行単位でグループ化する必要はない
<構文>
by_row(.d, .f, ..., .collate = c("list", "rows", "cols"),
.to = ".out", .labels = TRUE)
.d --- データフレーム
.f --- 適用する関数
... --- 適用する関数の引数
collate --- 集計方向
.to --- 集計結果の列名等
.labels --- FALSEなら集計結果のみを表示
<ポイント>
・データフレームの行ごとに列方向の集計を行う
- .collate : 集計方向を指定 (初期値:list colsは集計結果が単一要素の場合)
- .to : 集計列の名前
・データセットがグループ化の状態になっていない点に注意
# 初期設定では列方向に指定した演算を行う
# --- 集計値は初期状態ではリストに格納
X <- my_iris[, 1:4] %>% by_row(sum) %>% head(3) %T>% print()
## # A tibble: 3 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width .out
## <dbl> <dbl> <dbl> <dbl> <list>
## 1 5.1 3.5 1.4 0.2 <dbl [1]>
## 2 4.9 3.0 1.4 0.2 <dbl [1]>
## 3 4.7 3.2 1.3 0.2 <dbl [1]>
# リストを解消
X %>% unnest()
## # A tibble: 3 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width .out
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 5.1 3.5 1.4 0.2 10.2
## 2 4.9 3.0 1.4 0.2 9.5
## 3 4.7 3.2 1.3 0.2 9.4
<ポイント>
・データフレームの行ごとに列方向の集計を行う
- .collate : 集計方向を指定 (colsは集計結果が単一要素の場合)
- .to : 集計列の名前
・集計結果がリストになっていない点に注意
# 集計方法と集計列を指定
my_iris[, 1:4] %>% by_row(sum, .collate = "cols", .to = "Sum") %>% head(3)
## # A tibble: 3 x 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Sum
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 5.1 3.5 1.4 0.2 10.2
## 2 4.9 3.0 1.4 0.2 9.5
## 3 4.7 3.2 1.3 0.2 9.4
<概要>
- grouped_dfを受け取って`グループごと`に関数を適用する
- `dplyr::rowwise() %>% dplyr::do()`に相当する関数
- `map_row()`の後継版
X <- my_iris[1:4] %>% as_tibble() %T>% print()
X %>% by_row(sum) %>% head()
X %>% unnest()
<概要>
・リタイア予定
・invoke_row() や pmap() と同様の操作
--- 関数の中では invoke_row() を参照している
--- pmapは複数のリスト要素を串刺しにして演算、mapply()に似ている
<関数定義>
function (.d, .f, ..., .labels = TRUE)
{
deprecate("`map_rows()` is deprecated; please use `pmap()` instead.")
invoke_rows(.f, .d, ..., .labels = .labels)
}
# 準備:リストの作成
X <- list(a = 1:3, b = 4:6) %T>% print()
## $a
## [1] 1 2 3
##
## $b
## [1] 4 5 6
# リスト要素を串刺しに演算
# --- 出力はリスト形式
X %>% pmap(function(a, b) {a * b})
## [[1]]
## [1] 4
##
## [[2]]
## [1] 10
##
## [[3]]
## [1] 18
# リスト要素を串刺しに演算
# --- 出力はベクトル形式
X %>% pmap_dbl(function(a, b) {a * b})
## [1] 4 10 18