【问题标题】:Coalesce columns and create another column to specify source合并列并创建另一个列以指定源
【发布时间】:2020-11-09 16:44:00
【问题描述】:

我正在使用dplyr::coalesce() 将几列合并为一列。最初,跨列,每一行只有一列具有实际值,而其他列是NA。基于合并,我想创建一个附加列,该列将指定从中获取合并值的 source 列。

我的尝试受到其他 dplyr 函数中现有功能的启发。例如,dplyr::bind_rows() 具有 .id 参数,用于指定新数据帧中每一行的源数据帧。

来自bind_rows()的文档:

当提供 .id 时,会创建一个新的标识符列来链接 每一行到它的原始数据框。标签取自 bind_rows() 的命名参数。当数据帧列表是 提供时,标签取自列表的名称。如果没有名字 发现使用数字序列代替。

同样,我目前的问题是关于coalesce(),而不是bind_rows(),但我只是想把它放在上下文中。

数据

df <-
  data.frame(
  group_1 = c(NA, NA, NA, NA, 2),
  group_2 = c(NA, 4, NA, NA, NA),
  group_3 = c(NA, NA, 5, NA, NA),
  group_4 = c(1, NA, NA, 2, NA),
  group_5 = c(NA, NA, NA, NA, NA)
)

df

##   group_1 group_2 group_3 group_4 group_5         ## each row
## 1      NA      NA      NA       1      NA         ## has one value
## 2      NA       4      NA      NA      NA         ## and the rest
## 3      NA      NA       5      NA      NA         ## are NAs
## 4      NA      NA      NA       2      NA
## 5       2      NA      NA      NA      NA

将这些列组合成一个(附加)列

library(dplyr)

df %>%
  mutate(one_col = coalesce(group_1, group_2, group_3, group_4, group_5))

##   group_1 group_2 group_3 group_4 group_5 one_col
## 1      NA      NA      NA       1      NA       1
## 2      NA       4      NA      NA      NA       4
## 3      NA      NA       5      NA      NA       5
## 4      NA      NA      NA       2      NA       2
## 5       2      NA      NA      NA      NA       2



如何添加另一列来指定“来源”,即one_col 中的值取自哪一列?

期望的输出

  group_1 group_2 group_3 group_4 group_5 one_col source_col
1      NA      NA      NA       1      NA       1    group_4
2      NA       4      NA      NA      NA       4    group_2
3      NA      NA       5      NA      NA       5    group_3
4      NA      NA      NA       2      NA       2    group_4
5       2      NA      NA      NA      NA       2    group_1


编辑


@Karthik 下面的回答让我认为我上面使用的示例数据表明了一种过于狭窄和具体的情况。 Karthik 提供的解决方案独立于合并操作。因此,如果我们交换订单并先创建source_col,然后再创建coalesce,代码仍然可以工作。

但是,如果数据的每行有多个 NAcoalesce 仍然会做它的事情,但我们不能再将 source_col 建立在找到单个非缺失值的基础上。因此,我正在修改问题和数据。

数据

df_2 <-
  data.frame(
  group_1 = c(NA, NA, NA, NA, 2),
  group_2 = c(NA, 4, NA, NA, 1),
  group_3 = c(NA, NA, 5, NA, NA),
  group_4 = c(1, NA, NA, 2, NA),
  group_5 = c(NA, 3, NA, NA, NA)
)

> df_2

##   group_1 group_2 group_3 group_4 group_5
## 1      NA      NA      NA       1      NA   ## <--- one non-NA
## 2      NA       4      NA      NA       3   ## <--- *two* non-NA
## 3      NA      NA       5      NA      NA   ## <--- one non-NA
## 4      NA      NA      NA       2      NA   ## <--- one non-NA
## 5       2       1      NA      NA      NA   ## <--- *two* non-NA

合并

> df_2 %>%
   mutate(one_col = coalesce(group_1, group_2, group_3, group_4, group_5))

