我的问题位于一个循环中,我有一个大型数据集(DF),其中一个子集如下所示:
ID Site Species
101 4 x
101 4 y
101 4 z
102 6 x
102 6 z
102 6 a
102 6 b
103 6 a
103 6 z
103 6 c
103 6 x
103 6 y
105 6 x
105 6 y
105 6 a
105 6 z
108 1 x
108 1 a
108 1 c
108 1 z
我想随机选择,使用我的循环的每次迭代(因此,i
)来自每个站点的个人ID
的所有行。但至关重要的是,每个站点只有一个ID。我有一个单独的函数,可以将我的大数据集子集设置为站点数量,因此,如果i=1
,则子集中只有一个上述站点(例如)。
如果是i=3
,那么我希望所有101行,以及102,103或105的所有行以及108的所有行。
我觉得ddply()
和sample()
之类的东西应该这样做,但我无法让它随机发生。
任何建议都将不胜感激。 感谢
詹姆斯
答案 0 :(得分:1)
我认为您可以使用unique
查找所有可能的ID /网站,然后从唯一和子集中进行抽样。
例如,让我们创建一个数据集
# Set the RNG seed for reproducibility
set.seed(12345)
ID <- rep(100:110, c(2, 6, 3, 1, 3, 8, 9, 2, 4, 5, 6))
site <- rep(1:6, c(8, 7, 8, 11, 4, 11))
species <- sample(letters[1:5], length(ID), replace=T)
df <- data.frame(ID=ID, Site=site, Species=species)
所以,df看起来像:
> head(df, 15)
ID Site Species
1 100 1 d
2 100 1 e
3 101 1 d
4 101 1 e
5 101 1 c
6 101 1 a
7 101 1 b
8 101 1 c
9 102 2 d
10 102 2 e
11 102 2 a
12 103 2 a
13 104 2 d
14 104 2 a
15 104 2 b
总结数据,我们有:
Site 1 -> 100, 101
Site 2 -> 102, 103, 104
Site 3 -> 105
Site 4 -> 106, 107
Site 5 -> 108
Site 6 -> 109, 110
现在,假设我要从3个网站中选择
# The number of sites we want to sample
num.sites <- 3
# Find all the sites
all.sites <- unique(df$Site)
# Pick the sites.
# You may also want to check that num.sites <= length(all.sites)
sites <- sample(all.sites, num.sites)
在这种情况下,我们选择了
> sites
[1] 4 5 6
好的,现在我们找到每个网站可用的ID
# Now find the IDs in each of those sites
# simplify=F is VERY important to ensure we get a list even if every
# site has the same number of IDs
IDs <- sapply(chosen.sites, function(s)
{
unique(df$ID[df$Site==s])
}, simplify=FALSE)
这给了我们
> IDs
[[1]]
[1] 106 107
[[2]]
[1] 108
[[3]]
[1] 109 110
现在为每个网站选择一个ID
# NOTE: this assumes the same ID is not found in multiple sites
# but it's easy to deal with the opposite case
# Again, we return a list, because sapply does not seem
# to play well with data frames... (try it!)
res <- sapply(IDs, function(i)
{
chosen.ID <- sample(as.list(i), 1)
df[df$ID==chosen.ID,]
}, simplify=FALSE)
# Finally convert the list to a data frame
res <- do.call(rbind, res)
> res
ID Site Species
24 106 4 d
25 106 4 d
26 106 4 b
27 106 4 d
28 106 4 c
29 106 4 b
30 106 4 c
31 106 4 d
32 106 4 a
35 108 5 b
36 108 5 b
37 108 5 e
38 108 5 e
44 110 6 d
45 110 6 b
46 110 6 b
47 110 6 a
48 110 6 a
49 110 6 a
所以,单个函数中的所有内容
pickSites <- function(df, num.sites)
{
all.sites <- unique(df$Site)
chosen.sites <- sample(all.sites, num.sites)
IDs <- sapply(chosen.sites, function(s)
{
unique(df$ID[df$Site==s])
}, simplify=FALSE)
res <- sapply(IDs, function(i)
{
chosen.ID <- sample(as.list(i), 1)
df[df$ID==chosen.ID,]
}, simplify=FALSE)
res <- do.call(rbind, res)
}
答案 1 :(得分:0)
这个怎么样?我添加了一个函数来模拟我认为你的数据的样子。
#dependencies
require(plyr)
#function to make data (just to work with)
make_data<-function(id){
set.seed(id)
num_sites<-round(runif(1)*3,0)+1
num_sp<-round(runif(1)*7,0)+1
sites<-sample(1:10,num_sites,FALSE)
ldply(sites,function(x)data.frame(sites=x,sp=sample(letters[1:26],num_sp,FALSE)))
}
#make a data frame for example use (as per question)
ids<-100:200
df<-ldply(ids,function(x)data.frame(id=x,make_data(x)))
################################################
# HERE'S THE CODE FOR THE ANSWER #
# use ddply to summarise by site & sampled ids #
filter<-ddply(df,.(sites),summarise,set=sample(id,1))
# then apply this filter to the original list
ddply(filter,.(sites),.fun=function(x){return(df[df$site==x$sites & df$id==x$set,])})