数据表中的Ifelse行为(R)

5
我有一张包含一些消费产品的data.table。我将这些产品分为了“低质量”,“高质量”或“未知”的类别。这些数据是时间序列,我想要平滑一些数据中的季节性。如果一个产品在X期的原始分类(由我用来确定质量的算法产生的分类)是“低质量”,但它在X-1期的原始分类是“高质量”,那么我将把该产品重新分类为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'且上一期为'high',则我们看到重新分类为'high',并且quality基本保持不变。但是,当quality_lag为NA时,在quality_1'low'会被重新分类为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

你有什么想法是导致这个问题的原因吗?


7
首先,你不需要重新发明轮子。data.table 版本大于等于1.9.5已经有了名为shiftlag 函数,所以你可以简单地执行 foo[, quality_lag := shift(quality), by = group] 来实现。 - David Arenburg
6
其次,ifelse 函数真的很糟糕,我总是尽量避免使用它。我的建议是像这样做:foo[, quality_1 := quality][quality == 'low' & quality_lag == 'high', quality_1 := "high"],来完成同样的功能。 - David Arenburg
1
@DavidArenburg的观点非常准确。此外,有关ifelse的更多信息,请参见https://dev59.com/fGQo5IYBdhLWcg3wKcrH - Ricardo Saporta
感谢@DavidArenburg提供的关于data.table v >= 1.9.5中shift函数的提示。我会尝试您的建议,因为尽可能减少ifelse语句的使用确实很有吸引力。 - thagzone
1
啊,@DavidArenburg,你的解决方案真的很简单。不确定为什么我没有想到像那样进行子集操作。如果你想把你的评论写成答案,我会很乐意接受它。 - thagzone
2个回答

6
首先,GitHub上的开发版本已经有了一个高效的滞后函数,称为shift,既可以用作滞后也可以用作超前(还具有一些额外的功能,请参见?shift)。
此外,在这里还有许多其他新函数,现在在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,原因在这里中有详细说明。
一个可能的替代方案是,只需使用简单的索引,如下所示:
foo[, quality_1 := quality][quality == 'low' & quality_lag == 'high', quality_1 := "high"]

这个解决方案有一点开销,需要调用 [.data.table 两次,但它仍然比 ifelse 解决方案更高效/安全。

-3
你的问题在于 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)]

4
你不应该将NA表示为一个字符,因为is.na("NA") # [1] FALSE - Rich Scriven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接