代码之家  ›  专栏  ›  技术社区  ›  DTYK

在dplyr管道中排除特定值而不修改基础数据帧的行和

  •  0
  • DTYK  · 技术社区  · 8 年前

    我有一个宽格式的问卷数据的数据框架,每一列代表一个问卷项目。

    数据如下:

    df <- data.frame(Q1 = c(1, 4, 2, 3, 1, 1, 4, 4, 1, 2), 
                 Q2 = c(NA, 3, 1, 4, NA, NA, 3, 4, 1, 2),
                 Q3 = c(3, 4, 1, 2, 4, NA, NA, 1, 1, 2),
                 Q4 = c(NA, 4, 1, 1, 1, 3, NA, 2, 2, NA))
    

    我想用 rowSums 函数将每行中非“4”的值相加,并排除NAS,然后将结果除以非4列和非NA列的数目(使用DPLYR管道)。我不想替换底层数据框中的4s;我想保持原样。

    由于我不知道如何将结果除以非4列和非na列的数目,所以我只尝试了我问题的第一部分。我使用了以下代码来尝试第一部分,但它没有起作用:

    library(dplyr)
    
    df <- df %>%
      as.data.frame() %>%
      mutate(sum = rowSums(.[. != 4, ], na.rm = TRUE))
    

    所需的输出如下所示: rowSums excluding particular value

    在上面的屏幕截图中,“mean”列是非4列和非na值的总和除以非4列和非na列的数目。

    谢谢!

    3 回复  |  直到 8 年前
        1
  •  2
  •   s_baldur    8 年前
    sp_mean <- function(x) mean(x[!is.na(x) & x != 4])
    df$mean <- 
      df %>%
      apply(1, sp_mean)
    
    df
       Q1 Q2 Q3 Q4 mean
    1   1 NA  3 NA 2.00
    2   4  3  4  4 3.00
    3   2  1  1  1 1.25
    4   3  4  2  1 2.00
    5   1 NA  4  1 1.00
    6   1 NA NA  3 2.00
    7   4  3 NA NA 3.00
    8   4  4  1  2 1.50
    9   1  1  1  2 1.25
    10  2  2  2 NA 2.00
    

    编辑1 -略为强劲:

    df$mean <- 
      df %>%
      select(matches("^Q\\d+")) %>%
      apply(1, sp_mean)
    

    matches("^Q\\d+") 匹配以开头的列名 Q1, Q2,..., Q199, Q200, ...

    编辑2 - 结合我的sp_mean()和Ronak的解决方案(不需要do()?以下内容:

    df %>%
      rowwise() %>%
      mutate(mean = sp_mean(c(Q1, Q2, Q3, Q4)))
    
        2
  •  2
  •   Ronak Shah    8 年前

    如果我们想严格按照 dplyr 我们可以利用 rowwise 具有 do 并为每行计算不为4的值之和,并将其除以 length 价值观。

    library(dplyr)
    df %>%
      rowwise() %>%
      do( (.) %>% as.data.frame %>% 
      mutate(mean = sum(.[. != 4], na.rm = TRUE)/length(.[.!=4 & !is.na(.)])))
    
    
    #    Q1    Q2    Q3    Q4   mean
    # * <dbl> <dbl> <dbl> <dbl> <dbl>
    # 1  1.00 NA     3.00 NA     2.00
    # 2  4.00  3.00  4.00  4.00  3.00
    # 3  2.00  1.00  1.00  1.00  1.25
    # 4  3.00  4.00  2.00  1.00  2.00
    # 5  1.00 NA     4.00  1.00  1.00
    # 6  1.00 NA    NA     3.00  2.00
    # 7  4.00  3.00 NA    NA     3.00
    # 8  4.00  4.00  1.00  2.00  1.50
    # 9  1.00  1.00  1.00  2.00  1.25
    #10  2.00  2.00  2.00 NA     2.00
    

    编辑 -在发布了答案之后,我意识到我们实际上可以使用 mean

    df %>%
      rowwise() %>%
      do( (.) %>% as.data.frame %>% 
      mutate(mean = mean(.[. != 4], na.rm = TRUE)))
    
        3
  •  2
  •   Onyambu    8 年前

    使用base r可以执行以下操作:

    df$mean = rowMeans(`is.na<-`(df,df==4),T)#or rowMeans(replace(df,df==4,NA),T)
    > df
       Q1 Q2 Q3 Q4 mean
    1   1 NA  3 NA 2.00
    2   4  3  4  4 3.00
    3   2  1  1  1 1.25
    4   3  4  2  1 2.00
    5   1 NA  4  1 1.00
    6   1 NA NA  3 2.00
    7   4  3 NA NA 3.00
    8   4  4  1  2 1.50
    9   1  1  1  2 1.25
    10  2  2  2 NA 2.00
    
    推荐文章