【问题标题】:R - Summary of non NAs for each rowR - 每行的非 NA 汇总
【发布时间】:2021-08-28 17:01:27
【问题描述】:

我有一个非常相似的问题:How to identify which columns are not “NA” per row in a dataframe?

我只想将结果放在多列中,并且还需要有实际值。 重要的是,当值不是数字而是字符时,它也可以工作!我还有另一个 df,其中有刺而不是数字!

     AFA  AFI  AII  AMA  AMI  AMU  BFA  BFI  BFU  BII
 1: 0.79   NA   NA 0.58   NA   NA   NA   NA 0.75   NA
 2:   NA   NA   NA   NA   NA 0.78   NA -0.5   NA   NA
 3:   NA   NA   NA   NA   NA   NA 0.79 -0.5   NA   NA
 4:   NA   NA   NA   NA   NA   NA   NA -0.5   NA   NA
 5:   NA   NA   NA   NA 0.63   NA   NA   NA   NA   NA
 6:   NA   NA   NA   NA   NA   NA 0.83   NA   NA   NA
 7: 0.63   NA   NA   NA   NA   NA   NA   NA   NA 0.82
 8:   NA   NA   NA   NA 0.63   NA   NA   NA   NA   NA
 9:   NA   NA 0.54 0.59   NA   NA   NA   NA   NA   NA
10:   NA 0.51   NA   NA   NA   NA   NA   NA   NA   NA

输出:

   V1_Code V1_Val V2_Code V2_Val V3_Code V3_Val
1:     AFA   0.79     AMA   0.58     BFU   0.75
2:     AMU   0.78     BFI   -0.5      NA     NA
3:     BFA   0.79     BFI   -0.5      NA     NA
       and so on....

这是我的 df:

    structure(list(AFA = c(0.79, NA, NA, NA, NA, NA, 0.63, NA, NA, 
    NA), AFI = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, 0.51), AII = c(NA, 
    NA, NA, NA, NA, NA, NA, NA, 0.54, NA), AMA = c(0.58, NA, NA, 
    NA, NA, NA, NA, NA, 0.59, NA), AMI = c(NA, NA, NA, NA, 0.63, 
    NA, NA, 0.63, NA, NA), AMU = c(NA, 0.78, NA, NA, NA, NA, NA, 
    NA, NA, NA), BFA = c(NA, NA, 0.79, NA, NA, 0.83, NA, NA, NA, 
    NA), BFI = c(NA, -0.5, -0.5, -0.5, NA, NA, NA, NA, NA, NA), BFU = c(0.75, 
    NA, NA, NA, NA, NA, NA, NA, NA, NA), BII = c(NA, NA, NA, NA, 
NA, NA, 0.82, NA, NA, NA)), row.names = c(NA, -10L), class = c("data.table", 
"data.frame"), .internal.selfref = <pointer: 0x000001fc6b791ef0>)

