dplyrを使用して複数の列にまたがる合計


98

私の質問には、データフレームの複数の列にわたる値を合計し、を使用してこの合計に対応する新しい列を作成することが含まれますdplyr。列のデータエントリはbinary(0,1)です。のsummarise_eachormutate_each関数の行方向のアナログを考えていdplyrます。以下は、データフレームの最小限の例です。

library(dplyr)
df=data.frame(
  x1=c(1,0,0,NA,0,1,1,NA,0,1),
  x2=c(1,1,NA,1,1,0,NA,NA,0,1),
  x3=c(0,1,0,1,1,0,NA,NA,0,1),
  x4=c(1,0,NA,1,0,0,NA,0,0,1),
  x5=c(1,1,NA,1,1,1,NA,1,0,1))

> df
   x1 x2 x3 x4 x5
1   1  1  0  1  1
2   0  1  1  0  1
3   0 NA  0 NA NA
4  NA  1  1  1  1
5   0  1  1  0  1
6   1  0  0  0  1
7   1 NA NA NA NA
8  NA NA NA  0  1
9   0  0  0  0  0
10  1  1  1  1  1

私は次のようなものを使用できます:

df <- df %>% mutate(sumrow= x1 + x2 + x3 + x4 + x5)

ただし、これには各列の名前を書き出すことが含まれます。私は50列が好きです。さらに、列名は、この操作を実装するループのさまざまな反復で変更されるため、列名を指定する必要がないようにしたいと思います。

どうすればそれを最も効率的に行うことができますか?どんな援助も大歓迎です。


11
なぜdplyrですか?df$sumrow <- rowSums(df, na.rm = TRUE)ベースRから単純なものではないのはなぜですか?またはdf$sumrow <- Reduce(`+`, df)、で行ったのとまったく同じことを複製したい場合dplyr
David Arenburg 2015年

7
あなたはとの両方を行うことができますdplyrのように、あまりにもdf %>% mutate(sumrow = Reduce(`+`, .))df %>% mutate(sumrow = rowSums(.))
デヴィッドArenburg

2
最新dplyrバージョンに更新すれば動作します。
デビッドアレンバーグ2015年

1
David Arenburgによる提案は、パッケージdplyr @DavidArenburgを更新した後に機能しました
amo

1
@boern David Arenburgsのコメントが最良の答えであり、最も直接的な解決策でした。あなたの答えはうまくいくでしょうが、それはNA値をゼロに置き換える追加のステップを含み、それは場合によっては適切でないかもしれません。
amo 2016

回答:


112

どうですか

各列を合計する

df %>%
   replace(is.na(.), 0) %>%
   summarise_all(funs(sum))

各行を合計する

df %>%
   replace(is.na(.), 0) %>%
   mutate(sum = rowSums(.[1:5]))

8
summarise_each各列に沿って合計し、必要なのは各行に沿って合計します
amo 2015

1
同じことを達成しようとしていますが、DFに文字である列があるため、すべての列を合計することはできません。(.[1:5])パーツを変更する必要があると思いますが、残念ながら構文に精通しておらず、ヘルプを探す方法もわかりません。試してみましたmutate(sum = rowSums(is.numeric(.)))が、機能しませんでした。
ccamara 2017年

5
そうですか。あなたはdf %>% replace(is.na(.), 0) %>% select_if(is.numeric) %>% summarise_each(funs(sum))ショットを与えたいかもしれませんか?
Boern 2017年

2
非推奨となったため、summarise_all代わりに使用してくださいsummarise_each
hmhensen

2
mutate(sum = rowSums(.[,-1]))処理する必要のある列の数がわからない場合は、構文が役立つことがあります。
Paulo S.Abreu19年

32

特定の列のみを合計したい場合は、次のようなものを使用します。

library(dplyr)
df=data.frame(
  x1=c(1,0,0,NA,0,1,1,NA,0,1),
  x2=c(1,1,NA,1,1,0,NA,NA,0,1),
  x3=c(0,1,0,1,1,0,NA,NA,0,1),
  x4=c(1,0,NA,1,0,0,NA,0,0,1),
  x5=c(1,1,NA,1,1,1,NA,1,0,1))
df %>% select(x3:x5) %>% rowSums(na.rm=TRUE) -> df$x3x5.total
head(df)

このようにして、dplyr::selectの構文を使用できます。


NAを0に強制する必要がないため、このアプローチが他のアプローチよりも気に入っています
Michael Bellhouse 2017年

そして、x4:x11のようなものを扱うのが簡単なのでgrepよりも優れています
DovRosenberg19年

32

正規表現マッチングを使用して、特定のパターン名を持つ変数を合計します。例えば:

df <- df %>% mutate(sum1 = rowSums(.[grep("x[3-5]", names(.))], na.rm = TRUE),
                    sum_all = rowSums(.[grep("x", names(.))], na.rm = TRUE))

このようにして、データフレームの特定の変数グループの合計として複数の変数を作成できます。


素晴らしい解決策!最近のリリースでこれを行う特定のdplyr関数を探していましたが、見つかりません
でした

このソリューションは素晴らしいです。含めたくない列がある場合は、特定のパターンに一致する列を選択するようにgrep()ステートメントを設計する必要があります。
トレントンホフマン

