如何将每个标记的可变数量的连接标记的列拆分为一列?

时间:2016-08-02 13:26:32

标签: r dplyr tidyr stringr

考虑以下数据:

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 在管道中执行

问题:如何将每个标记的可变数量的连接标记拆分为一列?

4 个答案:

答案 0 :(得分:5)

这是一个基本的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

答案 1 :(得分:3)

来自 tidyr separate_rows功能可以帮助您获得所需的位置。这会将tags中的字符串拆分为单独的行而不是单独的列,这样就可以使用spread

要获取TRUE / FALSE结果,我创建了一个包含所有TRUE的新列作为值列,然后在FALSE填充了spread {1}}。最后,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_rowstable几乎可以到达目的地,但我仍然需要删除额外的空白列。

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

答案 2 :(得分:1)

第三个基础R方法是

currencyName : {type : String, required : true}

返回

# 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

答案 3 :(得分:0)

从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