我有两个数据帧:
set.seed(343)
testDF <- data.frame(Score = sample(50, size=50, replace=TRUE), number = rep(letters[1:25],2), Rev = rep(0,50))
sourceDF <- data.frame(min = c(1,10,20,30,40), max = c(9, 19, 29, 39, 50), rev = 1:5)
对于testDF的每一行,其中testDF $得分在sourceDF $ min和sourceDF的sourceDF $ max之间,请将testDF $ Rev的值替换为相应的sourceDF $ rev。
我使用了两个for循环和一个if条件,但它是......慢(我的数据集接近100万行)。 我尝试使用findInterval但没有成功。
有更好/更有效的方法吗?
答案 0 :(得分:5)
首先,请参阅我对如何改进您的问题并使其重现的评论。其次,这是一种可能的方法,使用data.table::foverlaps
library(data.table)
setkey(setDT(testDF)[, Score2 := Score], Score, Score2) # create bounds and key
setkey(setDT(sourceDF), min, max) # Key by min, max
indx <- foverlaps(sourceDF, testDF, nomatch = 0L, which = TRUE) # run foverlaps
testDF[indx$yid, Rev := sourceDF[indx$xid, rev]] # Update in place by corresponding values
答案 1 :(得分:0)
感谢您的回答。我想我没有测试就过快地发布了这个例子。对我感到羞耻...... @David感谢指示我将进一步了解foverlaps函数(并将探索更多的数据表世界)。
我找到了一种非常有效并且速度很快的解决方法。由于我的范围数量有限(示例中为5),因此我只使用变量Score上的过滤函数(dplyr库)将tesdDF子集化为5个数据帧。
testDF1 <- filter(testDF, Score>=1 & Score <=9) ## First DF
然后,这只是在每个数据帧中分配Rev值的问题。
testDF1$Rev <- sourceDF$rev[1]
对于800k +行的旧循环,这在不到1秒的时间内比1h35mn跑了。