我有以下数据框(简化),其中国家变量作为因子,值变量具有缺失值:
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.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 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)
软件包dplyr和imputeTS的组合可以完成这项工作。
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 的结果。