【问题标题】:How to find last column with value (for each row), with some rows with all NA as values?如何找到具有值的最后一列(对于每一行),其中一些行的值全部为 NA?
【发布时间】:2022-01-01 15:52:08
【问题描述】:

我遇到了与How to find last column with value (for each row) in R? 相同的问题,除了我的行没有值(NA 的整行)。所述帖子中提供的示例没有整行 NA。

我想知道我应该如何修改以下内容?我不想删除所有 NA 的那些行,因为它们在以后的分析中很有用。

df %>%
  rowwise %>% 
  mutate(m = {tmp <- c_across(starts_with('m'))
               tail(na.omit(tmp), 1)}) %>%
  ungroup

提前非常感谢!

【问题讨论】:

  • 这个类似问题的选项不会起作用吗?如果其他一切都是 NA,它将返回 ID 字段:names(df)[-1][max.col(!is.na(df[-1]), 'last')]。如果你不这样做,我认为最简单的方法是添加一个索引字段(如 id),这样你也可以识别所有 NA 的行。

标签: r dataframe


【解决方案1】:

如果行中的所有元素都是空的,那么一般的解决方案是创建条件以为这些行返回 NA

library(dplyr)
df %>%
  rowwise %>% 
  mutate(m = {tmp <- c_across(starts_with('m'))
               if(all(is.na(tmp))) NA_character_ else 
                   tail(na.omit(tmp), 1)}) %>%
  ungroup

-输出

# A tibble: 4 × 5
     id m_1   m_2   m_3   m    
  <dbl> <chr> <chr> <chr> <chr>
1     1 a     e     i     i    
2     2 b     <NA>  <NA>  b    
3     3 <NA>  <NA>  <NA>  <NA> 
4     4 d     h     l     l    

如果 OP 只想返回最后一个非 NA 元素,我们还可以添加索引[1] 进行提取,当没有元素时自动返回NA

df %>%
  rowwise %>% 
  mutate(m = {tmp <- c_across(starts_with('m'))
               tail(na.omit(tmp), 1)[1]}) %>%
  ungroup
# A tibble: 4 × 5
     id m_1   m_2   m_3   m    
  <dbl> <chr> <chr> <chr> <chr>
1     1 a     e     i     i    
2     2 b     <NA>  <NA>  b    
3     3 <NA>  <NA>  <NA>  <NA> 
4     4 d     h     l     l    

数据

df <- structure(list(id = c(1, 2, 3, 4), m_1 = c("a", "b", NA, "d"), 
    m_2 = c("e", NA, NA, "h"), m_3 = c("i", NA, NA, "l")), row.names = c(NA, 
-4L), class = "data.frame")

【讨论】:

  • 非常感谢@akrun,这运行得很漂亮!非常感谢您的帮助!
【解决方案2】:

使用来自@akrun 的数据(非常感谢)我们可以这样做:

'\\b[^,]+$' 是一个正则表达式:

\\ ... 表示转义(换句话说,不匹配)这是R 在其他语言中特别它只是一个\

\\b... 元字符 \b 是一个锚点,例如 ^$ 符号。它匹配一个称为“单词边界”的位置。这个匹配是零长度的。

[^,]+... 代表字符类,这里特别是^caret:一个不是, 的字符。 + 在这里表示一个或多个,

$ ... 表示字符串结束或行结束,具体取决于多行模式。

library(dplyr)
library(tidyr)
library(stringr)

df %>% 
  mutate(across(starts_with("m"), ~case_when(!is.na(.) ~ cur_column()), .names = 'new_{col}')) %>%
  unite(New_Col, starts_with('new'), na.rm = TRUE, sep = ', ') %>% 
  mutate(New_Col = str_extract(New_Col, '\\b[^,]+$'))
  id  m_1  m_2  m_3 New_Col
1  1    a    e    i     m_3
2  2    b <NA> <NA>     m_1
3  3 <NA> <NA> <NA>    <NA>
4  4    d    h    l     m_3

【讨论】:

  • 非常感谢!抱歉,我在 R 方面不太有经验,但我想知道 '\\b[^,]+$' 有什么用?
  • 请看我的更新。
【解决方案3】:
library(tidyverse)
df <- data.frame(id = c(1, 2, 3, 4), m_1 = c("a", NA, "c", "d"), m_2 = c("e", NA, "g", "h"), m_3 = c("i", NA, NA, "l"))


df %>%
  rowwise() %>%
  mutate(
    nms = list(str_subset(names(df), "^m")),
    m = c_across(starts_with("m")) %>%
      {
        ifelse(test = all(is.na(.)),
          yes = NA,
          no = nms[which(. == tail(na.omit(.), 1))]
        )
      }
  ) %>%
  select(-nms)
#> # A tibble: 4 × 5
#> # Rowwise: 
#>      id m_1   m_2   m_3   m    
#>   <dbl> <chr> <chr> <chr> <chr>
#> 1     1 a     e     i     m_3  
#> 2     2 <NA>  <NA>  <NA>  <NA> 
#> 3     3 c     g     <NA>  m_2  
#> 4     4 d     h     l     m_3




# only the value no the column name
df %>%
  rowwise() %>%
  mutate(
    m = c_across(starts_with("m")) %>%
      {
        ifelse(test = all(is.na(.)),
          yes = NA,
          no = tail(na.omit(.), 1)
        )
      }
  )
#> # A tibble: 4 × 5
#> # Rowwise: 
#>      id m_1   m_2   m_3   m    
#>   <dbl> <chr> <chr> <chr> <chr>
#> 1     1 a     e     i     i    
#> 2     2 <NA>  <NA>  <NA>  <NA> 
#> 3     3 c     g     <NA>  g    
#> 4     4 d     h     l     l

reprex package (v2.0.1) 于 2022-01-01 创建

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-26
    • 2021-11-10
    相关资源
    最近更新 更多