2016-05-23 69 views
0

我试图用同一个行中同一列中出现的另一个值填充所有NA,是否有一种简单的方法可以做到这一点?我发现了几乎所有的功能,但并不完全如此。根据其他列值在列中复制值

data.frame看起来像这样

id month price1 price2 
1 1   NA  2 
2 1   4  NA 
3 1   NA  NA 
1 2   6  NA 
2 2   NA  NA 
3 2   NA  4 

输出应该是这样的:

id month price1 price2 
1 1   4  2 
2 1   4  2 
3 1   4  2 
1 2   6  4 
2 2   6  4 
3 2   6  4 

回答

0

,因为它专注于编程R此问题可能在StackExchange会更好,但这里是一个回答:

我想有更好的方法来做到这一点,但立即想到的一个。

replace_nas <- function(df,var,id_var,func = function(x) x[!is.na(x)]) 
    return(merge(df[,-which(names(df)==var)],aggregate(as.formula(paste0(var,"~",id_var)),df,func))[,var]) 
replace_all_nas <- function(df,id_vars,select_var,agg_vars,func = function(x) x[!is.na(x)]) 
    return(cbind(df[,id_vars],sapply(agg_vars,function(x) replace_nas(df,x,select_var,func)))) 

用法:调用replace_all_nas用df为data.frame要执行上,id_vars是你想要固定的列名的向量这个动作,select_var是要组织由变量, agg_vars是您想要替换NA的变量,func是您希望用来收集非na值来替换NA的函数。我将其设置为选择不是NA值(假设只有一个值),但如果列中存在多个非NA值,则需要其他方法来处理此问题。

运行在你的例子:

replace_all_nas(blah,id_vars = c("id","month"),select_var = c("month"),agg_vars = c("price1","price2"),func = function(x) x[!is.na(x)]) 
# id month price1 price2 
# 1 1  1  4  2 
# 2 2  1  4  2 
# 3 3  1  4  2 
# 4 1  2  6  4 
# 5 2  2  6  4 
# 6 3  2  6  4 
+0

谢谢,我要试试这个! –

1

一种可能的方法是使用match功能。

d <- data.frame(id = rep(1:3, 2), 
       month = rep(1:2, each=3), 
       price1 = c(NA, 4, NA, 6, NA, NA), 
       price2 = c(2, NA, NA, NA, NA, 4)) 

d[is.na(d$price1), "price1"] <- 
    d[!is.na(d$price1), ][match(d[is.na(d$price1), "month"], 
           d[!is.na(d$price1), "month"]), "price1"] 

d[is.na(d$price2), "price2"] <- 
    d[!is.na(d$price2), ][match(d[is.na(d$price2), "month"], 
           d[!is.na(d$price2), "month"]), "price2"] 

> d 
    id month price1 price2 
1 1  1  4  2 
2 2  1  4  2 
3 3  1  4  2 
4 1  2  6  4 
5 2  2  6  4 
6 3  2  6  4 

注意,如果有一个以上的非缺失值可供选择,此方法将使用第一个非缺失值。

至于建议的Laterow,您可以遍历变量:

for (j in 3:ncol(d)) { 
    varname <- names(d)[j] 
    d[is.na(d[, varname]), varname] <- 
    d[!is.na(d[, varname]), ][match(d[is.na(d[, varname]), "month"], 
            d[!is.na(d[, varname]), "month"]), 
           varname] 
} 
+0

谢谢,你有没有建议迭代这个方法?我忘了提及,我有大约400列。我可以用“for i in ....”开始命令,然后用我替换price1/price2吗?此外,多个值无关紧要,它每个产品每月的价格始终相同:) –

+0

@larryfisherman只需用'm < - 名称替换'd [is.na(d $ price1),“price1”]' d)[I]; d [is.na(d [,m]),m]',并循环类似'for(i in 3:ncol(d))'。 – Laterow

0

一个dplyr解决方案。它假设每个“月”与NA之间都有一个单一的值。

为每个月创建一个数据框,并为每个月创建具有单个值的新变量。

d1 <- d %>% group_by(month) 
%>% summarise(price1a = mean(price1,na.rm=TRUE),price2a=mean(price2,na.rm=TRUE)) 

将新列追加到原始数据框。

dplyr::left_join(d,d1,by="month") 
id month price1 price2 price1a price2a 
1 1  1  NA  2  4  2 
2 2  1  4  NA  4  2 
3 3  1  NA  NA  4  2 
4 1  2  6  NA  6  4 
5 2  2  NA  NA  6  4 
6 3  2  NA  4  6  4 
0

一种方法是使用ave。功能可应用于ave的相同因子水平的组。

ave(df$price1, df$month, FUN=function(x)unique(x[!is.na(x)])) 

#[1] 4 4 4 6 6 6 

ave(df$price2, df$month, FUN=function(x)unique(x[!is.na(x)])) 
#[1] 2 2 2 4 4 4