【问题标题】:Selecting values from specific columns and skipping NA values in R从特定列中选择值并跳过 R 中的 NA 值
【发布时间】:2021-10-25 00:35:26
【问题描述】:

我正在处理癌症登记数据。在以下数据示例 (ex_data) 中,变量 iddiagnosis_yr 分别代表癌症诊断时的 ID 和年份。 x_2005x_2010 列和 y_2005y_2010 列分别代表每年(2005 年到 2010 年)的 x 和 y 状态)。在我的实际工作数据中,我有很多年(2005-2020)的专栏。我想通过排除 NA 从最早可用年份、最新可用年份和诊断年份(即“wanted”中的 x_earliest, y_latest,x_at_diagnosis,y_at_diagnosis 变量)中提取 x 和 y 值.例如,对于 id 1,我想通过跳过 NA 从最早的一年中提取 x 值,从最近一年中提取 y 值。对于诊断年份的 x 和 y 值,如果诊断年份有 NA,我想跳过 NA 并提取前一年的可用数据。如何实现在 R 中获取想要的变量?

library(tidyverse)

#example data
ex_data <- tribble(
~id,~diagnosis_yr,~x_2005,~x_2006,~x_2007,~x_2008,~x_2009,~x_2010,~y_2005,~y_2006,~y_2007,~y_2008,~y_2009,~y_2010,
1,  2007,   NA, NA, 1,  2,  2,  3,  "a",    "b",    "c",    "d",    "e",    NA, 
2,  2008,   1,  3,  1,  NA, 1,  2,   NA,    "b",    "b",    "e",    "d", "d",
3,  2010,   NA, 2,  2,  2,  3,  NA, "a",    "b",    "c",     NA,     NA,    NA,
4,  2009, 1,    3,  1,  NA, 1,  2,   NA,     NA,     NA,     NA,     NA,    NA,
5,  2005, NA,   1,  1,  2,  2,  3,  "a",    "b",    "c",    "d",    "e",    "e"
)

#wanted variables
wanted <- tribble(
  ~id,~diagnosis_yr,~x_earliest,~y_latest,~x_at_diagnosis,~y_at_diagnosis,
  1,    2007,   1,  "e",    1,  "c",
  2,    2008,   1,  "d",    1,  "e",
  3,    2010,   2,  "c",    3,  "c",
  4,  2009, 1,   NA,  1,  NA,
  5,  2005, 1,  "e", NA,  "a"
)