##   group_1 group_2 group_3 group_4 group_5 one_col
## 1      NA      NA      NA       1      NA       1
## 2      NA       4      NA      NA       3       4
## 3      NA      NA       5      NA      NA       5
## 4      NA      NA      NA       2      NA       2
## 5       2       1      NA      NA      NA       2

如何添加一个源列,以 匹配coalesce() 选择的值与它来自的原始列?

期望的输出

  group_1 group_2 group_3 group_4 group_5 one_col source_col
1      NA      NA      NA       1      NA       1    group_4
2      NA       4      NA      NA       3       4    group_2
3      NA      NA       5      NA      NA       5    group_3
4      NA      NA      NA       2      NA       2    group_4
5       2       1      NA      NA      NA       2    group_1

【问题讨论】:

    标签: r dataframe dplyr


    【解决方案1】:

    这行得通吗:

    df %>%
       mutate(one_col = coalesce(group_1, group_2, group_3, group_4, group_5)) %>% 
    rowwise() %>% mutate(group_col = names(df)[!is.na(c_across(group_1:group_5))])
    # A tibble: 5 x 7
    # Rowwise: 
      group_1 group_2 group_3 group_4 group_5 one_col group_col
        <dbl>   <dbl>   <dbl>   <dbl> <lgl>     <dbl> <chr>    
    1      NA      NA      NA       1 NA            1 group_4  
    2      NA       4      NA      NA NA            4 group_2  
    3      NA      NA       5      NA NA            5 group_3  
    4      NA      NA      NA       2 NA            2 group_4  
    5       2      NA      NA      NA NA            2 group_1  
    >
    

    更新答案:

    df_2 %>% mutate(one_col = coalesce(group_1, group_2, group_3, group_4, group_5)) %>% rowwise() %>% 
       mutate(group_col = names(df_2)[!is.na(c_across(group_1:group_5))][1])
    # A tibble: 5 x 7
    # Rowwise: 
      group_1 group_2 group_3 group_4 group_5 one_col group_col
        <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl> <chr>    
    1      NA      NA      NA       1      NA       1 group_4  
    2      NA       4      NA      NA       3       4 group_2  
    3      NA      NA       5      NA      NA       5 group_3  
    4      NA      NA      NA       2      NA       2 group_4  
    5       2       1      NA      NA      NA       2 group_1  
    

    【讨论】:

    • 谢谢,@Karthik。鉴于我输入的数据,您的解决方案可以完成工作。但是,这不是我发布问题时的想法。我已经编辑了帖子以澄清这一点。
    • @Emman,已更新我的答案,请检查是否适合您。
    【解决方案2】:

    这似乎正在将数据从宽格式重塑为长格式。

    df2 <- reshape(df,
                   direction = 'long',
                   varying = 1:5,
                   v.names = 'one_col',
                   timevar = 'source_col',
                   times = paste0('group_', 1:5))
    

    这些函数中的任何一个都将删除由reshape 返回的NA

    df2[!is.na(df2$one_col), ]
    na.omit(df2)
    
              source_col one_col id
    5.group_1    group_1       2  5
    2.group_2    group_2       4  2
    3.group_3    group_3       5  3
    1.group_4    group_4       1  1
    4.group_4    group_4       2  4
    

    【讨论】:

      【解决方案3】:

      这是一个快速的基础解决方案:

      cbind(df_2,
            t(apply(df_2, 1, function(i){
              c(i[ which(!is.na(i))[1] ],
                colnames(df_2)[ which(!is.na(i))[1] ])
            }))
            )
      #   group_1 group_2 group_3 group_4 group_5 1       2
      # 1      NA      NA      NA       1      NA 1 group_4
      # 2      NA       4      NA      NA       3 4 group_2
      # 3      NA      NA       5      NA      NA 5 group_3
      # 4      NA      NA      NA       2      NA 2 group_4
      # 5       2       1      NA      NA      NA 2 group_1
      

      非常确定,这可以使用“which.min/is.na/arrayInd”组合来完成,无需 apply 循环,目前没有时间进行测试。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-04
        • 1970-01-01
        • 2021-04-10
        • 2019-08-12
        • 1970-01-01
        • 2021-01-21
        相关资源
        最近更新 更多