【问题标题】:Split character column into several binary (0/1) columns将字符列拆分为几个二进制 (0/1) 列
【发布时间】:2015-07-11 08:48:33
【问题描述】:

我有一个这样的字符向量:

a <- c("a,b,c", "a,b", "a,b,c,d")

我想做的是创建一个数据框,其中每个字符串中的单个字母由虚拟列表示:

   a    b    c    d
1] 1    1    1    0
2] 1    1    0    0
3] 1    1    1    1

我觉得我需要使用read.tablereshape 的某种组合,但我真的很挣扎。任何和帮助表示赞赏。

【问题讨论】:

  • 可以肯定会去read.table加上某种形式的“重塑”方式,但你可能会继续挣扎:-)

标签: r split


【解决方案1】:

你可以试试我的“splitstackshape”包中的cSplit_e

library(splitstackshape)
a <- c("a,b,c", "a,b", "a,b,c,d")
cSplit_e(as.data.table(a), "a", ",", type = "character", fill = 0)
#          a a_a a_b a_c a_d
# 1:   a,b,c   1   1   1   0
# 2:     a,b   1   1   0   0
# 3: a,b,c,d   1   1   1   1
cSplit_e(as.data.table(a), "a", ",", type = "character", fill = 0, drop = TRUE)
#    a_a a_b a_c a_d
# 1:   1   1   1   0
# 2:   1   1   0   0
# 3:   1   1   1   1

还有来自“qdapTools”的mtabulate

library(qdapTools)
mtabulate(strsplit(a, ","))
#   a b c d
# 1 1 1 1 0
# 2 1 1 0 0
# 3 1 1 1 1

一个非常直接的基础 R 方法是使用 table 以及 stackstrsplit

table(rev(stack(setNames(strsplit(a, ",", TRUE), seq_along(a)))))
#    values
# ind a b c d
#   1 1 1 1 0
#   2 1 1 0 0
#   3 1 1 1 1

【讨论】:

  • 嗯,不知道stack 是基础 R 中的东西。很酷的东西。 strsplit 中的 TRUE 在这里似乎没有任何作用。
  • @Frank,除了让它更快,什么都不做。
【解决方案2】:

另一个复杂的base-R解决方案:

x  <- strsplit(a,",")
xl <- unique(unlist(x))

t(sapply(x,function(z)table(factor(z,levels=xl))))

给了

     a b c d
[1,] 1 1 1 0
[2,] 1 1 0 0
[3,] 1 1 1 1

【讨论】:

    【解决方案3】:

    基础R - 但更长的解决方案:

    el = unique(unlist(strsplit(a, ',')))
    do.call(rbind, lapply(a, function(u) setNames(el %in% strsplit(u,',')[[1]]+0L, el))
    #     a b c d
    #[1,] 1 1 1 0
    #[2,] 1 1 0 0
    #[3,] 1 1 1 1
    

    【讨论】:

    • 这是一个了不起的解决方案 - 但是,我不确定 +0L 的作用。你介意解释一下这个答案的逻辑吗?
    • 它在a 的每个元素上循环,拆分它们并返回一个布尔向量,如果这些拆分的元素在el 中。我只是添加0 将布尔向量变成0/1 向量!
    【解决方案4】:

    另一个选项是tstrsplit() 来自

    library(data.table)
    vapply(tstrsplit(a, ",", fixed = TRUE, fill = 0), ">", integer(length(a)), 0L)
    #      [,1] [,2] [,3] [,4]
    # [1,]    1    1    1    0
    # [2,]    1    1    0    0
    # [3,]    1    1    1    1
    

    【讨论】:

    • 看起来不错,&gt; 部分看起来很聪明。是否使用'0' &gt; 0#FALSE,而其他都是TRUE
    • 对,这取决于fill = 0
    【解决方案5】:

    在我写完这篇文章后,我注意到 Beauvel 上校的解决方案非常相似,但也许这足以成为一个单独的解决方案。没有使用任何包。

    首先,我们将字符串拆分成一个向量列表,L,然后我们计算它们的并集,u。最后我们为每个列表元素和rbind一起确定一个二进制向量,使用+ 0将结果从逻辑转换为数字并设置列名。

    L <- strsplit(a, ",")
    u <- Reduce(union, L)
    m <- do.call(rbind, lapply(L, `%in%`, x = u)) + 0
    colnames(m) <- u
    

    给予:

    > m
         a b c d
    [1,] 1 1 1 0
    [2,] 1 1 0 0
    [3,] 1 1 1 1
    

    添加最后两行代码可以替换为以下任一行:

    do.call(rbind, lapply(lapply(L, factor, levels = u), table))
    
    do.call(rbind, Map(function(x) sapply(u, `%in%`, x), L)) + 0
    

    【讨论】:

      【解决方案6】:

      不幸的是,base R 不提供向量化字符串匹配功能,但 stringi 包提供。

      library(stringi)
      a=c("a,b,c", "a,b", "a,b,c,d")
      1*outer(a,unique(unlist(strsplit(a,","))),stri_detect_regex)
      
      #     [,1] [,2] [,3] [,4]
      #[1,]    1    1    1    0
      #[2,]    1    1    0    0
      #[3,]    1    1    1    1
      

      【讨论】:

        【解决方案7】:

        我在fastDummies 中使用dummy_cols 取得了很大的成功,它可以相当简单地处理这个问题并且可以通过变量指定。

        library(fastDummies)
        
        a <- c("a,b,c", "a,b", "a,b,c,d")
        a <- dummy_cols(a, split = ",")
        

        输出

        #    .data .data_a .data_b .data_c .data_d
        # 1   a,b,c       1       1       1       0
        # 2     a,b       1       1       0       0
        # 3 a,b,c,d       1       1       1       1
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-24
          • 2015-11-07
          • 2021-05-02
          • 2013-04-01
          • 1970-01-01
          相关资源
          最近更新 更多