在文件中构建 table 个独特的行,以及每个独特行被观察到的次数

Build a table of unique lines in a file and the number of times each unique line was observed

我有一个 DNA 序列文件 file.txt,其中每一行都是一个 DNA 序列。前 5 行如下所示:

GACAGAGGGTGCAAACGTTGTTCGGAATTACTGGGCGTAAAGCGCGTGTAGGCGGCCATGCAAGTCGGATGTGAAAGCCCTCGGCTCAACCGGGGAAGTGCACTCGAAACTGCAAGGCTAGAGTCTCGGAGAGGATCGTGGAATTCTCGGTGTAGAGGTGAAATTCGTAGATATCGAGAGGAACACCGGTGGCGAAGGCGGCGATCTGGACGATGACTGACGCTGAGACGCGAAAGCGTGGGGAGCAAACAGG
TACGTAGGGTGCGAGCGTTAATCGGAATTACTGGGCGTAAAGCGTGCGCAGGCGGTCTCGTAAGCTGGGTGTGAAAGCCCCGGGCTTAACCTGGGAATGGCATTCAGGACTGCGAGGCTCGAGTGTGGCAGAGGGAGGTGGAATTCCACGTGTAGCAGTGAAATGCGTAGAGATGTGGAGGAACACCGATGGCGAAGGCAGCCTCCTGGGCCAGCACTGACGCTCATGCACGAAAGCGTGGGGAGCAAACAGG
GACGTGTGAGGCAAGCGTTATTCGTCATTAATGGGTTTAAAGGGTACGTAGGCGGAATACTTTATTATGTTTAAGAAGACACTTAAAAGTGAACATGATAATAAAATTCTAGAGTTTGAAAGGAGTAAACAATTACCTCGAGAGTAAGGGACAACTAATACGGAAATACTTGGGGGGATTCTAAGCGGCGAAAGCATGTTACTATTGAAAACTGACGCTGAGGTACGAAGGCTTGGGTATCGACTGGG
TACGAAGGGTGCAAACGTTGCTCGGAATTATTGGGCGTAAAGCGCATGTAGGCGGCTTAGCAAGTCGGATGTGAAATCCCTCGGCTCAACCAAGGAAGTGCATCCGAAACTGCTGAGCTTGAGTACGAAAGAGGATCGCGGAATTCCCGGTGTAGAGGTGAAATTCGTAGATATCGGGAGGAACACCAGTGGCGAAGGCGGCGATCTGGGTCGATACTGACGCTGAGGTGCGAAAGCGTGGGGAGCAAACAGG
AACGTAGGAGACAAACGTTATCCGGAGTTACTGGGCGTAAAGGGCGTGTAGGTGGTTGCGTAAGTCTGGCGTGAAATTTTTCGGCTTAACCGGGAAAGGTCGTCGGATACTGCGTAGCTAGAGGACGGTAGAGGCGTGTGGAATTCCGGGGGTAGTGGTGAAATGCGTAGAGATCCGGAGGAACACCAGTGGCGAAGGCGACACGCTGGGCCGTACCTGACACTGATGCGCGACAGCATGGGGAGCAAACACT

实际文件有几万行。我想识别此文件中的所有唯一序列(或唯一行)以及每个序列(或行)在文件中被观察到的次数。理想情况下,这将作为矩阵返回,在 R 中有一列,其中条目是序列丰度,行名是唯一序列。

或者,这可以写入 .csv 文件,其中第一行是唯一序列(行)的逗号分隔字符串,第二行是每个序列(行)的逗号分隔字符串序列出现在文件中。

其次,此文件较大 (~5 MB),但类似的文件很多。在下游,我将不得不将许多这些向量合并在一起。如何在最小化内存使用量的同时生成此向量?

编辑

我不知道 Unix 答案是允许的。因此,以下是 sort | uniq 答案的两个备选方案。考虑到您的文件位于同一文件夹中,名为 myFile_1.txt myFile_2.txt myFile_n.txt

我测试中最好的 700k 行 160Mb:

perl -ne '$count{$_}++; END { print "$count{$_} $_" for sort {$count{$b} <=> $count{$a} || $b cmp $a} keys %count}' myFile*.txt > output.txt

可以找到更详细的解释here

还有一个不同的替代方案,因为它不必实际对文件进行排序(但如果您有太多不同的键,它将使用更多内存)。

cat myFile*.txt | awk '{ cnts[[=11=]] += 1 } END { for (v in cnts) print cnts[v], v }' > output.txt

可以找到更详细的解释here

前一个R答案

您可以将数据放入这样的向量结构中:

data <- c("GACAGAG", "TACGTAGG", "AACGTAGG", "GACGTGTG", "TACGAAGG", "AACGTAGG")
ans <- table(data)
ans["AACGTAGG"]

5MB 适合您的内存,所以我想它会起作用。但是,如果您有一些数据不适合内存,您将不得不逐行处理文件或使用诸如 SparkR 之类的解决方案。

希望对您有所帮助:)

您应该使用 HashMap,您的序列是键,值是计算出现次数的 Integer。

java 伪代码中的算法如下,读取行直到 EOF

Map<String, Integer> map = new Map...
String line;
Integer appearances;

while(not EOF)
    line = read line however suits your problem
    appearances = map.get(line)
    if(appearances == null)
        map.put(line, 1)
    else
        map.put(line, appearances+1)

然后您可以通过查询映射键集并执行获取或仅使用入口集来访问您拥有的所有行及其值

关于效率,您可能无法获得比以这种方式使用字典更有效的方法。

您使用的是 Unix 系统吗? (此答案不适用于开箱即用的 Windows)

我创建了一个名为testtext.txt的文件,内容如下:

c
a
b
a
b
b
b
c

然后在终端中执行以下命令

sort testtext.txt | uniq -c > testcounts.txt

生成一个文件,testcounts.txt内容如下。

2 a
4 b
2 c

我不能说这相对于其他解决方案的表现如何,但似乎值得一试。

您也可以在当前目录中匹配模式的所有文件同时执行此操作 - 我制作了三个 - testtext.txttesttext2.txttesttext3.txt

find . -type f -name 'testtext*' | xargs sort | uniq -c > Counts.txt

然后创建文件 Counts.txt

10 a
 6 b
 5 c
 3 d
 1 e
 1 f

或者(特别是当内存使用受到关注时)您可以将单个文件示例放在一个简单的 bash 循环脚本中,以一次处理一个文件。 无论哪种方式,Unix 命令行工具在优雅使用时都是 shockingly efficient

来源:Unix.StackExchange: Sort and Count Number of Occurence of Lines

仅使用 R 基本命令比较 500000 行数据的结果:

这是我们的测试文件,500K 行,122MB。

wc -l myFile.txt
# 500000 myFile.txt

ls -lh myFile.txt
# xxx xxx xxx xxx 122M May 10 09:05 myFile.txt

使用sort | uniq

time sort myFile.txt | uniq -c > myFileCounts1.txt

# real    0m7.317s
# user    0m12.998s
# sys     0m0.228s

使用 R,tablefrom related post):

system.time(write.table(table(readLines("myFile.txt")), "myFileCounts2.txt",
                        col.names = FALSE, row.names = FALSE , quote = FALSE))

#  user  system elapsed
# 3.028   0.100   3.142