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。
我有一个 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。