如何用数据框中的因子用LOCF填充NA,按国家/地区划分

时间:2012-11-29 00:41:08

标签: r dataframe missing-data r-factor

我有以下数据框(简化),国家/地区变量作为因素,而值变量缺少值:

country value
AUT     NA
AUT     5
AUT     NA
AUT     NA
GER     NA
GER     NA
GER     7
GER     NA
GER     NA

以下内容生成以上数据框:

data <- data.frame(country=c("AUT", "AUT", "AUT", "AUT", "GER", "GER", "GER", "GER", "GER"), value=c(NA, 5, NA, NA, NA, NA, 7, NA, NA))

现在,我想使用最后一次观察结果(LOCF)替换每个国家子集中的NA值。我知道 zoo 包中的命令na.locfdata <- na.locf(data)会给我以下数据框:

country value
AUT     NA
AUT     5
AUT     5
AUT     5
GER     5
GER     5
GER     7
GER     7
GER     7

但是, 该功能只应用于按国家/地区划分的各个子集 。以下是我需要的输出:

country value
AUT     NA
AUT     5
AUT     5
AUT     5
GER     NA
GER     NA
GER     7
GER     7
GER     7

我想不出一个简单的方法来实现它。在开始使用for循环之前,我想知道是否有人知道如何解决这个问题。

非常感谢!!

8 个答案:

答案 0 :(得分:15)

ddply解决方案的现代版本是使用包dplyr

library(dplyr)
DF %>%
  group_by(county) %>% 
  mutate(value = na.locf(value, na.rm = F))      

答案 1 :(得分:13)

这是一个ddply解决方案。试试这个

library(plyr)
ddply(DF, .(country), na.locf)
  country value
1     AUT  <NA>
2     AUT     5
3     AUT     5
4     AUT     5
5     GER  <NA>
6     GER  <NA>
7     GER     7
8     GER     7
9     GER     7

修改ddply帮助您可以找到

.variables:  variables to split data frame by, 
as quoted variables, a formula or character vector.

所以获得你想要的另一种选择是:

ddply(DF, "country", na.locf)
ddply(DF, ~country, na.locf)

请注意,不允许将.variables替换为DF$variable,这就是您在执行此操作时出错的原因。

DF是您的data.frame

答案 2 :(得分:7)

虽然不使用locf,但是整齐的方式是:

library(tidyverse)

data %>% 
    group_by(country) %>% 
    fill(value)

Source: local data frame [9 x 2]
Groups: country [2]

country value
(fctr) (dbl)
1     AUT    NA
2     AUT     5
3     AUT     5
4     AUT     5
5     GER    NA
6     GER    NA
7     GER     7
8     GER     7
9     GER     7

答案 3 :(得分:6)

data.frameby分开并在子集上使用na.locf

do.call(rbind,by(data,data$country,na.locf))

如果您想删除行名称:

do.call(rbind,unname(by(data,data$country,na.locf)))

答案 4 :(得分:4)

如果速度是一个考虑因素,那么这个unstack / stack解决方案比我系统上的其他解决方案快4到6倍,尽管它需要稍微长一点的代码:

stack(lapply(unstack(data, value ~ country), na.locf, na.rm = FALSE))

另一种方法是:

transform(data, value = ave(value, country, FUN = na.locf0))

答案 5 :(得分:4)

您只需按国家/地区划分,然后执行zoo::na.locf()或na.fill,填写右侧。 这是一个明确显示na.fill的三元组arg语法的例子:

library(plyr)
library(zoo)

data <- data.frame(country=c("AUT", "AUT", "AUT", "AUT", "GER", "GER", "GER", "GER", "GER"), value=c(NA, 5, NA, NA, NA, NA, 7, NA, NA))

# The following is equivalent to na.locf
na.fill.right <- function(...) { na.fill(..., list(left=NA,interior=NA,right="extend")) }

ddply(data, .(country), na.fill.right)

  country value
1     AUT  <NA>
2     AUT     5
3     AUT     5
4     AUT     5
5     GER  <NA>
6     GER  <NA>
7     GER     7
8     GER     7
9     GER     7

答案 6 :(得分:2)

我这次谈话有点晚了,但这是一种data.table的方式,对于较大的数据集,它将更快:

library(zoo)
library(data.table)

# Convert to data table
setDT(data)

data[, value := na.locf(value, na.rm = FALSE), by = country]

data
   country  value
1:     AUT     NA
2:     AUT      5
3:     AUT      5
4:     AUT      5
5:     GER     NA
6:     GER     NA
7:     GER      7
8:     GER      7
9:     GER      7

# And if you want to convert "data" back to a data frame...
setDF(data)

答案 7 :(得分:0)

dplyr imputeTS 软件包的组合可以完成这项工作。

library(dplyr)
library(imputeTS)
data %>% group_by(country) %>% 
mutate(value = na.locf(value, na.remaining="keep"))   

使用 imputeTS 的na.locf函数的na.remaining参数,您还可以选择如何处理尾随的NA。

这些是选项:

  • “保持”-返回带有NA的系列
  • “ rm”-删除剩余的NAs
  • “均值”-用总体均值替换剩余的资产净值
  • “ rev”-从相反方向执行nocb / locf

通过选择“平均值”,例如,在特定示例中,每个GER的结果为7。