【问题标题】:How to safely replace values in data.frame even when data.frame is empty?即使 data.frame 为空,如何安全地替换 data.frame 中的值?
【发布时间】:2015-11-11 04:39:12
【问题描述】:

我在编写安全代码来操作 R 中的数据帧时遇到问题。我遇到的问题是 df[...] <- (...) 容易受到没有行的 data.frame 的影响(除此之外!)。

示例 1:

df <- data.frame(a = 1:2, b = c(NA, 5))
df[is.na(df$b), 'b'] <- 0

做我想做的 - 用 0 替换 NA。

示例 2:

df.empty <- data.frame(a = character(), b = character())
df.empty[is.na(df.empty$b), 'b'] <- 0
df.empty[is.na(df.empty$b), 'b', drop = F] <- 0

在示例 2 中对数据框进行变异的两种尝试都会导致错误(替换有 1 行,数据有 0;或“未使用的参数 (drop = F))。

我觉得这很烦人。

我如何普遍根据 data.frame 中的任意(向量)标准改变列,而无需手动检查所有可能的条件,例如 NA、NULL、无行、强制转换为向量因为没有行等?

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    在您的第二个示例中,我发现向量标准存在逻辑问题。在以下代码中:

    df.empty <- data.frame(a = character(), b = character())
    df.empty[is.na(df.empty$b), 'b'] <- 0
    

    您正在使用条件is.na 选择行范围,但没有行,因此它返回factor(0),这不是有效范围。考虑这个例子:

    df.empty <- data.frame(a = numeric(), b = numeric())
    df.empty[1:2, 'b'] <- 0
    
    > df.empty
       a b
    1 NA 0
    2 NA 0
    

    当您使用有效范围作为标准时,进行分配没有问题。为简单起见,我选择使用 numeric 列。

    【讨论】:

    • is.na(df.empty$b) 是一个逻辑向量 - logical(0) - 所以它是一个有效的数据框选择。
    • logical(0) 是一个特例。
    • 我不明白你所说的特殊情况是什么意思 :) 我可以通过 which(is.na(df.empty$b)) 获得数字索引,但是,我仍然收到将向量分配给空 data.frame 的错误 :(
    • 您想用df.empty[logical(0), 'b'] &lt;- 0 创建多少行,记住logical(0) 是空集?
    • 我不想创建行。我也不想做 df.empty[logical(0), ...]。我正在寻找的是一种一致的、简单的方法来使用 [] 运算符或类似的标准语法将 data.frame 中的值替换为给定条件。 dplyr(另一个答案)可能是一个答案,但我发现很难相信 base R 不支持这一点。
    【解决方案2】:

    也许使用dplyr

    这个例子,结合mutate()ifelse(),似乎达到了你想要的效果。

    df.empty <- df.empty %>% 
        mutate(b = ifelse(is.na(b), 0, b))
    

    【讨论】:

    • 你打电话给dplyr是为了炒作吗?你可以用基本 R 做transform(df.empty, b = ifelse(is.na(b), 0, b))
    • @DavidArenburg 是的,也许是为了炒作!,...,当我想要像 @JakubP 这样的东西时。正在询问,它位于 dplyr 链的中间(例如,在加入表后,将 na 替换为 0,但最终连接可能为空)。所以,当我读到这个问题时,我自动想到了dplyr。你认为这是一个问题吗?,...,我只是喜欢它。也许您不喜欢,也许您更喜欢 base R 或 tsql 中的所有内容?
    • 是的,我喜欢 base R 和 tsql 中的所有内容(正如我的标签所示)
    • 是的,dplyr 解决方案很好,但是,这意味着将 dplyr 添加到我为这个微不足道的需要而编写的几乎所有代码中。 (乍一看,dplyr 在从源代码构建方面似乎有巨大的要求 - ~200 MB!)@DavidArenburg,感谢transform(),似乎可以完成这项工作。
    • 所以你基本上接受了你不会使用的解决方案。有趣
    【解决方案3】:

    如果空集的每个元素都映射到 0,我们仍然有空集。 因此,在示例 2 中,数据框不应受到分配的影响。 我不知道为什么,但为了摆脱错误消息,制作数据表会有所帮助:

    df.empty <- data.frame(a = character(), b = character())
    setDT(df.empty)
    df.empty[is.na(df.empty$b), 'b'] <- 0
    df.empty
    

    没有错误信息:

    > source('~/.active-rstudio-document', echo=TRUE)
    
    > df.empty <- data.frame(a = character(), b = character())
    
    > setDT(df.empty)
    
    > df.empty[is.na(df.empty$b), 'b'] <- 0
    
    > df.empty
    Empty data.table (0 rows) of 2 cols: a,b
    > 
    

    【讨论】:

      【解决方案4】:

      经常使用rep()

      我做这样的事情:

      df.empty[is.na(df.empty$b), 'b'] <- rep(0, sum(is.na(df.empty$b)))
      

      通过这种方式,您可以生成一个长度为 0 的 n 向量,其中 n 是要替换的行数,也可能为 0。

      在这种情况下有点笨拙,但我经常将其用作df[,"col"] &lt;- rep(x, nrow(df))

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-03
        • 2015-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-09-27
        相关资源
        最近更新 更多