[英]How do I take subsets of a data frame according to a grouping in R?
我有一個匯總問題,無法弄清楚如何在R中有效執行。
說我有以下數據:
group1 <- c("a","b","a","a","b","c","c","c","c",
"c","a","a","a","b","b","b","b")
group2 <- c(1,2,3,4,1,3,5,6,5,4,1,2,3,4,3,2,1)
value <- c("apple","pear","orange","apple",
"banana","durian","lemon","lime",
"raspberry","durian","peach","nectarine",
"banana","lemon","guava","blackberry","grape")
df <- data.frame(group1,group2,value)
我對從數據幀df
采樣感興趣,這樣我就從因素group1
和group2
每種組合中僅隨機選擇了一行。
如您所見, table(df$group1,df$group2)
1 2 3 4 5 6
a 2 1 2 1 0 0
b 2 2 1 1 0 0
c 0 0 1 1 2 1
顯示了一些組合被多次查看,而其他組合則從未被看到。 對於那些被多次查看的對象(例如, group1="a"
和group2=3
),我只想隨機選擇一個對應的行,並返回僅包含該行子集的新數據框。 這樣,分組因子的每種可能組合僅由數據幀中的單個行表示。
這里的一個重要方面是我的實際數據集可以包含從500,000行到> 2,000,000行的任意位置,因此,請務必注意性能。
我是R的新手,因此一直很難弄清楚如何正確生成此結構。 一種嘗試如下所示(使用plyr
軟件包):
choice <- function(x,label) {
cbind(x[sample(1:nrow(x),1),],data.frame(state=label))
}
df <- ddply(df[,c("group1","group2","value")],
.(group1,group2),
pick_junc,
label="test")
請注意,在這種情況下,我還將在數據幀中添加一個稱為“標簽”的額外列,該列被指定為ddply
函數的額外參數。 但是,大約20分鍾后,我殺死了它。
在其他情況下,我曾嘗試使用aggregate
或by
或tapply
,但是我不知道確切地指定的函數正在獲取什么,應該返回什么或如何處理結果(尤其是by
)。
我正在嘗試從python切換到R以進行探索性數據分析,但是這種聚合類型對我來說至關重要。 在python中,我可以非常快速地執行這些操作,但是這很不方便,因為我必須為要執行的每種不同類型的聚合生成單獨的腳本/數據結構。
我想愛R,所以請幫忙! 謝謝!
烏里
這是plyr
解決方案
set.seed(1234)
ddply(df, .(group1, group2), summarize,
value = value[sample(length(value), 1)])
這給了我們
group1 group2 value
1 a 1 apple
2 a 2 nectarine
3 a 3 banana
4 a 4 apple
5 b 1 grape
6 b 2 blackberry
7 b 3 guava
8 b 4 lemon
9 c 3 durian
10 c 4 durian
11 c 5 raspberry
12 c 6 lime
編輯。 有了這么大的數據幀,最好使用data.table
library(data.table)
dt = data.table(df)
dt[,list(value = value[sample(length(value), 1)]),'group1, group2']
編輯2:性能比較:數據表快15倍
group1 = sample(letters, 1000000, replace = T)
group2 = sample(LETTERS, 1000000, replace = T)
value = runif(1000000, 0, 1)
df = data.frame(group1, group2, value)
dt = data.table(df)
f1_dtab = function() {
dt[,list(value = value[sample(length(value), 1)]),'group1, group2']
}
f2_plyr = function() {ddply(df, .(group1, group2), summarize, value =
value[sample(length(value), 1)])
}
f3_by = function() {do.call(rbind,by(df,list(grp1 = df$group1,grp2 = df$group2),
FUN = function(x){x[sample(nrow(x),1),]}))
}
library(rbenchmark)
benchmark(f1_dtab(), f2_plyr(), f3_by(), replications = 10)
test replications elapsed relative
f1_dtab() 10 4.764 1.00000
f2_plyr() 10 68.261 14.32851
f3_by() 10 67.369 14.14127
另一種方式:
with(df, tapply(value, list( group1, group2), length))
1 2 3 4 5 6
a 2 1 2 1 NA NA
b 2 2 1 1 NA NA
c NA NA 1 1 2 1
# Now use tapply to sample withing groups
# `resample` fn is from the sample help page:
# Avoids an error with sample when only one value in a group.
resample <- function(x, ...) x[sample.int(length(x), ...)]
#Create a row index
df$idx <- 1:NROW(df)
rowidxs <- with(df, unique( c( # the `c` function will make a matrix into a vector
tapply(idx, list( group1, group2),
function (x) resample(x, 1) ))))
rowidxs
# [1] 1 5 NA 12 16 NA 3 15 6 4 14 10 NA NA 7 NA NA 8
df[rowidxs[!is.na(rowidxs)] , ]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.