【问题标题】:Conditionally Change value of last column有条件地更改最后一列的值
【发布时间】:2020-06-21 05:34:57
【问题描述】:

我有一个data.frame 并想根据之前所有(第一列除外!)列的值更改最后一列的值。

如果我有:

id v1 v2 v3 wei
1  NA NA NA  1
2  1  1  2   2
3  1  1  NA  1
4  1  1  1   3

我需要得到

id v1 v2 v3 wei
1  NA NA NA  0
2  1  1  2   2
3  1  1  NA  1
4  1  1  1   3

基本上,如果我有所有以“v”开头且缺少值的变量,wei 需要为 0。对于 df 也会发生同样的情况,其中变量中的所有值都等于 0。所以它应该适用于 NA 或 0。

这可能吗?我想保留名为 wei 的同一列,只是“根据条件更新值。

【问题讨论】:

    标签: r na missing-data


    【解决方案1】:

    使用rowSums

    cols <- grep('^v', names(df))
    df$wei[rowSums(is.na(df[cols])) == length(cols) | 
           rowSums(df[cols] == 0, na.rm = TRUE) == length(cols)] <- 0
    df
    
    #  id v1 v2 v3 wei
    #1  1 NA NA NA   0
    #2  2  1  1  2   2
    #3  3  1  1 NA   1
    #4  4  1  1  1   3
    

    这会将wei 的值变为0,其中所有“v”列都是NA 或0。

    如果有一行同时包含 0 和 NA,我们可以这样做:

    df$wei[rowSums(is.na(df[cols])|df[cols] == 0, na.rm = TRUE) == length(cols)] <- 0
    

    【讨论】:

    • 什么是一行既有零又有NA?
    【解决方案2】:

    使用dplyr(见下面的注释):

    columns <- grep("^v", names(df))
    df %>% 
       mutate(wei = ifelse(apply(df[columns],1, function(x) all(is.na(x))),0,wei))
      id v1 v2 v3 wei
    1  1 NA NA NA   0
    2  2  1  1  2   2
    3  3  1  1 NA   1
    4  4  1  1  1   3
    

    注意

    • 由于使用了apply,这可能会非常慢。可以先使用rowwise 和/或transpose 或pivot_*

    数据:

    df <- structure(list(id = 1:4, v1 = c(NA, 1L, 1L, 1L), v2 = c(NA, 1L, 
    1L, 1L), v3 = c(NA, 2L, NA, 1L), wei = c(1L, 2L, 1L, 3L)), class = "data.frame", row.names = c(NA, 
    -4L))
    

    【讨论】:

      【解决方案3】:

      这是一个使用 ifelse

      的 tidyverse 方式
      library(tidyverse)
      
      df <- read.table(text="id v1 v2 v3 wei
      1  NA NA NA  1
      2  1  1  2   2
      3  1  1  NA  1
      4  1  1  1   3", header=T)
      colnames(df)
      #> [1] "id"  "v1"  "v2"  "v3"  "wei"
      df
      #>   id v1 v2 v3 wei
      #> 1  1 NA NA NA   1
      #> 2  2  1  1  2   2
      #> 3  3  1  1 NA   1
      #> 4  4  1  1  1   3
      df %>% 
        mutate(wei = ifelse(is.na(v1) & is.na(v2) & is.na(v3), 0, wei))
      #>   id v1 v2 v3 wei
      #> 1  1 NA NA NA   0
      #> 2  2  1  1  2   2
      #> 3  3  1  1 NA   1
      #> 4  4  1  1  1   3
      

      您可以以类似的方式在基础 R 中实现这一点
      # the same in base-R
      df[is.na(df$v1)& is.na(df$v2)&is.na(df$v3),]$wei <- 0
      df
      #>   id v1 v2 v3 wei
      #> 1  1 NA NA NA   0
      #> 2  2  1  1  2   2
      #> 3  3  1  1 NA   1
      #> 4  4  1  1  1   3
      

      【讨论】:

        【解决方案4】:

        这是我想出的,可能不是最优雅的解决方案,但适用于以“v”开头的任意数量的列:

        library(dplyr)
        df <- tibble::tribble(
          ~id, ~v1, ~v2, ~v3, ~wei,
          1 , NA, NA, NA, 1,
          2 , 1 , 1 , 2 , 2, 
          3 , 1 , 1 , NA, 1,
          4 , 1 , 1 , 1 , 3)
        
        
        df %>% 
          rowwise() %>% 
          mutate(all_na = all(is.na(c_across(starts_with("v")))),
                 all_zero = all(c_across(starts_with("v")) == 0)) %>% 
          mutate(wei = case_when(
            all_na | all_zero ~ 0,
            TRUE ~ wei
          )) %>% 
          ungroup() %>% 
          select(-all_na, -all_zero) # remove intermediate columns if needed, can be removed for debugging
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-10-16
          • 2020-07-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-11
          • 1970-01-01
          相关资源
          最近更新 更多