【问题标题】:count number of part of string by columns按列计算字符串部分的数量
【发布时间】:2011-05-24 12:21:26
【问题描述】:

我有一个这样的文本文件:

V1 V2   V3
X  N    aaaaaabbbabab
C  T    ababaaabaaabb
V  H    babbbabaabbba

我要做的是计算每个V3的列中有多少a和多少b。

所以输出会是这样的:

   col1  col2 col3 .......  col13
a  2     2    2             1
b  1     1    1             2

如何做到这一点?

我尝试了count函数和子字符串,但没有成功。

谢谢

【问题讨论】:

    标签: r


    【解决方案1】:

    假设dat 包含您的数据,我们使用strsplit() 来处理

    tt <- matrix(unlist(strsplit(dat$V3, split = "")), ncol = 13, byrow = TRUE)
    

    给予:

    > tt
         [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13]
    [1,] "a"  "a"  "a"  "a"  "a"  "a"  "b"  "b"  "b"  "a"   "b"   "a"   "b"  
    [2,] "a"  "b"  "a"  "b"  "a"  "a"  "a"  "b"  "a"  "a"   "a"   "b"   "b"  
    [3,] "b"  "a"  "b"  "b"  "b"  "a"  "b"  "a"  "a"  "b"   "b"   "b"   "a"
    

    我们可以通过注意正确设置级别来获得所需的结果:

    apply(tt, 2, function(x) c(table(factor(x, levels = c("a","b")))))
    

    给出:

    > apply(tt, 2, function(x) c(table(factor(x, levels = c("a","b")))))
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13]
    a    2    2    2    1    2    3    1    1    2     2     1     1     1
    b    1    1    1    2    1    0    2    2    1     1     2     2     2
    

    要自动选择适当的级别,我们可以执行以下操作:

    > lev <- levels(factor(tt))
    > apply(tt, 2, function(x, levels) c(table(factor(x, levels = lev))), 
    +       levels = lev)
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13]
    a    2    2    2    1    2    3    1    1    2     2     1     1     1
    b    1    1    1    2    1    0    2    2    1     1     2     2     2
    

    在第一行中,我们将tt 视为向量,并在将tt 临时转换为因子后提取级别。然后,我们将这些级别 (lev) 提供给 apply() 步骤,而不是明确说明级别。

    【讨论】:

    • @Gavin Simpson:你能解释一下你做了什么吗?
    • @smack 和@Joris 一样得到tt。不同之处在于我如何使用table()。重要的是让table() 同时计算"a""b",即使其中一个缺失也是如此。这样做的方法是将levels 显式设置为c("a","b")。这是否足够,还是我应该尝试解释更多?
    • 不,我认为这就足够了,但是如果我想在列表中添加第三个变量,也许“c”我可以将它添加到级别对吗??我可以用什么来绘制这些数据框??
    • @smack 实际上,我们可以简化最后一步,因为如果table() 中的计数正确,apply() 会返回一个矩阵。
    • @smack 是的,只需将"c" 添加到级别列表即可。如果它们很多,我们也可以自动执行该步骤,以选择正确的级别。
    【解决方案2】:

    编辑:在 Gavin Simpson 的 cmets 之后更正了解决方案。现在可以使用了


    为避免多次转换为因子,您可以对索引和 tapply 使用以下技巧:

    tt <- c("aaaaaabbbabab","ababaaabaaabb","babbbabaabbba")
    
    ttstr <- strsplit(tt,"")
    ttf <- factor(unlist(ttstr))
    n <- length(ttstr[[1]])
    k <- length(ttstr)
    
    > do.call(cbind,tapply(ttf,rep(1:n,k),table))
      1 2 3 4 5 6 7 8 9 10 11 12 13
    a 2 2 2 1 2 3 1 1 2  2  1  1  1
    b 1 1 1 2 1 0 2 2 1  1  2  2  2
    

    这使@Gavin 所示方法的速度提高了大约 7 倍

    > benchmark(method1(tt),method2(tt),replications=1)
             test replications elapsed relative user.self 
    1 method1(tt)            1    0.89 1.000000      0.89   
    2 method2(tt)            1    6.99 7.853933      6.98     
    

    【讨论】:

    • @Joris Meys:这两种方法都有效,但都给出了警告:警告消息:在函数中(...,deparse.level = 1):结果的行数不是向量长度的倍数(arg 1)
    • @smack :那么您提供的数据与您拥有的数据不同,因为当我将 tt 替换为 df$V3 时,我没有收到警告。哪一行给了你警告?
    • @Joris Meys:好的,我给了你一个有代表性的数据示例,但是感谢它有效,但是当我将其转换为数据框时,数字消失了并被 a 和 b 替换,但是我想在图表中绘制这些数字(x 轴:列号(1..13)和 y 轴(a 和 b 的数量)),我怎样才能在不丢失数字的情况下转换它,抱歉问很多,但我是 R 的新手
    • @Joris 实际上,两者都是错误的。我想出了与您的矩阵一相同的解决方案,然后意识到对于仅包含“a”的“列”6,您会得到错误的答案。看看你的结果,它计算了 3 个“b”和 3 个“a”,这是不对的 - R 正在默默地扩展 a 的计数。您需要根据我的回答在table() 调用中设置正确的级别。
    • @smack :你的代码出了点问题,不要忽视它。如果您收到警告,则它不起作用。特别是如果您将其转换为数据框,您会得到数字。
    【解决方案3】:

    这是一个用于解决实际问题的新版本。仍然使用gregexpr,但这次使用索引。我必须稍微考虑一下零计数单元格(我无法进入表格?)

    foo <- data.frame(
        V1 = c("X","C","V"),
        V2 = c("N","T","H"),
        V3 = c("aaaaaabbbabab","ababaaabaaabb","babbbabaabbba"))
    
    n <- nchar(as.character(foo$V3)[1])
    tabA <- table(unlist(gregexpr("a",foo$V3)),exclude=-1)
    tabB <- table(unlist(gregexpr("b",foo$V3)),exclude=-1)
    
    res <- matrix(0,2,n)
    
    res[1,as.numeric(names(tabA))] <- tabA
    res[2,as.numeric(names(tabB))] <- tabB
    
    rownames(res) <- c("a","b")
    res
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13]
    a    2    2    2    1    2    3    1    1    2     2     1     1     1
    b    1    1    1    2    1    0    2    2    1     1     2     2     2
    

    如果没有 zerocount 单元格,您可以简单地执行 rbind(tabA,tabB)

    【讨论】:

    • 这不是 OP 想要的...他正在查看按列进行比较。
    • 我想你弄错了,我想按 V3 的子串的列来计算 a 和 b,而不是按行
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-20
    • 1970-01-01
    • 1970-01-01
    • 2021-09-28
    • 2014-04-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多