我有一些dplyr代码要移到data.table,这是我刚遇到的问题。如果b
大于或等于c
,我希望存储在列a
中的3
中一行与另一行之间的差异。但是,运行此代码后:
df = data.frame(a = c(1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3),
b = c(0, 1, 0, 1, 0, 1, 1, 0, 3, 4, 5))
setDT(df)
df[ , c := ifelse(a >= 3, c(0, diff(b)), b), by = .(a)]
c
中的所有元素均为0。为什么?
df
a b c
1: 1 0 0
2: 1 1 0
3: 1 0 0
4: 1 1 0
5: 2 0 0
6: 2 1 0
7: 2 1 0
8: 3 0 0
9: 3 3 0
10: 3 4 0
11: 3 5 0
我认为是等效的dplyr:
df = data.frame(a = c(1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3),
b = c(0, 1, 0, 1, 0, 1, 1, 0, 3, 4, 5))
df %>%
group_by(a) %>%
mutate(c = ifelse( a >= 3, c(0, diff(b)), b))
答案 0 :(得分:3)
从ifelse(test, yes, no)
的帮助中,它应该返回...
具有相同长度和属性(包括尺寸和“类”)的矢量,这些矢量与来自yes或no值的测试和数据值相同。答案的方式将从逻辑上强制为首先容纳从yes获取的任何值,然后容纳从no获取的任何值。
但是:
> df %>% group_by(a) %>% do(print(.$a))
[1] 1 1 1 1
[1] 2 2 2
[1] 3 3 3 3
> data.table(df)[, print(a), by=a]
[1] 1
[1] 2
[1] 3
如帮助页面中所述,由于第一个参数的长度为1,因此如果您为其他部分传递矢量,则仅使用其第一个元素:
> ifelse(TRUE, 1:10, eleventy + million)
[1] 1
在使用常量值(例如...)时,您应该使用if ... else ...
。
> data.table(df)[, b := if (a >= 3) c(0, diff(b)) else b, by=a]
甚至更好,在这种情况下,您可以分配一个子集:
> data.table(df)[a >= 3, b := c(0, diff(b)), by=a]
关于为什么a
的data.table习惯用法的长度为1,请参见常见问题解答“在每个组中,为什么组变量的长度为1?”
答案 1 :(得分:1)
我正在创建一个数据集,该数据集的b
为a
的第一个元素,其值非零,以更好地说明。您先前的数据集全为零,并且c(0,diff(b))
也是从零开始的,因此很难区分。
这里发生的是ifelse
的输出是长度为1的向量。
library(data.table)
df = data.frame(a = c(1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3),
b = c(10, 1, 0, 1, 0, 1, 1, 0, 3, 4, 5))
看下面:
setDT(df)[ , c := ifelse(a >= 3, c(0, diff(b)), b), by = .(a)][]
#> a b c
#> 1: 1 10 10
#> 2: 1 1 10
#> 3: 1 0 10
#> 4: 1 1 10
#> 5: 2 0 0
#> 6: 2 1 0
#> 7: 2 1 0
#> 8: 3 0 0
#> 9: 3 3 0
#> 10: 3 4 0
#> 11: 3 5 0
现在,让我们看看其他示例;这里我使用的是长度为4的简单向量(而不是c(0,diff(b))
):
setDT(df)[ , c := ifelse(a >= 3L, c(20,2,3,4), -999), by=a][]
#> a b c
#> 1: 1 10 -999
#> 2: 1 1 -999
#> 3: 1 0 -999
#> 4: 1 1 -999
#> 5: 2 0 -999
#> 6: 2 1 -999
#> 7: 2 1 -999
#> 8: 3 0 20
#> 9: 3 3 20
#> 10: 3 4 20
#> 11: 3 5 20
您会看到第一个元素仍被分配给c
组的a
的所有行。
一种变通办法是在diff
上使用a
来查看何时未更改( ie diff(a)==0
),并将其用作伪分组。在其他情况下;如下所示:
setDT(df)[, c := ifelse(a >= 3 & c(F,diff(a)==0), c(0,diff(b)), b)][]
#> a b c
#> 1: 1 10 10
#> 2: 1 1 1
#> 3: 1 0 0
#> 4: 1 1 1
#> 5: 2 0 0
#> 6: 2 1 1
#> 7: 2 1 1
#> 8: 3 0 0
#> 9: 3 3 3
#> 10: 3 4 1
#> 11: 3 5 1