Rで集計表の作成 - totalize

個票データ(microdata)の足し上げを小計と合計付きで表示するパッケージ
R
公開

2023年3月26日

これまで個票データの集計というテーマでtapplybyaggregatedplyr::summariseを紹介してきました。 これらでカテゴリ別の足し上げなどを行うことができますが、小計や合計を一緒に出したいときは少し困ります。

例えばtapply関数でdatasets::CO2データについて次のような集計を行ったとします。

tapply(CO2$uptake, CO2[c("Type", "Treatment")], sum)
             Treatment
Type          nonchilled chilled
  Quebec             742   666.8
  Mississippi        545   332.1

Type別、Treatment別の集計はできましたが、ここにそれぞれのカテゴリの小計と、全体の合計を加えたい場合はどうしたらよいでしょうか。実はそれらは別途作成しなくてはなりません。

まずTypeTreatmentの計は、片方だけのカテゴリで集計することで得られます。

tapply(CO2$uptake, CO2["Treatment"], sum)
Treatment
nonchilled    chilled 
    1287.0      998.9 
tapply(CO2$uptake, CO2["Type"], sum)
Type
     Quebec Mississippi 
     1408.8       877.1 

全体の合計は、単純にsumを取るだけです。

sum(CO2$uptake)
[1] 2285.9

これらを組み合わせて表を作ります。

cbind(matrix(c(sum(CO2$uptake), tapply(CO2$uptake, CO2["Type"], sum))),
      rbind(tapply(CO2$uptake, CO2["Treatment"], sum),
            tapply(CO2$uptake, CO2[c("Type", "Treatment")], sum)))
                   nonchilled chilled
            2285.9       1287   998.9
Quebec      1408.8        742   666.8
Mississippi  877.1        545   332.1

手間がかかりますね。なぜこのような手順を踏むかと言うと、集計の関数はどれも基本的にデータ1つ1つをどこかのカテゴリに振り分けていて、1つのデータは1つのカテゴリにしか属することができないからです。上のような小計や合計を算出するには、1つのデータが自身のカテゴリに加えて小計と合計にも振り分けられる必要があります。つまり1つのデータを重複して数える必要があるのですが、それは通常の関数では一度にできないのです。

totalize

そこで、小計や合計も一度に算出する関数を自作しました。totalizeと命名しています。これを使うと次のような記述で上の表が作れます。

totalize(CO2, Type, Treatment, uptake, sum)
             Treatment
Type             all nonchilled chilled
  all         2285.9       1287   998.9
  Quebec      1408.8        742   666.8
  Mississippi  877.1        545   332.1

引数の説明をすると、

  • 1つ目にデータを指定
  • 2つ目に表の行方向に表示する変数を指定
  • 3つ目に表の列方向に表示する変数を指定
  • 4つ目に集計する変数を指定
  • 5つ目に集計関数を指定

となっています。

これは表(matrix)の形で作った例ですが、aggregate関数のようにdata frameの形で作ることもできます。それにはasDF=TRUEを指定します。

totalize(CO2, Type, Treatment, uptake, sum, asDF=TRUE)
         Type  Treatment uptake
1         all        all 2285.9
2         all nonchilled 1287.0
3         all    chilled  998.9
4      Quebec        all 1408.8
5      Quebec nonchilled  742.0
6      Quebec    chilled  666.8
7 Mississippi        all  877.1
8 Mississippi nonchilled  545.0
9 Mississippi    chilled  332.1

また、変数の値の足し上げではなくtable関数のようにデータ数をカウントしたい場合は、4つ目の引数を省略します。その場合は5つ目以降の引数は名前付きで指定する必要があります。(なお、5つ目の引数がsumならばそれも省略できます)

totalize(CO2, Type, Treatment, FUN=sum)
             Treatment
Type          all nonchilled chilled
  all          84         42      42
  Quebec       42         21      21
  Mississippi  42         21      21

non-standard evaluation

totalize関数の引数を見て、何か違和感を感じたかも知れません。実は変数の名前を指定するときにダブルクォーテーション""で囲まなくてもよいように作っています。subset関数で使われている”non-standard evaluation”を真似しています。

tidyverseパッケージの各関数は、それをさらに拡張して変数の名前の一部だけでも指定できたりしますね(starts_with()など)。totalizeはそこまでは実装していません。そこまでやるならtidyselectパッケージを利用するべきですね。このtotalizeはそういった外部パッケージを使わずに、Rにプリインストールされているパッケージだけを使って実装しているのが特徴の1つです。

インストール

totalizeはRのパッケージとして作成してあります。私のGithubで公開していますのでご興味があればご覧ください。次のコマンドでパッケージのインストールができます。(devtoolsパッケージを使います)

devtools::install_github("ichiromurata/totalize")