【问题标题】:Assigning 1 or 0 conditionally to a new column based on values from another dataframe in R根据 R 中另一个数据框的值有条件地将 1 或 0 分配给新列
【发布时间】:2016-11-23 13:37:42
【问题描述】:

我有一个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,那么我想在cplt_flag 中输入一个值1,否则是0

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

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

【问题讨论】:

  • @Arun r-gold 徽章的魔力 ;-)

标签: r


【解决方案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's scoping rule。要修改函数范围之外的变量,请使用&lt;&lt;- 而不是&lt;-。请参阅this 以获得解释,并注意有关使用&lt;&lt;- 的警告。

  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)

【讨论】:

    【解决方案2】:

    您的数据集实际上没有任何情况会出现TRUE 场景。但这里有一个解决方案,它使用了当前开发版本 data.table v1.9.7 中的新非等连接功能。请参阅安装说明here

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-23
      • 2023-02-15
      相关资源
      最近更新 更多