【问题标题】:Perl (or R, or SQL): Count how often string appears across columnsPerl(或 R,或 SQL):计算字符串在列中出现的频率
【发布时间】:2011-08-04 02:19:22
【问题描述】:

我有一个如下所示的文本文件:

gene1   gene2   gene3
a       d       c
b       e       d
c       f       g
d       g       
        h
        i

(每列是一个人类基因,每列包含可变数量的蛋白质(字符串,此处显示为字母),可以与这些基因结合)。

我要做的是计算每个字符串代表多少列,输出该数字和所有列标题,如下所示:

a   1   gene1
b   1   gene1
c   2   gene1 gene3
d   3   gene1 gene2 gene3
e   1   gene2
f   1   gene2
g   2   gene2 gene3
h   1   gene2
i   1   gene2

我一直试图弄清楚如何在 Perl 和 R 中做到这一点,但到目前为止还没有成功。感谢您的帮助。

【问题讨论】:

  • 列是制表符分隔的,还是空格格式的?这将决定如何对待他们。

标签: mysql string perl r


【解决方案1】:

这个解决方案看起来有点小技巧,但它提供了所需的输出。它依赖于使用plyrreshape 包,但我相信你可以找到基本的R 替代品。诀窍在于melt 函数让我们将数据扁平化为长格式,这使得从那时起可以轻松(ish)进行操作。

library(reshape)
library(plyr)

#Recreate your data
dat <- data.frame(gene1 = c(letters[1:4], NA, NA),
                  gene2 = letters[4:9],
                  gene3 = c("c", "d", "g", NA, NA, NA)
                  )

#Melt the data. You'll need to update this if you have more columns
dat.m <- melt(dat, measure.vars = 1:3)

#Tabulate counts
counts <- as.data.frame(table(dat.m$value))

#I'm not sure what to call this column since it's a smooshing of column names
otherColumn <- ddply(dat.m, "value", function(x) paste(x$variable, collapse = " "))

#Merge the two together. You could fix the column names above, or just deal with it here
merge(counts, otherColumn, by.x = "Var1", by.y = "value")

给予:

> merge(counts, otherColumn, by.x = "Var1", by.y = "value")
  Var1 Freq                V1
1    a    1             gene1
2    b    1             gene1
3    c    2       gene1 gene3
4    d    3 gene1 gene2 gene3
....

【讨论】:

  • 谢谢,一直喜欢 R 解决方案,尤其是使用 **ply 函数。
  • 您可以使用ddply(dat.m, .(value), summarize, Freq = length(variable), V1 = paste(variable, collapse = " ")) 简化为单个ddply 调用
【解决方案2】:

在 perl 中,假设每列中的蛋白质没有需要删除的重复项。 (如果这样做,则应使用散列的散列。)

use strict;
use warnings;

my $header = <>;
my %column_genes;
while ($header =~ /(\S+)/g) {
    $column_genes{$-[1]} = "$1";
}

my %proteins;
while (my $line = <>) {
    while ($line =~ /(\S+)/g) {
        if (exists $column_genes{$-[1]}) {
            push @{ $proteins{$1} }, $column_genes{$-[1]};
        }
        else {
            warn "line $. column $-[1] unexpected protein $1 ignored\n";
        }
    }
}

for my $protein (sort keys %proteins) {
    print join("\t",
        $protein,
        scalar @{ $proteins{$protein} },
        join(' ', sort @{ $proteins{$protein} } )
    ), "\n";
}

从标准输入读取,写入标准输出。

【讨论】:

  • 我不熟悉 $hash{$-[1]} 语法。这是干什么的?
  • @- 是一个特殊数组,用于报告正则表达式捕获开始的位置($-[1] 表示 $1 开始的位置,$_[2] 表示 $2 等)
  • 特殊变量@- 包含“范围内成功子匹配的开始偏移量”。见perlmonks.org/?node_id=353259
  • 哎呀,写了%-我的意思是@-;修改了评论(并用 _ 代替了一个 - 太晚了,无法编辑它:()
【解决方案3】:

单排(或者更确切地说是 3 排)

ddply(na.omit(melt(dat, m = 1:3)), .(value), summarize, 
     len = length(variable), 
     var = paste(variable, collapse = " "))

【讨论】:

    【解决方案4】:

    如果不是很多列,你可以在sql中做这样的事情。您基本上将数据展平为 2 列派生的蛋白质/基因表,然后根据需要对其进行汇总。

    ;with cte as (
      select gene1 as protein, 'gene1' as gene
      union select gene2 as protein, 'gene2' as gene
      union select gene3 as protein, 'gene3' as gene
    )
    
    select protein, count(*) as cnt, group_concat(gene) as gene
    from cte
    group by protein
    

    【讨论】:

    • 错误,但最难的部分是整理数据
    • 谢谢。我曾想过在 MySQL 中这样做,但我有很多专栏。如果需要,我会试试这个,也许写一些 perl 代码来编写我的查询,呃。
    【解决方案5】:

    在mysql中,像这样:

    select protein, count(*), group_concat(gene order by gene separator ' ') from gene_protein group by protein;
    

    假设数据如下:

    create table gene_protein (gene varchar(255) not null, protein varchar(255) not null);
    insert into gene_protein values ('gene1','a'),('gene1','b'),('gene1','c'),('gene1','d');
    insert into gene_protein values ('gene2','d'),('gene2','e'),('gene2','f'),('gene2','g'),('gene2','h'),('gene2','i');
    insert into gene_protein values ('gene3','c'),('gene3','d'),('gene3','g');
    

    【讨论】:

      猜你喜欢
      • 2013-10-14
      • 2016-12-30
      • 1970-01-01
      • 1970-01-01
      • 2016-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多