【问题标题】:Replace NA with previous occurrence将 NA 替换为上一次出现
【发布时间】:2016-06-09 17:00:16
【问题描述】:

这是我的 CSV 数据示例。它包含约 10 列。

    Product_id    Product_Weight    Product_Name    Shop_Name ...
[1]    A             10                xxxx            Walmart
[2]    B             12                yyyy            Target
[3]    C             11                zzzz            Target
[4]    A             NA                xxxx            Walmart
[5]    C             NA                zzzz            Target

我想在第 4 行和第 5 行分别用 10 和 11 填写 NA(因为从第 1 行和第 3 行已经知道 A 和 C 的产品重量)。我希望最终的数据框是这样的

    Product_id    Product_Weight    Product_Name    Shop_Name ...
[1]    A             10                xxxx            Walmart
[2]    B             12                yyyy            Target
[3]    C             11                zzzz            Target
[4]    A             10                xxxx            Walmart
[5]    C             11                zzzz            Target 

在 R 中最好的方法是什么?

【问题讨论】:

标签: r na


【解决方案1】:

尽管问题要求“上一次出现”,但这将有一个缺点,即如果任何Product_id 中的第一个Product_WeightNA,那么即使我们知道Product_Weight 来自随后的Product_id,因此我们不使用先前出现的值,而是取所有具有相同Product_id 的非NA 的平均值。由于这些都应该相同,因此它们的平均值是它们的共同值。

如果您确实想要上一次出现,请使用 Prev 函数,其中:

Prev <- function(x) na.locf(x, na.rm = FALSE)

代替 (1) 和 (3) 中的 na.aggregate 并且不要使用 (2)。

以下解决方案具有所有优点:

  • 保留输入的顺序

  • 即使任何 Product_id 中的第一个 Product_Weight 为 NA 也可以工作

  • 不要修改输入

第一个解决方案的额外优势是只有一行代码(加上library 语句),而第二个解决方案的额外优势是不使用任何包。

1) zoo::na.aggregate 我们在 zoo 包中使用 na.aggregate(用非 NA 的平均值替换所有 NA),并将其分别应用于 Product_Weight对于每个Product_id

library(zoo)
transform(DF, Product_Weight = ave(Product_Weight, Product_id, FUN = na.aggregate))

给予:

  Product_id Product_Weight Product_Name Shop_Name
1          A             10         xxxx   Walmart
2          B             12         yyyy    Target
3          C             11         zzzz    Target
4          A             10         xxxx   Walmart
5          C             11         zzzz    Target

2) 无包 交替使用Mean 代替na.aggregate,其中Mean 定义为:

Mean <- function(x) replace(x, is.na(x), mean(x, na.rm = TRUE))

3) dplyr/zoo 添加行号,按Product_id 分组,使用na.aggregateMean 像之前的解决方案一样填写NA,如下所示,重新排列到原始顺序并删除行号:

library(dplyr)
library(zoo)

DF %>% 
   mutate(row = row_number()) %>% 
   group_by(Product_id) %>% 
   mutate(Product_Weight = na.aggregate(Product_Weight)) %>% 
   ungroup() %>% 
   arrange(row) %>% 
   select(-row)

注意:这是用于输入DF

Lines <- "    Product_id    Product_Weight    Product_Name    Shop_Name
    A             10                xxxx            Walmart
    B             12                yyyy            Target
    C             11                zzzz            Target
    A             NA                xxxx            Walmart
    C             NA                zzzz            Target"
DF <- read.table(text = Lines, header = TRUE)

【讨论】:

    【解决方案2】:

    dplyrtidyr 的另一个选项:

    library(dplyr); library(tidyr);
    df %>% group_by(Product_id) %>% fill(Product_Weight)
    
    Source: local data frame [5 x 4]
    Groups: Product_id [3]
    
      Product_id Product_Weight Product_Name Shop_Name
          (fctr)          (int)       (fctr)    (fctr)
    1          A             10         xxxx   Walmart
    2          A             10         xxxx   Walmart
    3          B             12         yyyy    Target
    4          C             11         zzzz    Target
    5          C             11         zzzz    Target
    

    结果是按 Product_id 排序的。

    【讨论】:

    • 不重新排序就不能 dplyr 做到这一点?
    【解决方案3】:

    这是使用基本 R 命令的解决方案:

    #   create lookup table with item and weight combinations
    lookup<-unique(df[complete.cases(df[ ,1:2]),])
    
    #     find the NAs needing replacement: which(is.na(df$weight))
    #     find index in lookup tabe:match(df$a[which(is.na(df$weight))
    #     subset: df$weight[which(is.na(df$weight))
    df$weight[which(is.na(df$weight))]<-lookup$weight[match(df$Product_id[which(is.na(df$weight))], lookup$Product_id)]
    

    很可能不如上述 dplyr/tidyr 解决方案高效。

    【讨论】:

      猜你喜欢
      • 2019-05-20
      • 2016-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-28
      • 2019-04-16
      • 1970-01-01
      • 2020-01-14
      相关资源
      最近更新 更多