【问题标题】:sampling randomly with conditions随机抽样
【发布时间】:2014-01-15 04:27:44
【问题描述】:

我的问题在一个循环中,我有一个大型数据集 (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() 这样的事情应该这样做,但我不能让它随机发生。

任何建议将不胜感激。 谢谢

詹姆斯

【问题讨论】:

  • 您能解释一下为什么i=3 意味着应该选择那些IDs 以及为什么108102, 103, 105 不同?你能否展示一些代码来说明你在做什么,一些一般的设置。不清楚i 是什么。
  • 好的,抱歉,这里有更多上下文。我正在使用 specaccum() 跨不同数量的远程摄像机(ID 列)和不同数量的站点(站点列)引导物种累积曲线的生成。因此,对于一个站点,我需要一个摄像机,两个摄像机等的曲线,然后对于两个站点,一个摄像机,两个摄像机等的曲线。我的第一个循环:for (l in 1:length(sitelist)),subsets into l 可能的站点并生成这些站点上所有可能的摄像机的列表。我的下一个嵌套循环:for (i in 1:l) 是我想要对一台相机、两台相机(来自不同站点)等进行采样的地方。
  • 108 与 102、103 和 105 不同,因为它位于不同的站点(站点列)。我想从每个站点中随机选择一个 ID。我提供的数据集显示了 i=3(3 个站点)的迭代,i(更多站点)的其他迭代中有更多的 ID,但我仍然只想要每个站点的一个 ID,不管 i 有多大(即如何有很多网站)。我希望这更有意义。
  • 谢谢,我现在按照你想要的。

标签: r vegan


【解决方案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)
    }

【讨论】:

    【解决方案2】:

    这个怎么样?我添加了一个函数来模拟我认为您的数据的样子。

    #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,])})
    

    【讨论】:

    • 谢谢,两个答案都很好,但我选择了这个,因为它只有 2 行代码。
    猜你喜欢
    • 2016-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-31
    • 2013-08-17
    • 1970-01-01
    相关资源
    最近更新 更多