使用 tidyverse 将字符串列拆分为多个
Splitting string column into many using tidyverse
我有一个带逗号的字符串列。我想将这个单列转换为多个带标签的列,并适当地填充值。输出数据框将有 3 列(A、B 和 C)。第 1 行的 A 列和 B 列用 "Yes" 填充,C 列用 "No" 填充。第 2 行将在所有 3 列中填充 "Yes",等等
df1 <- data.frame(X= c("A, B", "A, B, C", "A", "A, C"))
df1
X
1 A, B
2 A, B, C
3 A
4 A, C
需要输出
A B C
Yes Yes No
Yes Yes Yes
Yes No No
Yes No Yes
任何提示,请。
像这样:
library(tidyverse)
df1 %>%
mutate(id = row_number()) %>%
separate_rows(X) %>%
group_by(id) %>%
mutate(Y = "yes") %>%
spread(X, Y, fill = "no")
# A tibble: 4 x 4
# Groups: id [4]
id A B C
<int> <chr> <chr> <chr>
1 1 yes yes no
2 2 yes yes yes
3 3 yes no no
4 4 yes no yes
一种不依赖于分组的稍微不同的方法。到 "Yes/"No" 的最终转换也是按列执行的,而不是依赖于从长数据到宽数据的转换。对于非常大的数据集,这可能会更有效一些。
df2 <- df1 %>%
mutate(row_num = 1:n()) %>%
separate_rows(X) %>%
spread(X, 1) %>%
select(-row_num) %>%
mutate_all(~ifelse(!is.na(.), 'Yes', 'No'))
A B C
1 Yes Yes No
2 Yes Yes Yes
3 Yes No No
4 Yes No Yes
使用splitstackshape
library(splitstackshape)
newdf=cSplit_e(df1, "X", sep = ", ",type = "character")
newdf[newdf==1]='Yes'
newdf[is.na(newdf)]='No'
newdf
X X_A X_B X_C
1 A, B Yes Yes No
2 A, B, C Yes Yes Yes
3 A Yes No No
4 A, C Yes No Yes
这是 base
中的另一个解决方案
lets <- strsplit(as.character(.subset2(df1,1L)), ', ')
lets_unique <- unique(unlist(lets))
vapply(seq_along(lets_unique),function(k)grepl(lets_unique[k],lets),logical(length(lets)))
# [,1] [,2] [,3]
# [1,] TRUE TRUE FALSE
# [2,] TRUE TRUE TRUE
# [3,] TRUE FALSE FALSE
# [4,] TRUE FALSE TRUE
这是一个使用 base R
和 table
的选项。我们将 'X' 列按 ,
拆分为 vector
的 list
,将其转换为 data.frame
和 stack
的两列,得到频率 table
并将其转换为逻辑
table(stack(setNames(strsplit(as.character(df1$X), ", +"),
seq_len(nrow(df1))))[2:1]) > 0
# values
#ind A B C
# 1 TRUE TRUE FALSE
# 2 TRUE TRUE TRUE
# 3 TRUE FALSE FALSE
# 4 TRUE FALSE TRUE
通过stringi
stringi::stri_split_fixed(df1$X, ", ", simplify = TRUE) != ""
# [,1] [,2] [,3]
# [1,] TRUE TRUE FALSE
# [2,] TRUE TRUE TRUE
# [3,] TRUE FALSE FALSE
# [4,] TRUE TRUE FALSE
TRUE
/FALSE
本质上是 yes
/no
但如果您需要字符矩阵,您可以随时执行 ifelse(., "yes", "no")
并保留矩阵结构.
我有一个带逗号的字符串列。我想将这个单列转换为多个带标签的列,并适当地填充值。输出数据框将有 3 列(A、B 和 C)。第 1 行的 A 列和 B 列用 "Yes" 填充,C 列用 "No" 填充。第 2 行将在所有 3 列中填充 "Yes",等等
df1 <- data.frame(X= c("A, B", "A, B, C", "A", "A, C"))
df1
X
1 A, B
2 A, B, C
3 A
4 A, C
需要输出
A B C
Yes Yes No
Yes Yes Yes
Yes No No
Yes No Yes
任何提示,请。
像这样:
library(tidyverse)
df1 %>%
mutate(id = row_number()) %>%
separate_rows(X) %>%
group_by(id) %>%
mutate(Y = "yes") %>%
spread(X, Y, fill = "no")
# A tibble: 4 x 4
# Groups: id [4]
id A B C
<int> <chr> <chr> <chr>
1 1 yes yes no
2 2 yes yes yes
3 3 yes no no
4 4 yes no yes
一种不依赖于分组的稍微不同的方法。到 "Yes/"No" 的最终转换也是按列执行的,而不是依赖于从长数据到宽数据的转换。对于非常大的数据集,这可能会更有效一些。
df2 <- df1 %>%
mutate(row_num = 1:n()) %>%
separate_rows(X) %>%
spread(X, 1) %>%
select(-row_num) %>%
mutate_all(~ifelse(!is.na(.), 'Yes', 'No'))
A B C
1 Yes Yes No
2 Yes Yes Yes
3 Yes No No
4 Yes No Yes
使用splitstackshape
library(splitstackshape)
newdf=cSplit_e(df1, "X", sep = ", ",type = "character")
newdf[newdf==1]='Yes'
newdf[is.na(newdf)]='No'
newdf
X X_A X_B X_C
1 A, B Yes Yes No
2 A, B, C Yes Yes Yes
3 A Yes No No
4 A, C Yes No Yes
这是 base
lets <- strsplit(as.character(.subset2(df1,1L)), ', ')
lets_unique <- unique(unlist(lets))
vapply(seq_along(lets_unique),function(k)grepl(lets_unique[k],lets),logical(length(lets)))
# [,1] [,2] [,3]
# [1,] TRUE TRUE FALSE
# [2,] TRUE TRUE TRUE
# [3,] TRUE FALSE FALSE
# [4,] TRUE FALSE TRUE
这是一个使用 base R
和 table
的选项。我们将 'X' 列按 ,
拆分为 vector
的 list
,将其转换为 data.frame
和 stack
的两列,得到频率 table
并将其转换为逻辑
table(stack(setNames(strsplit(as.character(df1$X), ", +"),
seq_len(nrow(df1))))[2:1]) > 0
# values
#ind A B C
# 1 TRUE TRUE FALSE
# 2 TRUE TRUE TRUE
# 3 TRUE FALSE FALSE
# 4 TRUE FALSE TRUE
通过stringi
stringi::stri_split_fixed(df1$X, ", ", simplify = TRUE) != ""
# [,1] [,2] [,3]
# [1,] TRUE TRUE FALSE
# [2,] TRUE TRUE TRUE
# [3,] TRUE FALSE FALSE
# [4,] TRUE TRUE FALSE
TRUE
/FALSE
本质上是 yes
/no
但如果您需要字符矩阵,您可以随时执行 ifelse(., "yes", "no")
并保留矩阵结构.