web-dev-qa-db-ja.com

グループごとに変数を合計する方法

2列のデータがあるとしましょう。 1つ目は、 "First"、 "Second"、 "Third"などのカテゴリを含みます。

例えば:

Category     Frequency
First        10
First        15
First        5
Second       2
Third        14
Third        20
Second       3

データをカテゴリ別に並べ替え、頻度を合計します。

Category     Frequency
First        30
Second       5
Third        34

これをRでどうやってやるのでしょうか。

295
user5243421

aggregateを使う:

aggregate(x$Frequency, by=list(Category=x$Category), FUN=sum)
  Category  x
1    First 30
2   Second  5
3    Third 34

上記の例では、listに複数の次元を指定できます。同じデータ型の複数の集約メトリックをcbind経由で組み込むことができます。

aggregate(cbind(x$Frequency, x$Metric2, x$Metric3) ...

(@thelatemailコメントを埋め込む)、aggregateは式のインターフェースも持っています

aggregate(Frequency ~ Category, x, sum)

あるいは、複数の列を集約したい場合は、.表記を使用することができます(1つの列に対しても機能します)。

aggregate(. ~ Category, x, sum)

またはtapply

tapply(x$Frequency, x$Category, FUN=sum)
 First Second  Third 
    30      5     34 

このデータを使う:

x <- data.frame(Category=factor(c("First", "First", "First", "Second",
                                      "Third", "Third", "Second")), 
                    Frequency=c(10,15,5,2,14,20,3))
330
rcs

最近では、そのためにdplyrパッケージも使用できます。

library(dplyr)
x %>% 
  group_by(Category) %>% 
  summarise(Frequency = sum(Frequency))

#Source: local data frame [3 x 2]
#
#  Category Frequency
#1    First        30
#2   Second         5
#3    Third        34

または、複数の集計列の場合(1列でも機能します)。

x %>% 
  group_by(Category) %>% 
  summarise_each(funs(sum))

dplyr> = 0.5に更新:summarise_eachは、dplyrのsummarise_allsummarise_atおよびsummarise_if関数ファミリーに置き換えられました。

または、でグル​​ープ化する複数の列がある場合は、カンマで区切ってgroup_byにそれらすべてを指定できます。

mtcars %>% 
  group_by(cyl, gear) %>%                            # multiple group columns
  summarise(max_hp = max(hp), mean_mpg = mean(mpg))  # multiple summary columns

%>%演算子を含む詳細については、dplyrの の紹介 を参照してください。

177

Rcsによって提供される答えは機能し、簡単です。ただし、もっと大きなデータセットを処理していてパフォーマンスを向上させる必要がある場合は、もっと早い方法があります。

library(data.table)
data = data.table(Category=c("First","First","First","Second","Third", "Third", "Second"), 
                  Frequency=c(10,15,5,2,14,20,3))
data[, sum(Frequency), by = Category]
#    Category V1
# 1:    First 30
# 2:   Second  5
# 3:    Third 34
system.time(data[, sum(Frequency), by = Category] )
# user    system   elapsed 
# 0.008     0.001     0.009 

それをdata.frameと上記のものを使って同じものと比較しましょう。

data = data.frame(Category=c("First","First","First","Second","Third", "Third", "Second"),
                  Frequency=c(10,15,5,2,14,20,3))
system.time(aggregate(data$Frequency, by=list(Category=data$Category), FUN=sum))
# user    system   elapsed 
# 0.008     0.000     0.015 

そして列を残したい場合はこれが構文です。

data[,list(Frequency=sum(Frequency)),by=Category]
#    Category Frequency
# 1:    First        30
# 2:   Second         5
# 3:    Third        34

以下のコードが示すように、大きなデータセットでは違いがより顕著になります。

data = data.table(Category=rep(c("First", "Second", "Third"), 100000),
                  Frequency=rnorm(100000))
system.time( data[,sum(Frequency),by=Category] )
# user    system   elapsed 
# 0.055     0.004     0.059 
data = data.frame(Category=rep(c("First", "Second", "Third"), 100000), 
                  Frequency=rnorm(100000))
system.time( aggregate(data$Frequency, by=list(Category=data$Category), FUN=sum) )
# user    system   elapsed 
# 0.287     0.010     0.296 

複数の集計では、lapply.SDを次のように組み合わせることができます。

data[, lapply(.SD, sum), by = Category]
#    Category Frequency
# 1:    First        30
# 2:   Second         5
# 3:    Third        34
62
asieira

これは、この質問に多少 関連しています

あなたはまたちょうど使用することができます によって() 関数:

x2 <- by(x$Frequency, x$Category, sum)
do.call(rbind,as.list(x2))

これらの他のパッケージ(plyr、reshape)にはdata.frameを返すという利点がありますが、by()は基本関数なので、よく知っておく価値があります。

35
Shane
library(plyr)
ddply(tbl, .(Category), summarise, sum = sum(Frequency))
24
learnr

数年後、何らかの理由でここには存在しない別の単純なbase Rソリューションを追加するためにxtabs

xtabs(Frequency ~ Category, df)
# Category
# First Second  Third 
#    30      5     34 

あるいはdata.frameを返したい場合

as.data.frame(xtabs(Frequency ~ Category, df))
#   Category Freq
# 1    First   30
# 2   Second    5
# 3    Third   34
21
David Arenburg

3番目のオプションを追加するだけです:

require(doBy)
summaryBy(Frequency~Category, data=yourdataframe, FUN=sum)

編集:これは非常に古い答えです。 @docendo answerのように、summariseからgroup_bydplyrを使用することをお勧めします。

16
dalloliogm

xがあなたのデータを含むデータフレームであるならば、以下はあなたが望むことをするでしょう:

require(reshape)
recast(x, Category ~ ., fun.aggregate=sum)
16
Rob Hyndman

私は最近これらのタイプの操作の大部分でdplyrへの変換になっていますが、sqldfパッケージはまだいくつかの点で本当にいいです(そして私見はもっと読みやすくなります)。

これはsqldfでこの質問にどう答えることができるかの例です。

x <- data.frame(Category=factor(c("First", "First", "First", "Second",
                                  "Third", "Third", "Second")), 
                Frequency=c(10,15,5,2,14,20,3))

sqldf("select 
          Category
          ,sum(Frequency) as Frequency 
       from x 
       group by 
          Category")

##   Category Frequency
## 1    First        30
## 2   Second         5
## 3    Third        34
16
joemienko

私は ave が異なる列に異なる集計関数を適用する必要があるときに(そしてベースRに固執したいときに)非常に役立つ(そして効率的)と思います:

例えば.

この入力を考えると:

DF <-                
data.frame(Categ1=factor(c('A','A','B','B','A','B','A')),
           Categ2=factor(c('X','Y','X','X','X','Y','Y')),
           Samples=c(1,2,4,3,5,6,7),
           Freq=c(10,30,45,55,80,65,50))

> DF
  Categ1 Categ2 Samples Freq
1      A      X       1   10
2      A      Y       2   30
3      B      X       4   45
4      B      X       3   55
5      A      X       5   80
6      B      Y       6   65
7      A      Y       7   50

Categ1Categ2でグループ化し、Samplesの合計とFreqの平均を計算します。
これはaveを使った可能な解決策です:

# create a copy of DF (only the grouping columns)
DF2 <- DF[,c('Categ1','Categ2')]

# add sum of Samples by Categ1,Categ2 to DF2 
# (ave repeats the sum of the group for each row in the same group)
DF2$GroupTotSamples <- ave(DF$Samples,DF2,FUN=sum)

# add mean of Freq by Categ1,Categ2 to DF2 
# (ave repeats the mean of the group for each row in the same group)
DF2$GroupAvgFreq <- ave(DF$Freq,DF2,FUN=mean)

# remove the duplicates (keep only one row for each group)
DF2 <- DF2[!duplicated(DF2),]

結果:

> DF2
  Categ1 Categ2 GroupTotSamples GroupAvgFreq
1      A      X               6           45
2      A      Y               9           40
3      B      X               7           50
6      B      Y               6           65
4
digEmAll

最近追加されたdplyr::tally()は今これをこれまで以上に簡単にします:

tally(x, Category)

Category     n
First        30
Second       5
Third        34
4
dmca

packageRfastの関数group.sumを使うことができます。

Category <- Rfast::as_integer(Category,result.sort=FALSE) # convert character to numeric. R's as.numeric produce NAs.
result <- Rfast::group.sum(Frequency,Category)
names(result) <- Rfast::Sort(unique(Category)
# 30 5 34

Rfastには多くのグループ関数があり、そのうちの1つがgroup.sumです。

3
Csd

castの代わりにrecastを使用する('Frequency''value'になりました)

df  <- data.frame(Category = c("First","First","First","Second","Third","Third","Second")
                  , value = c(10,15,5,2,14,20,3))

install.packages("reshape")

result<-cast(df, Category ~ . ,fun.aggregate=sum)

取得するため:

Category (all)
First     30
Second    5
Third     34
2
Grant Shannon