【问题标题】:Copy values within column, based on other column value根据其他列值复制列内的值
【发布时间】:2016-05-24 17:21:06
【问题描述】:

我试图用同一列中出现的另一个值填充所有 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

【问题讨论】:

    标签: r dataframe


    【解决方案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]
    }
    

    【讨论】:

    • 谢谢,您对迭代这个方法有什么建议吗?我忘了提,我有大约 400 列。我可以用“for i in ....”开始命令,然后用 i 替换 price1/price2 吗?此外,多个值无关紧要,每个产品每月的价格始终相同:)
    • @larryfisherman 只需将d[is.na(d$price1), "price1"] 替换为m &lt;- names(d)[i]; d[is.na(d[,m]), m],然后使用for (i in 3:ncol(d)) 之类的内容循环即可。
    【解决方案2】:

    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
    

    【讨论】:

      【解决方案3】:

      这个问题在 StackExchange 中可能会更好,因为它专注于 R 中的编程,但这里有一个答案:

      我想有更好的方法可以做到这一点,但会立即浮现在脑海中。

      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
      

      【讨论】:

        【解决方案4】:

        一种方法是使用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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-19
          • 1970-01-01
          • 2022-08-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多