dplyrで周辺合計を計算する

R
作者

伊東宏樹

公開

2023年7月30日

Rでは、配列(array)や行列(matrix)だと、basemarginSums関数で周辺合計が計算できますが、この関数はデータフレームには適用できません。janitorパッケージを使うと簡単にできるそうなのですが、dplyrでなんとかしてみました。

準備

まずは、dplyrパッケージとtibbleパッケージを読み込み、さらにデータを作成します。

library(dplyr)
## 
##  次のパッケージを付け加えます: 'dplyr'
##  以下のオブジェクトは 'package:stats' からマスクされています:
## 
##     filter, lag
##  以下のオブジェクトは 'package:base' からマスクされています:
## 
##     intersect, setdiff, setequal, union
library(tibble)

set.seed(123)
ncol <- 7
nrow <- 4
d <- matrix(rpois(ncol * nrow, 3), ncol = ncol, nrow = nrow)
colnames(d) <- letters[1:ncol]
rownames(d) <- letters[23:(22 + nrow)]
print(d)
##   a b c d e f g
## w 2 6 3 4 2 5 4
## x 4 0 3 3 0 4 4
## y 2 3 6 1 2 3 3
## z 5 5 3 5 6 8 3

marginSums関数

行列ならmarginSums関数で周辺合計が計算できます。

marginSums(d, 1)
##  w  x  y  z 
## 26 18 20 35
marginSums(d, 2)
##  a  b  c  d  e  f  g 
## 13 14 15 13 10 20 14

データをtibble形式に変換して、行の名前をnameという列に入れるようにしました。

tbl <- as_tibble(d) %>%
  add_column(name = letters[23:(22 + nrow)]) %>%
  relocate(name, letters[1:ncol])
print(tbl)
## # A tibble: 4 × 8
##   name      a     b     c     d     e     f     g
##   <chr> <int> <int> <int> <int> <int> <int> <int>
## 1 w         2     6     3     4     2     5     4
## 2 x         4     0     3     3     0     4     4
## 3 y         2     3     6     1     2     3     3
## 4 z         5     5     3     5     6     8     3

tibbleに対してmarginSums関数を適用しようとすると、

marginSums(tbl, 1)

「marginSums(tbl, 1) でエラー: ‘x’ は配列ではありません」といわれてしまいます。

dplyrで計算する場合

そこで、dplyrrowwise関数を使い、sum(c_across(-name))として、name以外の各行の合計を求め、totalという列に入れるようにしました。

tbl_rtot <- tbl %>%
  rowwise() %>%
  mutate(total = sum(c_across(-name)))
print(tbl_rtot)
## # A tibble: 4 × 9
## # Rowwise: 
##   name      a     b     c     d     e     f     g total
##   <chr> <int> <int> <int> <int> <int> <int> <int> <int>
## 1 w         2     6     3     4     2     5     4    26
## 2 x         4     0     3     3     0     4     4    18
## 3 y         2     3     6     1     2     3     3    20
## 4 z         5     5     3     5     6     8     3    35

次に、name以外の各列の合計を求めます。ungrouprowwiseを解除しておきます。

col_sum <- tbl_rtot %>%
  ungroup() %>%
  summarise(across(-name, sum))
print(col_sum)
## # A tibble: 1 × 8
##       a     b     c     d     e     f     g total
##   <int> <int> <int> <int> <int> <int> <int> <int>
## 1    13    14    15    13    10    20    14    99

tibbleadd_row関数で元の表の最後の行として、周辺合計を追加します。これで、周辺合計(と総計)を追加した表の完成です。

tbl_total <- tbl_rtot %>%
  add_row(bind_cols(name = "total", col_sum))
print(tbl_total)
## # A tibble: 5 × 9
## # Rowwise: 
##   name      a     b     c     d     e     f     g total
##   <chr> <int> <int> <int> <int> <int> <int> <int> <int>
## 1 w         2     6     3     4     2     5     4    26
## 2 x         4     0     3     3     0     4     4    18
## 3 y         2     3     6     1     2     3     3    20
## 4 z         5     5     3     5     6     8     3    35
## 5 total    13    14    15    13    10    20    14    99