问题类强制转换过的R data.table ifelse,if_else,if ... else

Fie*_*err 3 r data.table

我在基于某些条件将字符变量转换为数字变量时遇到了R data.table的问题:

library(data.table)
DT1 <- data.table(a = "A", b = "B")
DT2 <- data.table(a = "A", b = "B")

DT1[a == "A", b := ifelse(b == "B", 1, 0)]    #option 1: incorrect behavior
DT2[,         b := ifelse(b == "B", 1, 0)]    #option 2: correct behavior
Run Code Online (Sandbox Code Playgroud)

预期正确的输出:

   a             b
1: A (character) 1 (numeric)
Run Code Online (Sandbox Code Playgroud)

但是,使用选项1,我得到以下输出(带有警告):

   a             b
1: A (character) 1 (character)
Run Code Online (Sandbox Code Playgroud)

警告信息:

[.data.table(DT1,a ==“ A”,:=(b,ifelse(b ==“ B”,1,0)))中:

将双RHS强制转换为字符以匹配目标列的类型(第2列名为“ b”)。如果目标列的类型字符正确,则为避免效率强迫,最好将RHS创建为类型字符,以提高效率。为了实现这一点,请考虑R的类型后缀:typeof(0L)vs typeof(0),以及typeof(NA)vs typeof(NA_integer_)vs typeof(NA_real_)。您可以使用as.character()来包装RHS以避免出现此警告,但仍会强制执行。如果目标列的类型不正确,则最好重新访问DT的创建位置,然后在其中修复该列的类型。例如,通过在fread()中使用colClasses =。否则,您现在可以通过在其顶部插入一个新列(所需类型)来更改列类型;例如DT [,b:= as.double(b)]。如果:=的RHS具有nrow(DT)元素,则该分配称为列plonk,是更改列类型的方式。可以使用sapply(DT,typeof)观察列类型。

问:有人可以解释为什么选项1不起作用吗?对您来说这似乎是个bug吗?


Extra's:显然也可以执行以下操作:

DT3 <- data.table(a = "A", b = "B")
DT3[, b := ifelse(a == "A" & b == "B", 1, 0)] #option 3: correct behavior
Run Code Online (Sandbox Code Playgroud)

但是,与选项3相比,我更喜欢选项1,因为我想将变量逻辑和过滤器逻辑分开。

注意:用dplyr :: if_else或base :: if ... else替换ifelse时,也会出现此问题

Gre*_*gor 6

类具有层次结构- characternumeric。如果将character数字向量的赋给(部分),则可以安全地将整个向量转换为character,因为数字可以表示为character

在这种情况下,您可以将a分配给向量的numeric一部分character,并data.table可以选择

  • (a)检查整个向量(列),以查看将其转换为数字是否安全(价格昂贵,对用户而言可能是出乎意料且令人惊讶的)
  • (b)将数值转换为字符。

我的猜测是,当您使用时,即使您的条件碰巧匹配每行DT1[a == "A", ...],内部结构也会假设您仅分配给向量的一部分。因此,请data.table执行上述有效且安全的(b)选项,并将您转换numericcharacter

另一方面,语法会DT2[, b := ifelse(b == "B", 1, 0)]覆盖整个b列-之前的内容都没关系,您现在将其放在numeric此处。

我认为,真正的教训是,如果您想更改列的类,则应该明确地执行此操作,而不是依赖于基于为列的一部分分配新值的自动转换。