20

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

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 值。我知道zoona.locf中的命令。会给我以下数据框:data <- na.locf(data)

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

但是,该函数只能用于由 country 拆分的各个子集。以下是我需要的输出:

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

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

非常感谢!!

4

8 回答 8

15

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

library(dplyr)
DF %>%
  group_by(county) %>% 
  mutate(value = na.locf(value, na.rm = F))      
于 2014-09-19T22:51:12.823 回答
14

这是一个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)

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

DF是你的data.frame

于 2012-11-29T01:07:15.110 回答
8

tidyverse 方式,尽管不使用 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
于 2017-01-13T02:54:53.637 回答
6

在子集上拆分data.framewithby和 use na.locf

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

如果您想删除行名:

do.call(rbind,unname(by(data,data$country,na.locf)))
于 2012-11-29T01:03:15.223 回答
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))
于 2012-11-29T10:07:08.937 回答
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
于 2014-09-19T22:19:18.557 回答
3

我对这次谈话有点晚了,但这里有一种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)
于 2018-07-27T16:01:42.287 回答
1

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

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

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

这些是选项:

  • "keep" - 返回带有 NA 的系列
  • "rm" - 删除剩余的 NA
  • "mean" - 用整体平均值替换剩余的 NA
  • "rev" - 从相反方向执行 nocb / locf

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

于 2018-10-08T03:37:59.380 回答