【问题讨论】:

    标签: r dataframe multiple-columns summary


    【解决方案1】:
    library(dplyr)
    library(tidyr)
    
    mydf |>
      mutate(id = row_number()) |> 
      pivot_longer(-id, names_to = "Code", values_to = "Val") |> 
      drop_na() |> 
      group_by(id) |> 
      mutate(col_num = row_number()) |> 
      ungroup() |> 
      pivot_wider(id_cols = id, values_from = c(Code, Val), names_from = col_num,
                  names_glue = "V{col_num}_{.value}") |> 
      select(-id) |> 
      relocate(sort(tidyselect::peek_vars()))
        
    # A tibble: 10 x 6
       V1_Code V1_Val V2_Code V2_Val V3_Code V3_Val
       <chr>    <dbl> <chr>    <dbl> <chr>    <dbl>
     1 AFA       0.79 AMA       0.58 BFU       0.75
     2 AMU       0.78 BFI      -0.5  NA       NA   
     3 BFA       0.79 BFI      -0.5  NA       NA   
     4 BFI      -0.5  NA       NA    NA       NA   
     5 AMI       0.63 NA       NA    NA       NA   
     6 BFA       0.83 NA       NA    NA       NA   
     7 AFA       0.63 BII       0.82 NA       NA   
     8 AMI       0.63 NA       NA    NA       NA   
     9 AII       0.54 AMA       0.59 NA       NA   
    10 AFI       0.51 NA       NA    NA       NA   
    

    【讨论】:

    • 这个解决方案虽然更接近作者写的,但不是很好。看来作者的意图是摆脱NA这个值,进一步分析和处理数据。将数据转换为简单的 16x2 数据框将允许进一​​步简单的转换,例如使用group_bysummarise
    • 你们俩都做得很好。菲尔的回答非常好,因为他还解决了第二部分,如 OP 的输出所示。为了获得与 Marek Fiotka 相同的输出,Phils 4 行代码将提供相同的结果。总而言之,你们俩都做得很好,+1。个人菲尔的答案是最好的!
    【解决方案2】:

    这是另一种方法:

    1. 基本概念是将列名连接到一个新列CodeVal 的值相同。
    2. 然后使用strsplitunnest 拆分连接的值,将它们放入自己的行中。
    3. 到目前为止,这可以通过 Phil 和 Marek Fiotka 实现的 pivot_longer 缩短。
    4. 在按id 分组后,用mutate(group_id = row_number()) 分配新的id_group
    5. 然后pivot_wider 粘贴名称。
    library(tidyverse)
    
        df %>% 
            mutate(id = row_number(),
                   across(-id, ~case_when(!is.na(.) ~ cur_column()), .names = 'name_{col}'),
                   across(1:10, as.character)) %>%
            unite(Code, starts_with('name'), na.rm = TRUE, sep = ' ') %>% 
            unite(Val, AFA:BII, na.rm = TRUE, sep = " ") %>% 
            mutate(across(-id, ~strsplit(as.character(.), " "))) %>% 
            unnest(cols = c(Code, Val)) %>% 
            group_by(id) %>% 
            mutate(group_id = row_number()) %>% 
            pivot_wider(id_cols = id, values_from = c(Code, Val), names_from = group_id,
                        names_glue = "V{group_id}_{.value}") %>% 
            ungroup() %>% 
            select(V1_Code, V1_Val, V2_Code, V2_Val, V3_Code, V3_Val, -id)
    

    输出:

       V1_Code V1_Val V2_Code V2_Val V3_Code V3_Val
       <chr>   <chr>  <chr>   <chr>  <chr>   <chr> 
     1 AFA     0.79   AMA     0.58   BFU     0.75  
     2 AMU     0.78   BFI     -0.5   NA      NA    
     3 BFA     0.79   BFI     -0.5   NA      NA    
     4 BFI     -0.5   NA      NA     NA      NA    
     5 AMI     0.63   NA      NA     NA      NA    
     6 BFA     0.83   NA      NA     NA      NA    
     7 AFA     0.63   BII     0.82   NA      NA    
     8 AMI     0.63   NA      NA     NA      NA    
     9 AII     0.54   AMA     0.59   NA      NA    
    10 AFI     0.51   NA      NA     NA      NA   
    

    【讨论】:

      【解决方案3】:

      这样做:

      1. 把它变成小标题
      2. 转换为长格式
      3. 使用is.na 函数进行过滤
      4. 随心所欲地继续

      代码如下

      library(tidyverse)
      df = structure(list(AFA = c(0.79, NA, NA, NA, NA, NA, 0.63, NA, NA, NA), 
                          AFI = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, 0.51), 
                          AII = c(NA,NA, NA, NA, NA, NA, NA, NA, 0.54, NA), 
                          AMA = c(0.58, NA, NA, NA, NA, NA, NA, NA, 0.59, NA), 
                          AMI = c(NA, NA, NA, NA, 0.63, NA, NA, 0.63, NA, NA), 
                          AMU = c(NA, 0.78, NA, NA, NA, NA, NA, NA, NA, NA), 
                          BFA = c(NA, NA, 0.79, NA, NA, 0.83, NA, NA, NA, NA), 
                          BFI = c(NA, -0.5, -0.5, -0.5, NA, NA, NA, NA, NA, NA), 
                          BFU = c(0.75, NA, NA, NA, NA, NA, NA, NA, NA, NA), 
                          BII = c(NA, NA, NA, NA, NA, NA, 0.82, NA, NA, NA)), 
                     row.names = c(NA, -10L), class = c("data.table","data.frame"))
      
      df %>% tibble() %>% 
        pivot_longer(everything(), names_to = "key", values_to = "val") %>% 
        filter(!is.na(val))
      

      输出

      # A tibble: 16 x 2
         key     val
         <chr> <dbl>
       1 AFA    0.79
       2 AMA    0.58
       3 BFU    0.75
       4 AMU    0.78
       5 BFI   -0.5 
       6 BFA    0.79
       7 BFI   -0.5 
       8 BFI   -0.5 
       9 AMI    0.63
      10 BFA    0.83
      11 AFA    0.63
      12 BII    0.82
      13 AMI    0.63
      14 AII    0.54
      15 AMA    0.59
      16 AFI    0.51
      

      【讨论】:

      • 您好,感谢您的努力。但我真的需要保持相同的行数,并将结果添加到它们之前所在的同一行中。在此示例中可能没有意义,但这不是整个数据框。
      猜你喜欢
      • 1970-01-01
      • 2019-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-23
      • 1970-01-01
      • 2016-04-23
      • 1970-01-01
      相关资源
      最近更新 更多