data.table 内的 ifelse 行为 (R)

Ifelse behavior within data.table (R)

我有一个 data.table 装满了一些消费品。我已将产品区分为 'low''high''unknown' 质量。数据是时间序列,我有兴趣消除数据中的一些季节性。如果产品的原始分类(由我用来确定质量的算法产生的分类)在 X 期为 'low' 质量,但其原始分类在 X-1 期为 'high' 质量,我将该产品重新分类为 'high' 期间 X 的质量。此过程是在某种产品组区分中完成的。

为了完成这个,我有类似下面的东西:

require(data.table)

# lag takes a column and lags it by one period,
# padding with NA

lag <- function(var) {
    lagged <- c(NA, 
                var[1:(length(var)-1)])
    return(lagged)
}

set.seed(120)

foo <- data.table(group = c('A', rep(c('B', 'C', 'D'), 5)),
                  period = c(1:16),
                  quality = c('unknown', sample(c('high', 'low', 'unknown'), 15, replace = TRUE)))

foo[, quality_lag := lag(quality), by = group]

foo[, quality_1 := ifelse(quality == 'low' & quality_lag == 'high',
                          'high',
                          quality)]

正在看foo

    group period quality quality_lag quality_1
 1:     A      1 unknown          NA   unknown
 2:     B      2     low          NA        NA
 3:     C      3    high          NA      high
 4:     D      4     low          NA        NA
 5:     B      5 unknown         low   unknown
 6:     C      6    high        high      high
 7:     D      7     low         low       low
 8:     B      8 unknown     unknown   unknown
 9:     C      9    high        high      high
10:     D     10 unknown         low   unknown
11:     B     11 unknown     unknown   unknown
12:     C     12     low        high      high
13:     D     13 unknown     unknown   unknown
14:     B     14    high     unknown      high
15:     C     15    high         low      high
16:     D     16 unknown     unknown   unknown

所以,quality_1 主要是我想要的。如果期间 X 为 'low' 且期间 X-1 为 'high',我们会看到重新分类为 'high',并且从 quality 开始的所有内容基本保持不变。但是,当 quality_lag 为 NA 时,'low'quality_1 中被重新分类为 NA。这不是 'high''unknown' 的问题。

也就是前四行foo应该是这样的:

   group period quality quality_lag quality_1
 1:     A      1 unknown          NA   unknown
 2:     B      2     low          NA       low
 3:     C      3    high          NA      high
 4:     D      4     low          NA       low

想知道是什么原因造成的吗?

您的问题是 ifelse(NA, 1, 2) == NA,当您执行 NA == 'low' 时,结果是 NA。一个简单的解决方法是在滞后函数中将 NA 表示为字符串。这是您的代码的工作版本:

require(data.table)

# lag takes a column and lags it by one period,
# padding with NA

lag <- function(var) {
    lagged <- c("NA", 
                var[1:(length(var)-1)])
    return(lagged)
}

set.seed(120)

foo <- data.table(group = c('A', rep(c('B', 'C', 'D'), 5)),
                  period = c(1:16),
                  quality = c('unknown', sample(c('high', 'low', 'unknown'), 15, replace = TRUE)))

foo[, quality_lag := lag(quality), by = group]

foo[, quality_1 := ifelse(quality == 'low' & quality_lag == 'high',
                          'high',
                          quality)]

对于初学者来说,Development version on GitHub 已经有一个高效的滞后函数,称为 shift,它既可以用作滞后也可以用作超前(还有一些额外的功能,请参阅 ?shift) .

也看看 here,因为 v >= 1.9.5

中现在还有许多其他新功能

所以在 v >= 1.9.5 下我们可以简单地做

foo[, quality_lag := shift(quality), by = group]

虽然即使在 v < 1.9.5 下,您也可以使用 .N 而不是按以下方式创建此函数

foo[, quality_lag2 := c(NA, quality[-.N]), by = group]

关于你的第二个问题,我建议避免 ifelse 出于指定的许多原因 here

一个可能的替代方案是,只使用一个简单的索引,如

foo[, quality_1 := quality][quality == 'low' & quality_lag == 'high', quality_1 := "high"]

这个解决方案有一点开销,调用 [.data.table 两次,但它仍然比 ifelse 解决方案多 efficient/safe。