假设我们在R、df.A和df.B中有两个数据帧,定义如下:
bin_name <- c('bin_1','bin_2','bin_3','bin_4','bin_5')
bin_min <- c(0,2,4,6,8)
bin_max <- c(2,4,6,8,10)
df.A <- data.frame(bin_name, bin_min, bin_max, stringsAsFactors = FALSE)
obs_ID <- c('obs_1','obs_2','obs_3','obs_4','obs_5','obs_6','obs_7','obs_8','obs_9','obs_10')
obs_min <- c(6.5,0,8,2,1,7,5,6,8,3)
obs_max <- c(7,3,10,3,9,8,5.5,8,10,4)
df.B <- data.frame(obs_ID, obs_min, obs_max, stringsAsFactors = FALSE)df.A定义了回收箱的范围,而df.B则由带有min和max值的行组成,这些观察值可能或不完全属于df.A中定义的bin。
我们希望生成一个长度为nrow(df.B)的新向量,该向量包含df.A的行索引,该索引对应于每个观察完全落在其中的bin。如果一个观察横跨一个垃圾桶,或者部分地掉在它外面,那么它就不能分配给一个bin,而应该返回NA (或类似的东西)。
在上面的例子中,正确的输出向量是:
bin_rows <- c(4, NA, 5, 2, NA, 4, 3, 4, 5, 2)我想出了一个使用sapply的冗长的解决方案。
bin_assignments <- sapply(1:nrow(df.B), function(i) which(df.A$bin_max >= df.B$obs_max[i] & df.A$bin_min <= df.B$obs_min[i])) #get bin assignments for every observation
bin_assignments[bin_assignments == "integer(0)"] <- NA #replace "integer(0)" entries with NA
bin_assignments <- do.call("c", bin_assignments) #concatenate the output of the sapply call几个月前,我发现了一个解决这个问题的简单的单行解决方案,它没有使用应用函数。然而,我忘记了我是如何做到这一点的,而且我也无法重新发现它!解决方案可能涉及match()或which()。有什么想法吗?
发布于 2016-11-10 13:06:15
1)使用可以很容易地在一条语句中完成:
library(sqldf)
sqldf('select a.rowid
from "df.B" b
left join "df.A" a on obs_min >= bin_min and obs_max <= bin_max')
rowid
1 4
2 NA
3 5
4 2
5 NA
6 4
7 3
8 4
9 5
10 22) merge/by,我们可以使用merge和by在两个语句中进行合并。不使用包装。
这确实有一个缺点,即它实现了SQL解决方案不需要做的大型联接。
注意,问题中定义的df.B有obs_10是第二级而不是第10层。如果是这样的话,obs_10是第10层,那么by的第二个参数可能就是m$obs_ID,所以首先修复输入可以简化它。
m <- merge(df.B, df.A)
stack(by(m, as.numeric(sub(".*_", "", m$obs_ID)),
with, c(which(obs_min >= bin_min & obs_max <= bin_max), NA)[1]))给予:
values ind
1 4 1
2 NA 2
3 5 3
4 2 4
5 NA 5
6 4 6
7 3 7
8 4 8
9 5 9
10 2 103)
sapply(1:nrow(df.B), function(i)
c(which(df.A$bin_max >= df.B$obs_max[i] & df.A$bin_min <= df.B$obs_min[i]), NA)[1]) 给予:
[1] 4 NA 5 2 NA 4 3 4 5 23a) -- @Ronak‘在评论中给出了更好的(3)使用mapply的变体:
mapply(function(x, y) c(which(x >= df.A$bin_min & y <= df.A$bin_max), NA)[1],
df.B$obs_min,
df.B$obs_max)4)外部是另一个不使用包的语句解决方案。
seq_len(nrow(df.A)) %*%
(outer(df.A$bin_max, df.B$obs_max, ">=") & outer(df.A$bin_min, df.B$obs_min, "<="))给予:
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 4 0 5 2 0 4 3 4 5 2https://stackoverflow.com/questions/40527724
复制相似问题