【问题标题】:R: how to replace NAs with a median by rows?R:如何用中位数替换 NAs?
【发布时间】:2021-03-17 11:07:16
【问题描述】:

按列用中位数替换 NA 是一项非常简单的任务。但是如何用行中位数替换 NA 值?我试过matrixStats::rowMedians 还是不行。

示例:

 tibble(
   name = LETTERS[1:5],
   name2 = LETTERS[9:13],
   id = 1:5,
   val1 = rnorm(5, 0.05, 0.5),
   val2 = rnorm(5, 0, 1),
   val3 = c(1, 2, NA, 7, 0.55),
   val4 = c(NA, 2.33, 12, -0.444, 0)
  )


# A tibble: 5 x 7
  name  name2    id    val1   val2  val3   val4
  <chr> <chr> <int>   <dbl>  <dbl> <dbl>  <dbl>
1 A     I         1  0.160  -1.62   1    NA    
2 B     J         2  0.194   0.345  2     2.33 
3 C     K         3  0.681   1.18  NA    12    
4 D     L         4  0.0168 -0.385  7    -0.444
5 E     M         5 -0.509  -1.10   0.55  0   

我尝试了这段代码,但它给了我一个错误:

sample <- sample %>%
       mutate_all(~ifelse(is.na(.), matrixStats::rowMedians(., na.rm = T), .))

Problem with `mutate()` input `val3`.
x Argument 'dim.' must be an integer vector of length two.
i Input `val3` is `(structure(function (..., .x = ..1, .y = ..2, . = ..1) ...`.
Run `rlang::last_error()` to see where the error occurred.

我了解matrixStats::rowMedians 希望我将数据转换为矩阵。但是当我将数据转换为矩阵时,我无法执行mutate 函数。当我尝试立即实施rowMedians 时,我收到错误:

sample <- matrixStats::rowMedians(sample, cols = c("val1", "val2", "val3", "val4"))
Error in matrixStats::rowMedians(sample, cols = c("val1", "val2", "val3",  :
  Argument 'x' must be of type logical, integer or numeric, not 'character'.

as.matrix 将我的数据从numeric 转换为character。但是,在我的原始数据集上,我收到另一个错误:

Error in matrixStats::rowMedians(original_df, cols = c(val1, val2, val3,  :
  object 'val1' was not found

【问题讨论】:

    标签: r median


    【解决方案1】:

    如果你想留在tidyverse,一种方法是重塑数据:

    library(dplyr)
    library(tidyr)
    
    df %>%
      pivot_longer(cols = starts_with('val'), 
                   names_to = 'col') %>%
      group_by(id) %>%
      mutate(value = replace(value, is.na(value), median(value, na.rm = TRUE))) %>%
      pivot_wider(names_from = col, values_from = value) %>%
      ungroup
    

    在base R中,我们可以使用apply

    cols <- grep('val', names(df))
    df[cols] <- t(apply(df[cols], 1, function(x) 
                  replace(x, is.na(x), median(x, na.rm = TRUE))))
    

    【讨论】:

    • base R 解决方案非常好。我发现它比我在我的个人功能之一中估算行中位数的方式更好。您是否发现此解决方案足够可靠,可以在函数内部使用,或者在某些用例中会产生意想不到的结果?
    • 这应该是可靠的,只要注意包含您想要包含在cols中的所有变量。
    【解决方案2】:

    使用dplyrpurrr 的一个选项可能是:

    df %>%
     mutate(across(val1:val4, 
                   ~ if_else(is.na(.), pmap_dbl(across(val1:val4), ~ median(c(...), na.rm = TRUE)), .)))
                        
      name  name2    id   val1   val2  val3   val4
      <chr> <chr> <int>  <dbl>  <dbl> <dbl>  <dbl>
    1 A     I         1 -0.660  1.68   1     1    
    2 B     J         2  0.145  1.04   2     2.33 
    3 C     K         3 -1.26   2.54   2.54 12    
    4 D     L         4 -0.788 -0.562  7    -0.444
    5 E     M         5  0.821  1.74   0.55  0  
    

    【讨论】:

    • 您的代码似乎可以正常工作,谢谢。但是在我的原始数据帧上执行它会给我不正确的中值。
    • 似乎中位数是按列计算的,而不是按行计算的。例如,c(7, 7, 7, NA) 给了我8 而不是7
    • 我明白了,你是对的,这不是正确的解决方案。我相应地对其进行了修改。
    • @tmfmmk 是的,现在它可以正常工作了。非常感谢你!
    猜你喜欢
    • 2015-10-31
    • 1970-01-01
    • 2016-09-09
    • 2015-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-16
    • 1970-01-01
    相关资源
    最近更新 更多