8

グループを元の順序 (データ フレームの最初の出現に基づく順序) に保ちながら、データ フレームを集約するのに問題があります。私はそれを正しくすることができましたが、もっと簡単な方法があることを望んでいました。

作業するサンプル データ セットを次に示します。

set.seed(7)
sel.1 <- sample(1:5, 20, replace = TRUE)     # selection vector 1
sel.2 <- sample(1:5, 20, replace = TRUE)
add.1 <- sample(81:100)                      # additional vector 1
add.2 <- sample(81:100)
orig.df <- data.frame(sel.1, sel.2, add.1, add.2)

注意点: データをグループ化する方法を決定する 2 つの選択列があります。それらは同じであり、それらの名前は知られています。このデータには 2 つの列しか追加していませんが、さらに多くの列がある可能性があります。わかりやすくするために「sel」と「add」で始まる列名を付けましたが、実際のデータには別の名前が付いています (そのため、grepトリックはクールですが、ここでは役に立ちません)。

私がやろうとしているのは、データ フレームを「sel」列に基づいてグループに集約し、すべての「add」列を合計することです。aggregateこれは、次のように使用すると簡単です。

# Get the names of all the additional columns
all.add <- names(orig.df)[!(names(orig.df)) %in% c("sel.1", "sel.2")]
aggr.df <- aggregate(orig.df[,all.add], 
                     by=list(sel.1 = orig.df$sel.1, sel.2 = orig.df$sel.2), sum)

問題は、結果が「sel」列によって順序付けられることです。各グループの元データ初出順に並べてほしい。

これを機能させるための私の最善の試みは次のとおりです。

## Attempt 1
# create indices for each row (x) and find the minimum index for each range
index.df <- aggregate(x = 1:nrow(orig.df),
                      by=list(sel.1 = orig.df$sel.1, sel.2 = orig.df$sel.2), min)
# Make sure the x vector (indices) are in the right range for aggr.df
index.order <- (1:nrow(index.df))[order(index.df$x)]
aggr.df[index.order,]

## Attempt 2
# get the unique groups. These are in the right order.
unique.sel <- unique(orig.df[,c("sel.1", "sel.2")])
# use sapply to effectively loop over data and sum additional columns.
sums <- t(sapply(1:nrow(unique.sel), function (x) {
    sapply(all.add, function (y) {
        sum(aggr.df[which(aggr.df$sel.1 == unique.sel$sel.1[x] & 
                          aggr.df$sel.2 == unique.sel$sel.2[x]), y])
        })
}))
data.frame(unique.sel, sums)

これらは私に正しい結果をもたらしますが、誰かがより簡単な解決策を指摘できることを望んでいました. ソリューションが標準の R インストールに付属するパッケージで機能する場合は、それが望ましいでしょう。

aggregateとのドキュメントを見てきましたがmatch、答えが見つかりませんでした ( の「keep.original.order」パラメーターのようなものを望んでいたと思いますaggregate)。

どんな助けでも大歓迎です!


更新:(誰かがこれに出くわした場合に備えて)

さらに数日間試した後に見つけた最もクリーンな方法は次のとおりです。

unique(data.frame(sapply(names(orig.df), function(x){
    if(x %in% c("sel.1", "sel.2")) orig.df[,x] else
    ave(orig.df[,x], orig.df$sel.1, orig.df$sel.2, FUN=sum)},
simplify=FALSE)))
4

4 に答える 4

5

data.tableでは短くシンプルです。デフォルトでは、最初の出現順にグループを返します。

require(data.table)
DT = as.data.table(orig.df)
DT[, list(sum(add.1),sum(add.2)), by=list(sel.1,sel.2)]

    sel.1 sel.2  V1  V2
 1:     5     4  96  84
 2:     2     2 175 176
 3:     1     5 384 366
 4:     2     5  95  89
 5:     4     1 174 192
 6:     2     4  82  87
 7:     5     3  91  98
 8:     3     2 189 178
 9:     1     4 170 183
10:     1     1 100  91
11:     3     3  81  82
12:     5     5  83  88
13:     2     3  90  96

また、これは大きなデータの場合は高速になるため、速度の問題が見つかった場合に後でコードを変更する必要はありません。次の代替構文は、グループ化する列を渡す最も簡単な方法です。

DT[, lapply(.SD,sum), by=c("sel.1","sel.2")]

    sel.1 sel.2 add.1 add.2
 1:     5     4    96    84
 2:     2     2   175   176
 3:     1     5   384   366
 4:     2     5    95    89
 5:     4     1   174   192
 6:     2     4    82    87
 7:     5     3    91    98
 8:     3     2   189   178
 9:     1     4   170   183
10:     1     1   100    91
11:     3     3    81    82
12:     5     5    83    88
13:     2     3    90    96

または、by列名の単一のコンマ区切り文字列にすることもできます。

DT[, lapply(.SD,sum), by="sel.1,sel.2"]
于 2012-08-15T11:38:29.493 に答える
1

読むのは少し難しいですが、それはあなたが望むものをあなたに与えます、そして私は明確にするためにいくつかのコメントを追加しました。

# Define the columns you want to combine into the grouping variable
sel.col <- grepl("^sel", names(orig.df))
# Create the grouping variable
lev <- apply(orig.df[sel.col], 1, paste, collapse=" ")
# Split and sum up
data.frame(unique(orig.df[sel.col]),
           t(sapply(split(orig.df[!sel.col], factor(lev, levels=unique(lev))),
                    apply, 2, sum)))

出力は次のようになります

   sel.1 sel.2 add.1 add.2
1      5     4    96    84
2      2     2   175   176
3      1     5   384   366
5      2     5    95    89
6      4     1   174   192
7      2     4    82    87
8      5     3    91    98
10     3     2   189   178
11     1     4   170   183
14     1     1   100    91
17     3     3    81    82
19     5     5    83    88
20     2     3    90    96
于 2012-08-08T19:29:09.847 に答える