r语言 - 如何按数据框中的因子(按国家/地区划分)用 LOCF 填充 NA



我有以下数据框(简化),其中国家变量作为因子,值变量具有缺失值:

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 值。我知道动物园包中的命令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 循环之前,我想知道是否有人知道如何解决这个问题。

非常感谢!!

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

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

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是您的数据帧

尽管不使用 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

by拆分data.frame,并对子集使用na.locf

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

如果要删除行名:

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

你只需要按国家/地区拆分,然后做一个 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

如果考虑速度,那么这个unstack/stack解决方案比我系统上的其他解决方案快大约 4 到 6 倍,尽管它确实需要稍长的代码行:

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

另一种方法是:

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

我这次谈话有点晚了,但这里有一个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)

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

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

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

这些是选项:

  • "保留" - 返回带有 NA 的系列
  • "rm" - 删除剩余的 NA
  • "平均值" - 用总体平均值替换剩余的 NA
  • "Rev" - 从相反的方向执行 NOCB/LOCF

例如,通过选择"平均值",您将获得特定示例中每个 GER 为 7 的结果。

最新更新