R 如何按数据框中的因素(按国家/地区划分)使用LOCF填充NAs
我有以下数据框(简化),其中国家变量作为一个因子,值变量缺少值:R 如何按数据框中的因素(按国家/地区划分)使用LOCF填充NAs,r,dataframe,missing-data,r-factor,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")
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))
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循环之前,我想知道是否有人知道如何解决这个问题
非常感谢 使用
by
拆分data.frame
,并在子集上使用na.locf
:
do.call(rbind,by(data,data$country,na.locf))
如果要删除行名称,请执行以下操作:
do.call(rbind,unname(by(data,data$country,na.locf)))
这里有一个
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(DF, "country", na.locf)
ddply(DF, ~country, na.locf)
请注意,不允许将.variables
替换为DF$variable
,这就是执行此操作时出错的原因
DF
是您的数据。frame如果需要考虑速度,则此取消堆栈
/堆栈
解决方案的速度大约是我系统上其他解决方案的4到6倍,尽管它确实需要稍长的代码行:
stack(lapply(unstack(data, value ~ country), na.locf, na.rm = FALSE))
另一种方法是:
transform(data, value = ave(value, country, FUN = na.locf0))
您只需按国家划分,然后a进行a或na填充,填充到右侧。 下面是一个显式显示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
库(plyr)
图书馆(动物园)
数据现代版本的ddply
解决方案是使用包dplyr
:
library(dplyr)
DF %>%
group_by(county) %>%
mutate(value = na.locf(value, na.rm = F))
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
我这次谈话有点晚了,但这里有一个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和imputet的组合可以完成这项工作
library(dplyr)
library(imputeTS)
data %>% group_by(country) %>%
mutate(value = na.locf(value, na.remaining="keep"))
使用na.locf函数的na.remaining参数inputets,您还可以选择如何处理后续NAs
这些是选项:
- “保留”-返回带有NAs的系列
- “rm”-删除剩余的NAs
- “平均值”-用总体平均值替换剩余的NAs
- “rev”-从相反方向执行nocb/locf
例如,通过选择“平均值”,您将得到特定示例中每个GER的结果为7。如果您将问题编辑为包含合理的测试数据结构,您可能会得到更快的响应。您想要!太棒了,谢谢!正是我需要的。我以前尝试过ddply
,使用ddply(DF,DF$country,na.locf)
,但没有成功。使用()
符号有什么区别?谢谢,这也行。但是,我必须再次将行名称重命名为seq_len(nrow(data))
。因此,我选择了上述答案。但是,您的解决方案在计算上可能会更快,因为ddply
对于大数据集来说似乎非常慢。@Gregor,所以OP也想按国家进行划分,我错过了这一点,na.locf
提到的,它们被隐藏在第三段中。现在效果很好。通常标题和第一段应该说明问题,我不明白你为什么不把它们修好,我只是现在修好了。在过去的1.5年里,你们中的任何人都可以而且应该纠正这一点。您现在可以删除您的否决票。dplyr版本为+1@Gregor,请注意,您需要将na.rm=F
添加到na.locf()
调用中。否则会引发错误。有没有办法一次对多个列执行此操作?@RafaelMartins请参见?mutate\u at
library(dplyr)
library(imputeTS)
data %>% group_by(country) %>%
mutate(value = na.locf(value, na.remaining="keep"))