我有以下数据框(简化),国家/地区变量作为因素,而值变量缺少值:
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.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循环之前,我想知道是否有人知道如何解决这个问题。
非常感谢!!
答案 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.frame
与by
分开并在子集上使用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。
这些是选项:
通过选择“平均值”,例如,在特定示例中,每个GER的结果为7。