【R】Tidyverseの関数群でクロス集計表を作る
https://qiita.com/eitsupi/items/942d913e7b98e853a36b
であるが,tidyverse をパズルのように組み合わせて,tidyverse 食わず嫌いにとっては,何をやっているのかよくわからない。
そういうときは,そもそも,どのような結果がほしいのか,それを得るのには tidyverse を使わないでやる方法はあるのかを考える。
暫し黙考。
データが "T"/"F" で書かれているのでピンとひらめく。行列掛け算すれば一行でできる。
対角成分を NA にするかどうかは簡単な話。むしろこのままのほうが扱いやすいか?
> system.time({
+ df = as.matrix(read.csv("sampledatacross2.csv")[, -1])
+ print(t(df) %*% df)
+ })
果物.野菜 肉 日用雑貨 缶詰野菜 缶詰肉 冷凍肉 ビール ワイン 清涼飲料 魚 菓子
果物.野菜 299 59 62 86 61 86 89 84 56 145 82
肉 59 183 33 55 41 52 47 49 42 48 54
日用雑貨 62 33 177 44 31 51 45 46 35 56 56
缶詰野菜 86 55 44 303 73 173 167 97 63 89 71
缶詰肉 61 41 31 73 204 75 60 54 42 63 54
冷凍肉 86 52 51 173 75 302 170 71 54 90 66
ビール 89 47 45 167 60 170 293 77 45 85 64
ワイン 84 49 46 97 54 71 77 287 60 78 144
清涼飲料 56 42 35 63 42 54 45 60 184 52 52
魚 145 48 56 89 63 90 85 78 52 292 86
菓子 82 54 56 71 54 66 64 144 52 86 276
user system elapsed
0.003 0.001 0.006
tidyverse を使うより,150 倍ほど速い。
> library(tidyverse)
> system.time({
+ df_read <- read_csv("sampledatacross2.csv")
+ df_cross <- df_read |>
+ pivot_longer(cols = !ID) |>
+ filter(value == TRUE) |>
+ mutate(name_2 = name) |>
+ group_by(ID) |>
+ expand(name, name_2) |>
+ ungroup()
+ col_names <- df_read |>
+ names() |>
+ (\(x) x[-1])()
+
+ print(df_cross |>
+ filter(name != name_2) |>
+ pivot_wider(
+ id_cols = name,
+ names_from = name_2,
+ values_from = name_2,
+ values_fn = length
+ ) |>
+ relocate(name, {{ col_names }}) |>
+ mutate(name = name |> factor(levels = col_names)) |>
+ arrange(name) |>
+ knitr::kable())
+ })
Rows: 1000 Columns: 12
── Column specification ───────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
dbl (1): ID
lgl (11): 果物・野菜, 肉, 日用雑貨, 缶詰野菜, 缶詰肉, 冷凍肉, ビール, ワイン, 清涼飲料, 魚, 菓子
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
|name | 果物・野菜| 肉| 日用雑貨| 缶詰野菜| 缶詰肉| 冷凍肉| ビール| ワイン| 清涼飲料| 魚| 菓子|
|:---------|---------:|--:|--------:|--------:|------:|------:|------:|------:|--------:|---:|----:|
|果物・野菜 | NA| 59| 62| 86| 61| 86| 89| 84| 56| 145| 82|
|肉 | 59| NA| 33| 55| 41| 52| 47| 49| 42| 48| 54|
|日用雑貨 | 62| 33| NA| 44| 31| 51| 45| 46| 35| 56| 56|
|缶詰野菜 | 86| 55| 44| NA| 73| 173| 167| 97| 63| 89| 71|
|缶詰肉 | 61| 41| 31| 73| NA| 75| 60| 54| 42| 63| 54|
|冷凍肉 | 86| 52| 51| 173| 75| NA| 170| 71| 54| 90| 66|
|ビール | 89| 47| 45| 167| 60| 170| NA| 77| 45| 85| 64|
|ワイン | 84| 49| 46| 97| 54| 71| 77| NA| 60| 78| 144|
|清涼飲料 | 56| 42| 35| 63| 42| 54| 45| 60| NA| 52| 52|
|魚 | 145| 48| 56| 89| 63| 90| 85| 78| 52| NA| 86|
|菓子 | 82| 54| 56| 71| 54| 66| 64| 144| 52| 86| NA|
user system elapsed
0.487 0.009 0.497
元記事ではこれに引き続き,組み合わせの上位5件を抽出というのがあるのだが,仕様が今ひとつわからない。
いずれにしても,別の集計プログラムを書くよりは,上のクロス表を出発点にするのが吉かな?