dplyr:group_by 并汇总以折叠(通过串联)包含 NA 的字符串列

eco*_*_33 5 r dplyr summarize

我有一个相对简单的问题,但一直找不到解决方案。

假设我有以下数据集:

ID 虚拟变量 字符串1 字符串2 字符串3
1 0 汤姆 不适用 不适用
1 1 不适用 不适用
2 0 汤姆 不适用 不适用
2 1 不适用 不适用
2 0 不适用 不适用 鲍勃
3 0 史蒂夫 不适用 不适用
3 0 不适用 提米 不适用
4 0 亚历克斯 不适用 不适用

我想使用 group by 和 summarise 来得到以下内容:

ID 虚拟变量 字符串1 字符串2 字符串3
1 1 汤姆 不适用
2 1 汤姆 鲍勃
3 0 史蒂夫 提米 不适用
4 0 亚历克斯 不适用 不适用

我对“dummy_var”没有遇到任何问题,在汇总函数中使用 dummy_var = max(dummy_var) 的变体,但我似乎找不到任何关于如何获取我想要的字符串的信息。

我尝试过类似的变体:

group_by(ID) %>%
summarize(
String1 = str_c(String1)
)
Run Code Online (Sandbox Code Playgroud)

或者

group_by(ID) %>%
summarize(
String1 = case_when(
     length(str_c(String1)) > 0 ~ str_c(String1)
     str_c(String1) == rep(NA,length(str_c(String1)) ~ NA
     )
)
Run Code Online (Sandbox Code Playgroud)

第一次尝试时,行实际上并没有改变。例如,虽然像 max(dummy var) 这样的数值运算将按照组中每一行的预期产生 0 或 1,但字符串变量不会被汇总,并且在取消分组和打印数据帧时,每个 ID 会得到多行,就好像您从来没有首先总结过字符串列。

使用第二种方法时,当每个组的所有值均为 NA 时,该函数总是会失败,即“String(i) 的长度必须大于 0”或类似的情况。

我注意到如果我尝试以下操作

group_by(ID) %>%
summarize(
String1 = str_replace_na(String1)
)
Run Code Online (Sandbox Code Playgroud)

输出与第一个代码块相同,就好像什么也没发生一样。

关于我的数据的其他事实:每组字符串 1 始终至少有一个不带 NA 的值。对于 String2 和 String 3,有许多包含每组的所有 NA,并且我希望折叠的行也能读取 NA,按照我的示例。此外,在任何情况下,任何 group_by() 组的列都不会包含不止一行包含 NA 以外的内容;即,在组内,每行只有三个 String1/2/3 之一,而不是 NA,或者它们都可能是 NA(例如我的示例中的 ID=2)。所有其他包含 int 或 double 值的列汇总都没有问题。这只是字符串。使用paste0代替str_c()也没有什么区别。

谁能给我建议吗?我在网上找不到任何类似的示例,其中 NA 位于组内的列内,并且在组内它们有时包含列内的所有值。

我唯一的选择是在所有 NA 上使用replace_na(),将它们与一些填充文本连接起来,然后返回并为每个值用 stringr 或其他东西将它们拔出。它有效,但我知道必须有一种优雅的方法!

编辑:事实证明,如果我使用 str_replace_na() 而不是 str_c(),你最终会得到,例如,

ID 虚拟变量 字符串1 字符串2 字符串3
1 1 汤姆 “不适用” “不适用”
1 1 “不适用” “乔” “不适用”
2 1 汤姆 “不适用” “不适用”
2 1 “不适用” “乔” “不适用”
2 1 “不适用” “不适用” 鲍勃

也就是说,这些值被替换为字符串“NA”而不是 NA。鉴于以下情况属实,这令人惊讶:

str_replace_na("Something",NA)
> "Something"
str_c("Something",NA)
> NA
Run Code Online (Sandbox Code Playgroud)

Mar*_*Gal 3

你可以使用 的tidyr-fill功能:

library(tidyr)
library(dplyr)

df %>% 
  group_by(ID) %>% 
  fill(starts_with("String"), .direction="downup") %>% 
  filter(dummy_var == max(dummy_var)) %>% 
  distinct() %>% 
  ungroup()
Run Code Online (Sandbox Code Playgroud)

返回

# A tibble: 4 x 5
     ID dummy_var String1 String2 String3
  <dbl>     <dbl> <chr>   <chr>   <chr>  
1     1         1 Tom     Jo      NA     
2     2         1 Tom     Jo      Bob    
3     3         0 Steve   Timmy   NA     
4     4         0 Alex    NA      NA   
Run Code Online (Sandbox Code Playgroud)

##数据

df <- structure(list(ID = c(1, 1, 2, 2, 2, 3, 3, 4), dummy_var = c(0, 
1, 0, 1, 0, 0, 0, 0), String1 = c("Tom", NA, "Tom", NA, NA, "Steve", 
NA, "Alex"), String2 = c(NA, "Jo", NA, "Jo", NA, NA, "Timmy", 
NA), String3 = c(NA, NA, NA, NA, "Bob", NA, NA, NA)), class = c("spec_tbl_df", 
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -8L), spec = structure(list(
    cols = list(ID = structure(list(), class = c("collector_double", 
    "collector")), dummy_var = structure(list(), class = c("collector_double", 
    "collector")), String1 = structure(list(), class = c("collector_character", 
    "collector")), String2 = structure(list(), class = c("collector_character", 
    "collector")), String3 = structure(list(), class = c("collector_character", 
    "collector"))), default = structure(list(), class = c("collector_guess", 
    "collector")), skip = 1L), class = "col_spec"))
Run Code Online (Sandbox Code Playgroud)