繁体   English   中英

根据R中另一个数据框的值有条件地将1或0分配给新列

[英]Assigning 1 or 0 conditionally to a new column based on values from another dataframe in R

我有一个32,000个条目的data.frame 这是一个示例:

# 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则我想在cplt_flag输入值1 ,否则为0

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

我正在寻找一种有效的方法来完成此任务。

您的数据集实际上并没有任何可能会出现TRUE情况的情况。但是,这是一个使用data.table v1.9.7当前开发版本中新的非等额联接功能的解决方案。 请参阅此处的安装说明。

require(data.table) #v1.9.7+

setDT(df2)
setDT(df1)[df2, cplt_flag := 1, on = .(MINEVENT <= source_id, MAXEVENT >= source_id)]

对于df2每一行,在满足提供给on=参数的条件的情况下,从df1中提取匹配的行索引。 在这些行索引上, cplt_flag 更新1

使用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的作用域规则 要在函数范围之外修改变量,请使用<<-代替<- 请参阅以获取解释,并注意有关使用<<-的警告。

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

使用foreach而不是apply函数之一的另一个矢量化解决方案是:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM