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
ヒントはありますか?
まず、split
を使用してデータを分割します。
split(z,z$Group)
よりも、各チャンクについて、最大スコアの行を選択します。
lapply(split(z,z$Group),function(chunk) chunk[which.max(chunk$Score),])
最後にdata.frameに戻りますdo.call
ing 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行、魔法の呪文なし、高速、結果に良い名前=)
基本的な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に伝える作業をさらに行う必要があります。
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
は、複数の最大行があれば返します)。
これには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
Gavinの答えに追加するために、マージの前に、式インターフェイスを使用しないときに適切な名前を使用するように集計を取得することができます。
aggregate(data[,"score", drop=F], list(group=data$group), mean)
遅い回答ですが、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です。
これは私が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
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