如何将可变数量的串联标签的列拆分为每个标签的一列?
How to split a column of a variable number of concatenated tags into one column per tag?
考虑以下数据:
library(tibble)
key <- c("a", "b", "c", "d", "e")
tags <- c("A,B", "B", "A,E", "C,D", "")
data <- tibble(key, tags)
在这里,key
可能表示书名,tags
可能表示流派,或者 key
可能表示电子邮件发件人,而 tags
可能表示收件人。重要的是,列 tags
可以具有可变(可能为零)数量的不同子字符串。
为了拆分固定数量的连接标签(例如像数据)我可以使用 tidyr::spread
,我可以使用字符串拆分来分隔 tags
列本身,但是如何组合两个?
我希望转换后的数据如下所示:
key A B C D E
a TRUE TRUE FALSE FALSE FALSE
b FALSE TRUE FALSE FALSE FALSE
c TRUE FALSE FALSE FALSE TRUE
d FALSE FALSE TRUE TRUE FALSE
e FALSE FALSE FALSE FALSE FALSE
我可以看到可以通过拆分 tags
、确定唯一的子字符串并循环遍历每个子字符串并测试每一行的 tags
是否包含字符串来分几步完成此操作。但我更愿意 在使用 tidyverse 的管道中执行此操作。
问题:如何将可变数量的串联标签拆分为每个标签一列?
这是一个基本的 R 替代方法:
# get unique values in tags
x <- unique(unlist(strsplit(df$tags, ",", fixed=TRUE)))
# check for existence in the tags column
res <- sapply(paste0("(^|.*,)", x, "(,.*|$)"), grepl, df$tags)
# add sensible dimension names
dimnames(res) <- list(df$key, x)
生成的矩阵如下所示:
res
# A B E C D
#a TRUE TRUE FALSE FALSE FALSE
#b FALSE TRUE FALSE FALSE FALSE
#c TRUE FALSE TRUE FALSE FALSE
#d FALSE FALSE FALSE TRUE TRUE
#e FALSE FALSE FALSE FALSE FALSE
第三个基础 R 方法是
# get named list splitting by commas
myList <- setNames(strsplit(tags, split=",", fixed=TRUE), key)
# get unique elements from list
colTemp <- sort(unique(unlist(myList)))
# check each list element for the unique elements, return matrix
myMat <- t(sapply(myList, function(i) colTemp %in% i))
# add column names
colnames(myMat) <- colTemp
哪个returns
myMat
A B C D E
a TRUE TRUE FALSE FALSE FALSE
b FALSE TRUE FALSE FALSE FALSE
c TRUE FALSE FALSE FALSE TRUE
d FALSE FALSE TRUE TRUE FALSE
e FALSE FALSE FALSE FALSE FALSE
来自docendo discimus的方法,使用不同的粘贴方式
xx <- sort(unique(unlist(strsplit(data$tags,","))))
data1 <- sapply(paste(xx), grepl, data$tags)
data <- cbind(data[,1],data1)
key A B C D E
1 a TRUE TRUE FALSE FALSE FALSE
2 b FALSE TRUE FALSE FALSE FALSE
3 c TRUE FALSE FALSE FALSE TRUE
4 d FALSE FALSE TRUE TRUE FALSE
5 e FALSE FALSE FALSE FALSE FALSE
tidyr 中的 separate_rows
函数可以帮助您到达所需位置。这会将 tags
中的字符串拆分为单独的行而不是单独的列,这使您可以使用 spread
.
为了获得 TRUE
/FALSE
结果,我创建了一个包含所有 TRUE
的新列作为值列,然后用 FALSE
填充缺失的列在 spread
。最后,spread
将空白单元格保留为列名,我通过 select
将其删除。可能有更好的方法来做到这一点(也许转换为 NA?)。
library(tidyr)
library(dplyr)
data %>%
separate_rows(tags) %>%
mutate(tagslog = TRUE) %>%
spread(tags, tagslog, fill = FALSE) %>%
select(-one_of(""))
key A B C D E
* <chr> <lgl> <lgl> <lgl> <lgl> <lgl>
1 a TRUE TRUE FALSE FALSE FALSE
2 b FALSE TRUE FALSE FALSE FALSE
3 c TRUE FALSE FALSE FALSE TRUE
4 d FALSE FALSE TRUE TRUE FALSE
5 e FALSE FALSE FALSE FALSE FALSE
您几乎可以通过 separate_rows
和 table
到达您想要的位置,但我仍然有需要删除的额外空白列。
data %>%
separate_rows(tags) %>%
with(., table(key, tags) == 1)
tags
key A B C D E
a FALSE TRUE TRUE FALSE FALSE FALSE
b FALSE FALSE TRUE FALSE FALSE FALSE
c FALSE TRUE FALSE FALSE FALSE TRUE
d FALSE FALSE FALSE TRUE TRUE FALSE
e TRUE FALSE FALSE FALSE FALSE FALSE
考虑以下数据:
library(tibble)
key <- c("a", "b", "c", "d", "e")
tags <- c("A,B", "B", "A,E", "C,D", "")
data <- tibble(key, tags)
在这里,key
可能表示书名,tags
可能表示流派,或者 key
可能表示电子邮件发件人,而 tags
可能表示收件人。重要的是,列 tags
可以具有可变(可能为零)数量的不同子字符串。
为了拆分固定数量的连接标签(例如像数据)我可以使用 tidyr::spread
,我可以使用字符串拆分来分隔 tags
列本身,但是如何组合两个?
我希望转换后的数据如下所示:
key A B C D E
a TRUE TRUE FALSE FALSE FALSE
b FALSE TRUE FALSE FALSE FALSE
c TRUE FALSE FALSE FALSE TRUE
d FALSE FALSE TRUE TRUE FALSE
e FALSE FALSE FALSE FALSE FALSE
我可以看到可以通过拆分 tags
、确定唯一的子字符串并循环遍历每个子字符串并测试每一行的 tags
是否包含字符串来分几步完成此操作。但我更愿意 在使用 tidyverse 的管道中执行此操作。
问题:如何将可变数量的串联标签拆分为每个标签一列?
这是一个基本的 R 替代方法:
# get unique values in tags
x <- unique(unlist(strsplit(df$tags, ",", fixed=TRUE)))
# check for existence in the tags column
res <- sapply(paste0("(^|.*,)", x, "(,.*|$)"), grepl, df$tags)
# add sensible dimension names
dimnames(res) <- list(df$key, x)
生成的矩阵如下所示:
res
# A B E C D
#a TRUE TRUE FALSE FALSE FALSE
#b FALSE TRUE FALSE FALSE FALSE
#c TRUE FALSE TRUE FALSE FALSE
#d FALSE FALSE FALSE TRUE TRUE
#e FALSE FALSE FALSE FALSE FALSE
第三个基础 R 方法是
# get named list splitting by commas
myList <- setNames(strsplit(tags, split=",", fixed=TRUE), key)
# get unique elements from list
colTemp <- sort(unique(unlist(myList)))
# check each list element for the unique elements, return matrix
myMat <- t(sapply(myList, function(i) colTemp %in% i))
# add column names
colnames(myMat) <- colTemp
哪个returns
myMat
A B C D E
a TRUE TRUE FALSE FALSE FALSE
b FALSE TRUE FALSE FALSE FALSE
c TRUE FALSE FALSE FALSE TRUE
d FALSE FALSE TRUE TRUE FALSE
e FALSE FALSE FALSE FALSE FALSE
来自docendo discimus的方法,使用不同的粘贴方式
xx <- sort(unique(unlist(strsplit(data$tags,","))))
data1 <- sapply(paste(xx), grepl, data$tags)
data <- cbind(data[,1],data1)
key A B C D E
1 a TRUE TRUE FALSE FALSE FALSE
2 b FALSE TRUE FALSE FALSE FALSE
3 c TRUE FALSE FALSE FALSE TRUE
4 d FALSE FALSE TRUE TRUE FALSE
5 e FALSE FALSE FALSE FALSE FALSE
tidyr 中的 separate_rows
函数可以帮助您到达所需位置。这会将 tags
中的字符串拆分为单独的行而不是单独的列,这使您可以使用 spread
.
为了获得 TRUE
/FALSE
结果,我创建了一个包含所有 TRUE
的新列作为值列,然后用 FALSE
填充缺失的列在 spread
。最后,spread
将空白单元格保留为列名,我通过 select
将其删除。可能有更好的方法来做到这一点(也许转换为 NA?)。
library(tidyr)
library(dplyr)
data %>%
separate_rows(tags) %>%
mutate(tagslog = TRUE) %>%
spread(tags, tagslog, fill = FALSE) %>%
select(-one_of(""))
key A B C D E
* <chr> <lgl> <lgl> <lgl> <lgl> <lgl>
1 a TRUE TRUE FALSE FALSE FALSE
2 b FALSE TRUE FALSE FALSE FALSE
3 c TRUE FALSE FALSE FALSE TRUE
4 d FALSE FALSE TRUE TRUE FALSE
5 e FALSE FALSE FALSE FALSE FALSE
您几乎可以通过 separate_rows
和 table
到达您想要的位置,但我仍然有需要删除的额外空白列。
data %>%
separate_rows(tags) %>%
with(., table(key, tags) == 1)
tags
key A B C D E
a FALSE TRUE TRUE FALSE FALSE FALSE
b FALSE FALSE TRUE FALSE FALSE FALSE
c FALSE TRUE FALSE FALSE FALSE TRUE
d FALSE FALSE FALSE TRUE TRUE FALSE
e TRUE FALSE FALSE FALSE FALSE FALSE