根据R中另一个数据帧的值,有条件地为新列分配1或0

时间:2016-07-20 10:49:23

标签: r

我有一个data.frame,有32,000个条目。这是一个样本:

# df1
MINEVENT MAXEVENT      EVENTRANGE NUMEVENT cplt_flag
 2680001  2680051 2680001-2680051       51         0
 2680001  2680051 2680001-2680051       51         0
 2680001  2680051 2680001-2680051       51         0
 2680001  2680051 2680001-2680051       51         0
 2680001  2680051 2680001-2680051       51         0
 2680001  2680051 2680001-2680051       51         0

和另一个包含157个值的列表。这是一个样本:

# df2
source_id
   211535
   211535
   211535
   211536
   211536
   211536

我想阅读source_id并测试该值是否介于MINEVENTMAXEVENT之间。如果TRUE,我想在1中输入值cplt_flag,否则0

我有一个使用if-else语句的代码,但它对32,000条目运行速度超慢。此外,我一直在尝试使用函数和应用函数,但无法使其工作。

我正在寻找一种有效的方法来完成这项工作。

2 个答案:

答案 0 :(得分:2)

您的数据集实际上并不存在copy场景的任何情况。但是这里是使用当前开发版本的data.table,v1中的新的非equi连接功能的解决方案。 9.7。请参阅安装说明here

src

对于TRUE中的每一行,提取匹配来自require(data.table) #v1.9.7+ setDT(df2) setDT(df1)[df2, cplt_flag := 1, on = .(MINEVENT <= source_id, MAXEVENT >= source_id)] 的行索引,其中满足提供给df2参数的条件。在这些行索引上,df1 使用on=进行就地更新

答案 1 :(得分:0)

使用match.criterion函数和其中一个 apply 函数的替代解决方案应该比循环更快。我已经添加了一些额外的数据行来测试(不详尽但有说明性):

df1 <- read.table(text = "
                  MINEVENT MAXEVENT      EVENTRANGE NUMEVENT cplt_flag
                  211535   211634  211535-211634        100         0
                  2680001  2680051 2680001-2680051       51         0
                  2680001  2680051 2680001-2680051       51         0
                  2680001  2680051 2680001-2680051       51         0
                  2680001  2680051 2680001-2680051       51         0
                  2680001  2680051 2680001-2680051       51         0
                  2680001  2680051 2680001-2680051       51         0
                  2680101  2680151 2680101-2680151       51         0", header = TRUE)

df2 <- read.table(text = "
                  source_id
                  211535
                  211535
                  211535
                  211536
                  211536
                  211536
                  2680051", header = TRUE)

match.criterion <- function(source.id, df1) {
  matches <- which(df1$MINEVENT <= source.id & source.id <= df1$MAXEVENT)
  df1$cplt_flag[matches] <<- 1
}

sapply(df2$source_id, match.criterion, df1 = df1)
print(df1)
##  MINEVENT MAXEVENT      EVENTRANGE NUMEVENT cplt_flag
##1   211535   211634   211535-211634      100         1
##2  2680001  2680051 2680001-2680051       51         1
##3  2680001  2680051 2680001-2680051       51         1
##4  2680001  2680051 2680001-2680051       51         1
##5  2680001  2680051 2680001-2680051       51         1
##6  2680001  2680051 2680001-2680051       51         1
##7  2680001  2680051 2680001-2680051       51         1
##8  2680101  2680151 2680101-2680151       51         0

注意:

  1. 这里的关键是理解R's scoping rule。要修改函数范围之外的变量,请使用<<-而不是<-。请参阅this以获取解释,并留意有关使用<<-的警告。

  2. 这假定df1$cplt_flag最初全为零,因为match.criterion仅设置与1匹配的行。也就是说,与df1的每个值的标准不匹配的source_id行将保持不变。

  3. 使用foreach代替其中一个 apply 函数的另一个矢量化解决方案是:

    require(foreach)
    foreach(source.id = df2$source_id) %do% match.criterion(source.id, df1)