将NA替换为上一次出现

时间:2016-06-09 17:00:16

标签: r na

这是我的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

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

    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中执行此操作的最佳方法是什么?

3 个答案:

答案 0 :(得分:9)

虽然问题是“先前发生”,但这样做会有一个缺点,即如果Product_Weight中的第一个Product_idNA,那么即使我们无法填写我知道后续Product_Weight中的Product_id,所以我们采用相同Product_id的所有非NA的平均值而不是前一次出现。因为这些都应该是相同的,它们的平均值是它们的共同价值。

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

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

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

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

  • 保留输入的顺序

  • 即使任何Product_Weight中的第一个Product_id为NA

  • 也能正常工作
  • 不要修改输入

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

1)zoo :: na.aggregate 我们在动物园包中使用na.aggregate(用非NA的平均值替换所有NAs)并将其应用于{{ 1}}分别为每个Product_Weight

Product_id

,并提供:

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

2)没有软件包或者使用 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 代替Mean,其中na.aggregate定义为:

Mean

3)dplyr / zoo Mean <- function(x) replace(x, is.na(x), mean(x, na.rm = TRUE)) 添加行号,分组,使用Product_id填写新的解决方案,如下所示,或{{ 1}},安排回原始订单并删除行号:

na.aggregate

注意:这用于输入Mean

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)

答案 1 :(得分:6)

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排序。

答案 2 :(得分:2)

以下是基本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解决方案有效。