web-dev-qa-db-ja.com

特定の列でデータフレームを集計し、別の列を表示します

Rには次の形式のデータフレームがあります。

> head(data)
  Group Score Info
1     1     1    a
2     1     2    b
3     1     3    c
4     2     4    d
5     2     3    e
6     2     1    f

Score関数を使用してmax列に続いて集計したい

> aggregate(data$Score, list(data$Group), max)

  Group.1         x
1       1         3
2       2         4

しかし、各グループのInfo列の最大値に関連付けられたScore列も表示したいと思います。これを行う方法がわかりません。希望する出力は次のとおりです。

  Group.1         x        y
1       1         3        c
2       2         4        d

ヒントはありますか?

54
jul635

まず、splitを使用してデータを分割します。

split(z,z$Group)

よりも、各チャンクについて、最大スコアの行を選択します。

lapply(split(z,z$Group),function(chunk) chunk[which.max(chunk$Score),])

最後にdata.frameに戻りますdo.calling rbind

do.call(rbind,lapply(split(z,z$Group),function(chunk) chunk[which.max(chunk$Score),]))

結果:

  Group Score Info
1     1     3    c
2     2     4    d

1行、魔法の呪文なし、高速、結果に良い名前=)

37
mbq

基本的なRソリューションは、aggregate()の出力をmerge()ステップと結合することです。 aggregate()への数式インターフェイスは、標準インターフェイスよりも少し便利だと思います。これは、出力の名前がより優れていることもあるため、それを使用します。

aggregate()ステップは

_maxs <- aggregate(Score ~ Group, data = dat, FUN = max)
_

merge()ステップは単純に

_merge(maxs, dat)
_

これにより、目的の出力が得られます。

_R> maxs <- aggregate(Score ~ Group, data = dat, FUN = max)
R> merge(maxs, dat)
  Group Score Info
1     1     3    c
2     2     4    d
_

もちろん、これを1行にまとめることもできます(中間ステップは説明のためのものでした)。

_merge(aggregate(Score ~ Group, data = dat, FUN = max), dat)
_

数式インターフェイスを使用した主な理由は、マージステップに対して正しいnamesを含むデータフレームを返すためです。これらは、元のデータセットdatの列の名前です。 aggregate()の出力に正しい名前を付けて、merge()が元のデータフレームと集約されたデータフレームのどの列が一致するかを知る必要があります。

標準インターフェースは、あなたがそれを呼ぶ方法にかかわらず、奇妙な名前を与えます:

_R> aggregate(dat$Score, list(dat$Group), max)
  Group.1 x
1       1 3
2       2 4
R> with(dat, aggregate(Score, list(Group), max))
  Group.1 x
1       1 3
2       2 4
_

これらの出力にmerge()を使用できますが、どの列が一致するかをRに伝える作業をさらに行う必要があります。

51
Gavin Simpson

plyrパッケージを使用したソリューションは次のとおりです。

次のコード行は、基本的にddplyに最初にデータをグループごとにグループ化し、次に各グループ内で、スコアがそのグループの最大スコアに等しいサブセットを返します。

library(plyr)
ddply(data, .(Group), function(x)x[x$Score==max(x$Score), ])

  Group Score Info
1     1     3    c
2     2     4    d

また、@ SachaEpskampが指摘しているように、これはさらに次のように簡略化できます。

ddply(df, .(Group), function(x)x[which.max(x$Score), ])

(これには、which.maxは、複数の最大行があれば返します)。

15
Andrie

これにはplyrパッケージを使用できます。 ddply()関数を使用すると、1つ以上の列でデータフレームを分割し、関数を適用してデータフレームを返すことができます。その後、summarize()関数を使用すると、分割した列新しいデータフレームを作成する変数としてのデータフレーム/;

dat <- read.table(textConnection('Group Score Info
1     1     1    a
2     1     2    b
3     1     3    c
4     2     4    d
5     2     3    e
6     2     1    f'))

library("plyr")

ddply(dat,.(Group),summarize,
    Max = max(Score),
    Info = Info[which.max(Score)])
  Group Max Info
1     1   3    c
2     2   4    d
5
Sacha Epskamp

Gavinの答えに追加するために、マージの前に、式インターフェイスを使用しないときに適切な名前を使用するように集計を取得することができます。

aggregate(data[,"score", drop=F], list(group=data$group), mean) 
5
Dan

遅い回答ですが、data.tableを使用したアプローチ

library(data.table)
DT <- data.table(dat)

DT[, .SD[which.max(Score),], by = Group]

または、同等の最高スコアを複数持つことができる場合

DT[, .SD[which(Score == max(Score)),], by = Group]

それに注意してください(?data.tableから)

.SDは、グループ列を除く各グループのxのデータのサブセットを含むdata.tableです。

5
mnel

これは私がbase方法で問題を考える方法です。

my.df <- data.frame(group = rep(c(1,2), each = 3), 
        score = runif(6), info = letters[1:6])
my.agg <- with(my.df, aggregate(score, list(group), max))
my.df.split <- with(my.df, split(x = my.df, f = group))
my.agg$info <- unlist(lapply(my.df.split, FUN = function(x) {
            x[which(x$score == max(x$score)), "info"]
        }))

> my.agg
  Group.1         x info
1       1 0.9344336    a
2       2 0.7699763    e
4
Roman Luštrik

Gavin Simpsonの答えについてコメントするほどの評判はありませんが、aggregateの標準構文と式構文の間で欠損値のデフォルト処理に違いがあるように見えることを警告したかったのです。 。

#Create some data with missing values 
a<-data.frame(day=rep(1,5),hour=c(1,2,3,3,4),val=c(1,NA,3,NA,5))
  day hour val
1   1    1   1
2   1    2  NA
3   1    3   3
4   1    3  NA
5   1    4   5

#Standard syntax
aggregate(a$val,by=list(day=a$day,hour=a$hour),mean,na.rm=T)
  day hour   x
1   1    1   1
2   1    2 NaN
3   1    3   3
4   1    4   5

#Formula syntax.  Note the index for hour 2 has been silently dropped.
aggregate(val ~ hour + day,data=a,mean,na.rm=T)
  hour day val
1    1   1   1
2    3   1   3
3    4   1   5
3
John