【问题讨论】:

    标签: r na col


    【解决方案1】:

    我不完全确定,如果这是正确的:

    library(dplyr)
    library(tidyr)
    
    ex_data %>% 
      pivot_longer(-c(id, diagnosis_yr), 
                   names_to = c(".value", "year"),
                   names_pattern = "(.*)_(\\d+)") %>% 
      group_by(id) %>% 
      mutate(x_earliest     = first(na.omit(x)),
             x_at_diagnosis = last(na.omit(x[diagnosis_yr >= year])),
             y_latest       = last(na.omit(y)),
             y_at_diagnosis = last(na.omit(y[diagnosis_yr >= year]))) %>% 
      select(id, diagnosis_yr, x_earliest, y_latest, x_at_diagnosis, y_at_diagnosis) %>% 
      distinct() %>% 
      ungroup()
    

    返回

    # A tibble: 3 x 6
         id diagnosis_yr x_earliest y_latest x_at_diagnosis y_at_diagnosis
      <dbl>        <dbl>      <dbl> <chr>             <dbl> <chr>         
    1     1         2007          1 e                     1 c             
    2     2         2008          1 d                     1 e             
    3     3         2010          2 c                     3 c    
    

    【讨论】:

    • 花了我一些时间来了解实际问题。而且我仍然不确定这种方法在更大的数据集上是否非常稳定......
    • 这正是我的感受。我希望最终版本也适用于更大的数据集。但最终能有这样的任务真的很开心。
    • 就像解谜一样。 :-)
    • @TarJae 如果您不知道,请查看 Advent Of Code。除了 SO,它也是这种乐趣的重要来源。冬天来了。
    • 非常感谢您分享这个。我会探索它!
    【解决方案2】:

    策略:

    1. 拆分x和y数据帧,最后加入,x和y的逻辑是一样的:

    2. 使用coalesce 以正确的顺序您可以获得x_earliesty_latest

    3. 用之前的值填充 NA:这是 Anoushiravan Fill missing values with previous values by row using dplyr 的代码这是使用 library(zoo)

    4. mutate 一个新列,其值取决于年份(来自 akrun 的代码,感谢大师)。

    library(zoo)
    library(tidyverse)
    
    x <- ex_data %>% 
        select(id, diagnosis_yr, starts_with("x_")) %>% 
        mutate(x_earliest= coalesce(x_2005, x_2006, x_2007, x_2008, x_2009, x_2010 )) %>% 
        mutate(pmap_df(., ~ na.locf(c(...)[-1]))) %>% # fill NA with value before
        rowwise() %>% 
        mutate(x_at_diagnosis = get(str_c('x_', diagnosis_yr)))
    
    
    y <- ex_data %>% 
        select(id, diagnosis_yr, starts_with("y_")) %>% 
        mutate(y_latest = coalesce(y_2010, y_2009, y_2008, y_2007, y_2006, y_2005)) %>% 
        mutate(pmap_df(., ~ na.locf(c(...)[-1]))) %>% 
        rowwise() %>% 
        mutate(y_at_diagnosis = get(str_c('y_', diagnosis_yr))) %>% 
        type.convert(as.is=TRUE)
    
    left_join(x, y, by=c("id", "diagnosis_yr")) %>% 
        select(id, diagnosis_yr, x_earliest, y_latest, x_at_diagnosis, y_at_diagnosis)
    

    输出:

     id diagnosis_yr x_earliest y_latest x_at_diagnosis y_at_diagnosis
      <dbl>        <dbl>      <dbl> <chr>             <dbl> <chr>         
    1     1         2007          1 e                     1 c             
    2     2         2008          1 d                     1 e             
    3     3         2010          2 c                     3 c        
    

    【讨论】:

    • 天哪,我无语了。不知道该说什么:D
    • 感谢您的代码和 Martin 的代码,它们非常有帮助和教育意义,我已经为我的问题找到了解决方案(编辑版)
    【解决方案3】:

    在@Martin 和@TarJae 的建议代码和策略的帮助下,我想分享以下代码(Martin 和 TarJae 建议代码的组合)来解决我的问题(编辑版)。

    library (zoo)
    library(dplyr)
    library(tidyverse) 
    
    ex_data %>% 
      pivot_longer(-c(id, diagnosis_yr), 
                   names_to = c(".value", "year"),
                   names_pattern = "(.*)_(\\d+)") %>% 
      group_by(id) %>% 
      mutate(x_earliest     = first(na.locf(x,fromLast=T,na.rm = F)),
             x_at_diagnosis = last(na.locf(x[diagnosis_yr >= year],na.rm = F)), #na.rm=F is to keep as it is if there is no replacement 
             y_latest       = last(na.locf(y,fromLast=F, na.rm =F)), 
             y_at_diagnosis = last(na.locf(y[diagnosis_yr >= year],na.rm=F))) %>% 
      dplyr::select(id, diagnosis_yr, x_earliest, y_latest, x_at_diagnosis, y_at_diagnosis) %>% 
      distinct() %>% 
      ungroup()
    

    输出

    id       diagnosis_yr x_earliest y_latest  x_at_diagnosis  y_at_diagnosis
      <dbl>        <dbl>      <dbl>  <chr>             <dbl> <chr>         
         1         2007          1    e                    1   c             
         2         2008          1    d                    1   e             
         3         2010          2    c                    3   c             
         4         2009          1    NA                   1   NA            
         5         2005          1    e                   NA   a   
    

    【讨论】:

      猜你喜欢
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-13
      • 2017-11-29
      • 1970-01-01
      • 2022-10-14
      • 2017-12-19
      相关资源
      最近更新 更多