56

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

ヒントはありますか?

4

8 に答える 8

53

基本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

もちろん、これをワンライナーに貼り付けることもできます(中間のステップは説明のためのものでした):

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に伝えるためにさらに作業を行う必要があります。

于 2011-06-09T08:16:25.217 に答える
38

まず、次を使用してデータを分割します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行、魔法の呪文なし、高速、結果は良い名前です=)

于 2011-06-09T08:30:00.193 に答える
15

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(これには、複数の最大行があればそれを返すという利点もあります)。

于 2011-06-09T07:51:26.190 に答える
5

遅い答えですが、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です。

于 2012-10-31T22:55:47.997 に答える
5

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

aggregate(data[,"score", drop=F], list(group=data$group), mean) 
于 2013-01-28T04:39:58.090 に答える
5

パッケージはこれ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
于 2011-06-09T07:53:05.273 に答える
4

これが私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
于 2011-06-09T08:17:27.840 に答える