使用 dplyr、group_by 与 mutate() 或 summarize() & str_c() 或 paste() & collapse 连接字符串/行,但保持 NA & 所有字符串
Concatenating strings / rows using dplyr, group_by with mutate() or summarize() & str_c() or paste() & collapse, but maintain NA & all strings
使用 dplyr
、group_by()
和 mutate()
或 summarize ()
与 paste()
和 collapse
、NA
连接字符串时值被强制转换为字符串 "NA"
.
当使用 str_c()
而不是 paste()
时,与 NA
连接的字符串将被删除(?str_c
: 每当合并缺失值时使用另一个字符串,结果将始终丢失 )。当具有 NA
和非 NA
值的此类组合时,如何删除连接中的 NA
而不是非 NA
?
请参阅下面的示例:
library(dplyr)
library(stringr)
ID <- c(1,1,2,2,3,4)
string <- c(' asfdas ', 'sdf', NA,'sadf', 'NA', NA)
df <- data.frame(ID, string)
# ID string
# 1 1 asfdas
# 2 1 sdf
# 3 2 <NA> # ID 2 has both NA and non-NA values
# 4 2 sadf #
# 5 3 NA
# 6 4 <NA>
两者都有,
df%>%
group_by(ID)%>%
summarize(string = paste(string, collapse = "; "))%>%
distinct_all()
和
df_conca <-df%>%
group_by(ID)%>%
dplyr::mutate(string = paste(string, collapse = "; "))%>%
distinct_all()
结果
ID string
1 1 " asfdas ; sdf"
2 2 "NA; sadf"
3 3 "NA"
4 4 "NA" # NA coerced to "NA"
即NA
变为“NA”:
而
df %>%
group_by(ID)%>%
summarize(string = str_c(string, collapse = "; "))
结果:
ID string
1 1 " asfdas ; sdf"
2 2 NA
3 3 "NA"
4 4 NA
即根据 str_c
规则删除“sadf”:NA
与字符串组合,结果为 NA
.
但是,我想保留真实的 NA
值(例如 'ID' 4)和仅字符串(例如 'ID' 2),这样:
ID string
1 1 " asfdas ; sdf"
2 2 "sadf"
3 3 "NA"
4 4 NA
理想情况下,我想留在 dplyr
工作流程中。
这个问题是
的延伸
使用 pivot_wider
和 unite
library(dplyr)
library(tidyr)
library(data.table)
df %>%
mutate(rn = rowid(ID)) %>%
pivot_wider(names_from = rn, values_from = string) %>%
unite(string, `1`, `2`, na.rm = TRUE, sep = " ; ")%>%
mutate(string = na_if(string, ""))
-输出
# A tibble: 4 x 2
ID string
<dbl> <chr>
1 1 " asfdas ; sdf"
2 2 "sadf"
3 3 "NA"
4 4 <NA>
或者也可以使用coalesce
df %>%
group_by(ID) %>%
summarise(string = na_if(coalesce(str_c(string, collapse = " ; "),
str_c(string[complete.cases(string)], collapse = " ; ")), ""))
-输出
# A tibble: 4 x 2
ID string
<dbl> <chr>
1 1 " asfdas ; sdf"
2 2 "sadf"
3 3 "NA"
4 4 <NA>
这是dplyr框架中的一个解决方案。
这将使用 filter() 删除所有 'NA' 值 - 最初丢失 ID 4 - 然后使用连接替换丢失的 ID。
df_IDs <- data.frame(ID = unique(df$ID))
df%>%
group_by(ID)%>%
filter(!is.na(string)) %>%
summarize(string = paste(string, collapse = "; ")) %>%
full_join(df_IDs, by = "ID")
结果
ID string
1 1 " asfdas ; sdf"
2 2 "sadf"
3 3 "NA"
4 4 NA
感谢大家的努力,同时我想出了自己的答案:
replace(is.na(.),'XXX_MY_NAs_XXXX')%>%
group_by(ID)%>%
summarize(string = paste(string, collapse = "; "))%>%
dplyr::mutate_all(funs(str_replace_all(., c('XXX_MY_NAs_XXXX; ' = ''
,'; XXX_MY_NAs_XXXX' = ''))))%>%
na_if(., 'XXX_MY_NAs_XXXX')
那么获得运行公认答案背书的最佳答案是什么?
我放大了样本数据和运行一个简短的基准。
ID <- sample(1:4, 1000000, replace = T)
string <- sample(c(' asfdas ', 'sdf', NA,'sadf', 'NA', NA), 1000000, replace = T)
df <- data.frame(ID, string)
获胜者是 arkun 的第二个答案。最短的代码和最短的处理时间。然而,处理时间仅相差几毫秒(除了 arkun 的第一个答案,它需要十倍)。
df %>%
group_by(ID) %>%
summarise(string = na_if(coalesce(str_c(string, collapse = " ; "),
str_c(string[complete.cases(string)], collapse = " ; ")), ""))
无论如何,我想应该可以在堆栈交换中接受多个答案,因为不同的答案可能在不同的情况下效果最好。
此外,dplyr::mutate(string = paste(string, collapse = "; "))
的行为对我来说似乎很意外,值得通过一些 dplyr 更新来改变。
使用 dplyr
、group_by()
和 mutate()
或 summarize ()
与 paste()
和 collapse
、NA
连接字符串时值被强制转换为字符串 "NA"
.
当使用 str_c()
而不是 paste()
时,与 NA
连接的字符串将被删除(?str_c
: 每当合并缺失值时使用另一个字符串,结果将始终丢失 )。当具有 NA
和非 NA
值的此类组合时,如何删除连接中的 NA
而不是非 NA
?
请参阅下面的示例:
library(dplyr)
library(stringr)
ID <- c(1,1,2,2,3,4)
string <- c(' asfdas ', 'sdf', NA,'sadf', 'NA', NA)
df <- data.frame(ID, string)
# ID string
# 1 1 asfdas
# 2 1 sdf
# 3 2 <NA> # ID 2 has both NA and non-NA values
# 4 2 sadf #
# 5 3 NA
# 6 4 <NA>
两者都有,
df%>%
group_by(ID)%>%
summarize(string = paste(string, collapse = "; "))%>%
distinct_all()
和
df_conca <-df%>%
group_by(ID)%>%
dplyr::mutate(string = paste(string, collapse = "; "))%>%
distinct_all()
结果
ID string
1 1 " asfdas ; sdf"
2 2 "NA; sadf"
3 3 "NA"
4 4 "NA" # NA coerced to "NA"
即NA
变为“NA”:
而
df %>%
group_by(ID)%>%
summarize(string = str_c(string, collapse = "; "))
结果:
ID string
1 1 " asfdas ; sdf"
2 2 NA
3 3 "NA"
4 4 NA
即根据 str_c
规则删除“sadf”:NA
与字符串组合,结果为 NA
.
但是,我想保留真实的 NA
值(例如 'ID' 4)和仅字符串(例如 'ID' 2),这样:
ID string
1 1 " asfdas ; sdf"
2 2 "sadf"
3 3 "NA"
4 4 NA
理想情况下,我想留在 dplyr
工作流程中。
这个问题是
使用 pivot_wider
和 unite
library(dplyr)
library(tidyr)
library(data.table)
df %>%
mutate(rn = rowid(ID)) %>%
pivot_wider(names_from = rn, values_from = string) %>%
unite(string, `1`, `2`, na.rm = TRUE, sep = " ; ")%>%
mutate(string = na_if(string, ""))
-输出
# A tibble: 4 x 2
ID string
<dbl> <chr>
1 1 " asfdas ; sdf"
2 2 "sadf"
3 3 "NA"
4 4 <NA>
或者也可以使用coalesce
df %>%
group_by(ID) %>%
summarise(string = na_if(coalesce(str_c(string, collapse = " ; "),
str_c(string[complete.cases(string)], collapse = " ; ")), ""))
-输出
# A tibble: 4 x 2
ID string
<dbl> <chr>
1 1 " asfdas ; sdf"
2 2 "sadf"
3 3 "NA"
4 4 <NA>
这是dplyr框架中的一个解决方案。 这将使用 filter() 删除所有 'NA' 值 - 最初丢失 ID 4 - 然后使用连接替换丢失的 ID。
df_IDs <- data.frame(ID = unique(df$ID))
df%>%
group_by(ID)%>%
filter(!is.na(string)) %>%
summarize(string = paste(string, collapse = "; ")) %>%
full_join(df_IDs, by = "ID")
结果
ID string
1 1 " asfdas ; sdf"
2 2 "sadf"
3 3 "NA"
4 4 NA
感谢大家的努力,同时我想出了自己的答案:
replace(is.na(.),'XXX_MY_NAs_XXXX')%>%
group_by(ID)%>%
summarize(string = paste(string, collapse = "; "))%>%
dplyr::mutate_all(funs(str_replace_all(., c('XXX_MY_NAs_XXXX; ' = ''
,'; XXX_MY_NAs_XXXX' = ''))))%>%
na_if(., 'XXX_MY_NAs_XXXX')
那么获得运行公认答案背书的最佳答案是什么?
我放大了样本数据和运行一个简短的基准。
ID <- sample(1:4, 1000000, replace = T)
string <- sample(c(' asfdas ', 'sdf', NA,'sadf', 'NA', NA), 1000000, replace = T)
df <- data.frame(ID, string)
获胜者是 arkun 的第二个答案。最短的代码和最短的处理时间。然而,处理时间仅相差几毫秒(除了 arkun 的第一个答案,它需要十倍)。
df %>%
group_by(ID) %>%
summarise(string = na_if(coalesce(str_c(string, collapse = " ; "),
str_c(string[complete.cases(string)], collapse = " ; ")), ""))
无论如何,我想应该可以在堆栈交换中接受多个答案,因为不同的答案可能在不同的情况下效果最好。
此外,dplyr::mutate(string = paste(string, collapse = "; "))
的行为对我来说似乎很意外,值得通过一些 dplyr 更新来改变。