【问题标题】:Flag rows based on multiple conditions on specific columns in data.table根据 data.table 中特定列上的多个条件标记行
【发布时间】:2019-11-22 06:02:05
【问题描述】:

我有一个 data.table,其中包含特定年份的变量“Performance”的多列和名为“ExPerf”的列。我想创建一个名为 FLAG 的新列,它将根据这两个条件指示标记为手动审查的行:

  1. 任何“性能”列都有负值
  2. “ExPerf”列与任何列的差异超过 50%。

一个类似于我的模拟 data.table:

library(data.table)
dt <- data.table(Id = c("N23", "N34", "N11", "N65", "N55", "N78", "N88"),
                 Name = c("ABCD", "ACBD", "ACCD", "ADBN", "ADDD", "DBCA", "CBDA"),
                 Type = c("T", "B", "B", "T", "T", "B", "B"),
                 Sold = c(500, 300, 350, 500, 350, 400, 450),
                 Bl = c(2000, 2100, 2000, 1500, 1890, 1900, 2000),
                 P_2016 = c(-200, 420, 800, 900, -10, 75, 400),
                 P_2017 = c(500, 300, -20, 700, 50, 80, 370),
                 P_2018 = c(1000, 400, 600, 800, 40, 500, 300),
                 EP_2019 = c(1500, 380, 500, 850, 30, 400, 350))
dt

Id Name Type Sold Baseline Perf_2016 Perf_2017 Perf_2018 ExpPerf_2019
N23 ABCD T   500  2000     -200      500       1000      1500
N34 ACBD B   300  2100     420       300       400       380
N11 ACCD B   350  2000     800       -20       600       500
N65 ADBN T   500  1500     900       700       800       850
N55 ADDD T   350  1890     -10       50        40        30
N78 DBCA B   400  1900     75        80        500       400
N88 CBDA B   450  2000     400       370       300       350

对于此 data.table,所需的输出将添加 FLAG 列,如下所示:

    Id Name Type Sold Baseline Perf_2016 Perf_2017 Perf_2018 ExpPerf_2019  FLAG
1: N23 ABCD    T  500     2000      -200       500      1000         1500  TRUE
2: N34 ACBD    B  300     2100       420       300       400          380 FALSE
3: N11 ACCD    B  350     2000       800       -20       600          500  TRUE
4: N65 ADBN    T  500     1500       900       700       800          850 FALSE
5: N55 ADDD    T  350     1890       -10        50        40           30  TRUE
6: N78 DBCA    B  400     1900        75        80       500          400  TRUE
7: N88 CBDA    B  450     2000       400       370       300          350 FALSE

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    您可以使用以下代码来检查您的两个条件:

    dt[, FLAG := any(.SD < 0 | .SD < ExpPerf_2019 - .5*ExpPerf_2019 | .SD > ExpPerf_2019 + .5*ExpPerf_2019),
       by = Id,
       .SDcols = grep("^Perf", colnames(dt), value = TRUE)
       ]
    

    结果:

    > dt
        Id Name Type Sold Baseline Perf_2016 Perf_2017 Perf_2018 ExpPerf_2019  FLAG
    1: N23 ABCD    T  500     2000      -200       500      1000         1500  TRUE
    2: N34 ACBD    B  300     2100       420       300       400          380 FALSE
    3: N11 ACCD    B  350     2000       800       -20       600          500  TRUE
    4: N65 ADBN    T  500     1500       900       700       800          850 FALSE
    5: N55 ADDD    T  350     1890       -10        50        40           30  TRUE
    6: N78 DBCA    B  400     1900        75        80       500          400  TRUE
    7: N88 CBDA    B  450     2000       400       370       300          350 FALSE
    

    【讨论】:

      【解决方案2】:
      1. 任何性能列都有负值
      2. 预期性能列与任何性能列的差异超过 50%。

      换句话说,这些列有共同的最小和最大界限:

      • 最小值为最大值(0, ExpPerf*0.5)
      • 最大值为 ExpPerf*1.5

      所以...

      dt[, v := !Reduce(`&`, 
        lapply(.SD, between, pmax(0, ExpPerf_2019*0.5), ExpPerf_2019*1.5)
      ), .SDcols=grep("^Perf_", names(dt), value=TRUE)]
      
          Id Name Type Sold Baseline Perf_2016 Perf_2017 Perf_2018 ExpPerf_2019     v
      1: N23 ABCD    T  500     2000      -200       500      1000         1500  TRUE
      2: N34 ACBD    B  300     2100       420       300       400          380 FALSE
      3: N11 ACCD    B  350     2000       800       -20       600          500  TRUE
      4: N65 ADBN    T  500     1500       900       700       800          850 FALSE
      5: N55 ADDD    T  350     1890       -10        50        40           30  TRUE
      6: N78 DBCA    B  400     1900        75        80       500          400  TRUE
      7: N88 CBDA    B  450     2000       400       370       300          350 FALSE
      

      它是如何工作的:

      • between 检查列是否介于最小值和最大值之间
      • lapply 将检查应用于每一列,返回一个列表
      • Reduce&amp; 检查所有列是否满足条件
      • ! 否定结果,因此我们确定至少一列不符合条件的情况

      between&amp;! 是向量化运算符,因此我们最终得到一个结果向量,每行一个。我可能会在 magrittr 中编写此序列,因此步骤更简单:

      library(magrittr)
      
      dt[, v := .SD %>% 
        lapply(between, pmax(0, ExpPerf_2019*0.5), ExpPerf_2019*1.5) %>%
        Reduce(f=`&`) %>%
        not
      , .SDcols=grep("^Perf_", names(dt), value=TRUE)]
      

      not! 的重新标记,为方便起见由 magrittr 提供。

      .SD 是在DT[i, j, by]j 部分内操作的数据子集的特殊符号。在这种情况下,没有iby,所以只有.SDcols 是子集(选择感兴趣的列)。

      评论

      • 如果 OP 选择以长格式格式化数据,代码会更简单。
      • 我的答案使用与 Gilean 相同的步骤,但是是矢量化的,而不是按行计算。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-24
        • 1970-01-01
        • 1970-01-01
        • 2021-06-01
        相关资源
        最近更新 更多