data.table仅在某些条件下更改列

时间:2017-05-16 18:54:17

标签: r data.table

我有一个data.table,我希望在某些条件下更改某些列。

tmp = data.table(id = rep(LETTERS[1:4], each = 3), flag = c(NA, NA, 4, NA, 5, 4, NA, NA, NA, 7, 5, 6))

> tmp
    id flag
 1:  A   NA
 2:  A   NA
 3:  A    4
 4:  B   NA
 5:  B    5
 6:  B    5
 7:  C   NA
 8:  C   NA
 9:  C   NA
10:  D    7
11:  D    5
12:  D    6

我想要的是如果id列中的所有值都是NA,那么我希望该值为5,如果只有一些是NA,那么我希望该值为min,如果没有NA我想要原来的价值观。

我写了一些ifelse语句来做到这一点,但我发现的是,如果标志中没有NA,并且我返回该值的标志,它将返回它看到的第一个值。

tmp[ , "flag2" := ifelse(all(is.na(flag)), 5, ifelse(any(is.na(flag)), min(flag, na.rm = TRUE), flag)), by = .(id)]

> tmp
    id flag flag2
 1:  A   NA     4
 2:  A   NA     4
 3:  A    4     4
 4:  B   NA     5
 5:  B    5     5
 6:  B    5     5
 7:  C   NA     5
 8:  C   NA     5
 9:  C   NA     5
10:  D    7     7
11:  D    5     7
12:  D    6     7

为什么这不会返回D 5的原始序列7 5 6?并且,有没有一种简单的方法来纠正这个问题?

1 个答案:

答案 0 :(得分:1)

any(...)返回单个逻辑值而不是逻辑向量,因此结果采用flag的第一个元素,与:

相同
ifelse(FALSE, 3, c(2,3))
# [1] 2

在您的情况下,您不需要向量化ifelseif/else应该有效:

tmp[ , "flag2" := if(all(is.na(flag))) 5 else if(any(is.na(flag))) min(flag, na.rm = TRUE) else flag, by = .(id)]

tmp
#    id flag flag2
# 1:  A   NA     4
# 2:  A   NA     4
# 3:  A    4     4
# 4:  B   NA     4
# 5:  B    5     4
# 6:  B    4     4
# 7:  C   NA     5
# 8:  C   NA     5
# 9:  C   NA     5
#10:  D    7     7
#11:  D    5     5
#12:  D    6     6