![](/img/trans.png)
[英]Create a random subsample by ID and with a certain factor distribution in R
[英]random subsample with uniform distribution in R
我有一个包含植被指数 (VI) 观测值的大型数据集。 我使用 R 对数据进行随机子采样,同时保持分布(相对频率)均匀(在整个 VI 范围内的观察量相等)。 我一直无法获得相当均匀的分布。
示例:
norm<-rnorm(1000, mean = .5, sd = .25) # I have this
hist(norm) #that is distributed like this
hist(unif<-runif(1000, min=0, max=1)) # but I want to resample the data to look like this
这个怎么样:把VI的范围分成等宽的bins,把数据放到这些bins里。 分布中间的 bin 中的数据将多于末端的数据。 在 bin 中随机选择(等概率),然后从 bin 中选择一项。
该想法的一种变体是随机选择 VI 范围内的一个点(以相等的概率),然后找到落在 (x - dx/2) 到 (x + dx/2) 区间内的数据,其中 dx足够大,至少可以捕获一些数据。 然后从该区间中选择一个数据(概率相等)。 可能还有更多的变化。
像这样的非均匀采样的一个后果是您可能会一遍又一遍地从尾部选择相同的项目。 我看不出有什么办法解决这个问题; 这似乎是不可避免的后果。 但我可能错了。
啊哈! 我想到了第二个解决方案,我认为它可能比我的第一个更好,我将其保留在下面的重复目标分布最近匹配选择部分下。
sample()
函数有一个prob
参数,它允许我们为输入向量的元素指定概率权重。 我们可以使用此参数来增加选择出现在输入分布的较稀疏段(即尾部)中的元素的概率,并降低选择出现在较密集段(即中心)中的元素的概率。 我认为密度函数dnorm()
的简单算术反演就足够了:
测试数据
set.seed(1L);
normSize <- 1e4L; normMean <- 0.5; normSD <- 0.25;
norm <- rnorm(normSize,normMean,normSD);
解决方案
unifSize <- 1e3L; unifMin <- 0; unifMax <- 1;
normForUnif <- norm[norm>=unifMin & norm<=unifMax];
d <- dnorm(normForUnif,normMean,normSD);
unif <- sample(normForUnif,unifSize,prob=1/d);
hist(unif);
生成一组与目标(均匀)分布的随机偏差。 对于每个偏差,从输入(正态)分布中找到最接近它的元素。 考虑要为样本选择的元素。
重复上述操作,直到唯一选择的数量达到或超过所需的样本大小。 如果它超过了所需的大小,请将其截断为所需的大小。
我们可以使用findInterval()
为每个均匀偏差找到最接近的法线偏差。 这需要几次调解才能正确。 我们必须对正态分布向量进行排序,因为findInterval()
需要对vec
进行排序。 而不是使用零,目标分布的真实最小值,作为我们传递给runif()
的最小值,我们必须传递输入集中存在的不低于零的最小值; 否则,低于该值的均匀偏差将匹配低于可接受的均匀分布最小值的输入元素。 此外,为了提高效率,在运行调用findInterval()
的循环之前,最好从正态分布向量中删除不在目标分布可接受范围(即 [0,1])内的所有值,因此他们不会参与匹配算法。 它们不是必需的,因为无论如何它们都无法匹配。
如果目标样本大小比输入分布向量小足够的余量,这应该消除结果样本中输入分布的任何痕迹。
测试数据
set.seed(1L);
normSize <- 1e6L; normMean <- 0.5; normSD <- 0.25;
norm <- rnorm(normSize,normMean,normSD);
解决方案
unifSize <- 200L; unifMin <- 0; unifMax <- 1;
normVec <- sort(norm[norm>=unifMin & norm<=unifMax]);
inds <- integer();
repeat {
inds <- unique(c(inds,findInterval(runif(unifSize*2L,normVec[1L],unifMax),normVec)));
if (length(inds)>=unifSize) break;
};
length(inds) <- unifSize;
unif <- normVec[inds];
hist(unif);
一个警告是findInterval()
在技术上不会找到最近的元素,它会找到小于或等于搜索值的元素。 我认为这不会对结果产生任何重大影响; 至多,它会以一种统一的方式无限偏向选择更小的值。 如果你真的想要,你可以看看存在的各种 find-nearest 选项,例如参见R: find Nearest index 。
您可以在具有不同种子的循环中使用 R 中 stats 包中的runif
函数。 假设您想要制作 100 个子样本并在最后合并它们,那么这应该可以完成工作:
list_of_uniformsamples <- vector("list", length = 100)
for (i in 1:100){
set.seed(123+i)
list_of_uniformsamples[[i]] <- round(runif(1000, min=1, max=Number_of_observations))
}
pool_of_uniform_samples <- unlist(list_of_uniformsamples)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.