1
@TrentonHoffmanは、特定のパターンの列の選択を解除するビットです。-記号が必要です:rowSums(.[-grep("x[3-5]", names(.))], na.rm = TRUE)
alexb5 2319

22

この問題は頻繁に発生します。これを行う最も簡単な方法はapply()mutateコマンド内で関数を使用することです。

library(tidyverse)
df=data.frame(
  x1=c(1,0,0,NA,0,1,1,NA,0,1),
  x2=c(1,1,NA,1,1,0,NA,NA,0,1),
  x3=c(0,1,0,1,1,0,NA,NA,0,1),
  x4=c(1,0,NA,1,0,0,NA,0,0,1),
  x5=c(1,1,NA,1,1,1,NA,1,0,1))

df %>%
  mutate(sum = select(., x1:x5) %>% apply(1, sum, na.rm=TRUE))

ここでは、標準のdplyrトリック(starts_with()またはcontains())を使用して列を選択するために必要なものを使用できます。1つのmutateコマンド内ですべての作業を実行することにより、このアクションdplyrは処理ステップのストリーム内のどこでも発生する可能性があります。最後に、このapply()関数を使用することにより、独自の専用の要約関数を含め、必要な要約を柔軟に使用できます。

または、整頓されていない関数を使用するというアイデアが魅力的でない場合は、列をまとめて要約し、最後に結果を元のデータフレームに結合することができます。

df <- df %>% mutate( id = 1:n() )   # Need some ID column for this to work

df <- df %>%
  group_by(id) %>%
  gather('Key', 'value', starts_with('x')) %>%
  summarise( Key.Sum = sum(value) ) %>%
  left_join( df, . )

ここでは、starts_with()関数を使用して列を選択し、合計を計算しましたNA。値を使用して、好きなことを行うことができます。このアプローチの欠点は、かなり柔軟性がありdplyrますが、データクリーニング手順のストリームに実際には適合しないことです。


3
applyこれrowSumsが設計されたものである場合、使用するのはばかげているようです。
zacdav 2018

6
この場合rowSumsは非常にうまく機能しますがrowMeans、「計算する必要があるのが合計でも平均でもない場合はどうなるのか」という疑問をいつも少し奇妙に感じました。ただし、99%の場合、このようなことをしなければなりません。これは合計または平均のいずれかであるため、一般的なapply関数を使用する際の余分な柔軟性は保証されません。
デレクソンデレッガー2018

22

reduce()fromの使用purrrは、すべての行の反復を回避し、ベクトル化された操作を利用するだけrowSumsなのでapply、よりわずかに速く、間違いなくより速くなります。

library(purrr)
library(dplyr)
iris %>% mutate(Petal = reduce(select(., starts_with("Petal")), `+`))

タイミングはこちらをご覧ください


Iこのようなしかし、あなたは、あなたが必要なときにそれをどのように行うのでしょうna.rm = TRUE
see24

@ see24あなたが何を言っているのかわかりません。これは、すべて同じ長さのベクトルa + b + cを合計します。各ベクトルは異なる場所にNAを持っている場合と持っていない場合があるため、無視することはできません。これにより、ベクトルが整列しなくなります。あなたはNA値を削除したい場合は、それをしなければならない、その後例えば、で、drop_na
SKD

rowSums(select(., matches("myregex")) , na.rm = TRUE))NAを無視するという点で必要だったので、やることになりました。したがって、数値がsum(NA, 5)5の場合、結果は5です。しかし、reduceの方が優れているとおっしゃっrowSumsていましたが、この状況でそれを使用する方法があるかどうか疑問に思いました。
see24

そうですか。合計が必要で、NA値を確実に無視する場合は、rowSumsバージョンがおそらく最適です。主な欠点は、唯一のことであるrowSumsrowMeans(それがslighly遅いがない分だけ、減らすよりも)可能です。(合計ではなく)別の操作を実行する必要がある場合は、reduceバージョンがおそらく唯一のオプションです。applyこの場合は使用を避けてください。
skd

1

の新しいバージョンでは dplyrは、rowwise()と一緒c_acrossに使用して、特定の行ごとのバリアントを持たない関数の行ごとの集計を実行できますが、行ごとのバリアントが存在する場合は、より高速になるはずです。

以来 rowwise()はグループ化の特殊な形式であり、動詞の動作方法を変更するためungroup()、行単位の操作を行った後、動詞をパイプでつなぐことをお勧めします。

行の範囲を選択するには:

df %>%
  dplyr::rowwise() %>% 
  dplyr::mutate(sumrange = sum(dplyr::c_across(x1:x5), na.rm = T))
# %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()

タイプで行を選択するには:

df %>%
  dplyr::rowwise() %>% 
  dplyr::mutate(sumnumeric = sum(c_across(where(is.numeric)), na.rm = T))
# %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()

特定のケースでは、行ごとのバリアントが存在するため、次のことができます( across代わりに)。

df %>%
  dplyr::mutate(sumrow = rowSums(dplyr::across(x1:x5), na.rm = T))
# %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()

詳細については、上のページを参照してください行方向

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.