【问题标题】:Split comma-separated strings into boolean columns将逗号分隔的字符串拆分为布尔列
【发布时间】:2014-10-24 23:53:42
【问题描述】:

我有:

id choice
----------
1  "a,b,c"
2  "c"
3  "a,c"
4  "b,c"

我需要

id a b c
---------
1  1 1 1
2  0 0 1
3  0 0 1
4  0 1 1

(或等效的 TRUE/FALSE 值)

有没有办法在 R 中做到这一点?我已经查看了strsplit,但这似乎没有帮助。

【问题讨论】:

    标签: r


    【解决方案1】:

    这正是我的“splitstackshape”包中的cSplit_e 的设计目的。

    library(splitstackshape)
    cSplit_e(DF, "choice", sep = ",", mode = "binary", 
             type = "character", fill = 0, drop = TRUE)
    #   id choice_a choice_b choice_c
    # 1  1        1        1        1
    # 2  2        0        0        1
    # 3  3        1        0        1
    # 4  4        0        1        1
    

    这使用来自@G.Grothendieck 的答案的DF 作为输入:

    Lines <- 'id choice
    ----------
    1  "a,b,c"
    2  "c"
    3  "a,c"
    4  "b,c"'
    DF <- read.table(text = Lines, header = TRUE, comment = "-", as.is = TRUE)
    

    【讨论】:

    • 谢谢! splitstackshape 很棒。
    • cSpit 是一个非常好的函数系列,非常适合整理讨厌的数据类型。干得好+1
    【解决方案2】:

    试试这个:

    txt = 'id choice
    ----------
    1  "a,b,c"
    2  "c"
    3  "a,c"
    4  "b,c"'
    
    library(dplyr)
    
    txt %>% textConnection %>% 
      read.table(skip = 2, stringsAsFactors = FALSE) %>%
      select(V2) %>% unlist %>%
      strsplit("[,]") %>%
      lapply(function(x) data.frame(t(table(c(x, "a", "b", "c"))>1))) %>%
      rbind_all
    

    然后你会得到

    Source: local data frame [4 x 3]
    
          a     b    c
    1  TRUE  TRUE TRUE
    2 FALSE FALSE TRUE
    3  TRUE FALSE TRUE
    4 FALSE  TRUE TRUE
    

    【讨论】:

      【解决方案3】:

      这假设像 @kohske 所做的那样,您的数据实际上看起来就像您提供的那样。如果没有请以后使用dput分享数据:

      txt = 'id choice
      ----------
      1  "a,b,c"
      2  "c"
      3  "a,c"
      4  "b,c"'
      
      dat <- setNames(read.table(text=txt, skip = 2, stringsAsFactors = FALSE), 
          strsplit(strsplit(txt, "\n")[[1]][1], "\\s+")[[1]]
      )
      
      library(qdapTools)
      
      matrix2df(mtabulate(unlist(lapply(split(dat[[2]], dat[[1]]), 
          strsplit, ",\\s*"), recursive=FALSE)), "id")
      

      我讨厌嵌套调用,因为我熟悉了magrittr 的管道 %&gt;% 所以这里使用的是管道:

      library(magrittr)
      
      txt %>% read.table(text=., skip = 2, stringsAsFactors = FALSE) %>%
          setNames(strsplit(strsplit(txt, "\n")[[1]][1], "\\s+")[[1]]) %>%
          with(split(choice, id)) %>%
          lapply(strsplit, ",\\s*") %>%
          unlist(recursive=FALSE) %>%
          mtabulate %>%
          matrix2df("id")
      
      ##   id a b c
      ## 1  1 1 1 1
      ## 2  2 0 0 1
      ## 3  3 1 0 1
      ## 4  4 0 1 1
      

      【讨论】:

        【解决方案4】:

        使用strsplit 拆分choice 创建s 并将DF$id 作为名称。从s 提取所有级别的向量all_lev。然后sapplys 之上的一个函数,它从s 的每个组件创建一个因子并在其上运行table。最后转置。

        s <- setNames( strsplit(DF$choice, ","), DF$id )
        all_lev <- sort(unique(unlist(s)))
        m <- t(sapply(s, function(x) table(factor(x, lev = all_lev))))
        

        这给出了以下矩阵,其中行名是 id:

        > m
          a b c
        1 1 1 1
        2 0 0 1
        3 1 0 1
        4 0 1 1
        

        如果您更喜欢数据框,请使用上面的m

        data.frame(id = rownames(m), m)
        

        注意 1:如果我们知道级别总是"a""b""c",那么我们可以将all_lev硬编码为:

        s <- setNames( strsplit(DF$choice, ","), DF$id )
        m <- t(sapply(s, function(x) table(factor(x, lev = c("a", "b", "c")))))
        

        注意 2:我们假设 DF 是这样的:

        Lines <- 'id choice
        ----------
        1  "a,b,c"
        2  "c"
        3  "a,c"
        4  "b,c"'
        DF <- read.table(text = Lines, header = TRUE, comment = "-", as.is = TRUE)
        

        更新缩短答案。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-12-21
          • 2021-02-24
          相关资源
          最近更新 更多