2

我想知道将长格式数据解析为宽格式的最佳方法是在 python 中。我以前一直在 R 中执行此类任务,但它确实需要很长时间,因为我的文件可以超过 1 GB。这是一些虚拟数据:

Sequence Position Strand Score
Gene1    0        +      1
Gene1    1        +      0.25
Gene1    0        -      1
Gene1    1        -      0.5
Gene2    0        +      0
Gene2    1        +      0.1
Gene2    0        -      0
Gene2    1        -      0.5

但我希望它采用宽格式,我将每个位置的分数相加。这是我希望的输出:

Sequence 0 1
Gene1    2 0.75
Gene2    0 0.6

关于如何从概念上解决此类问题的任何帮助都会非常有帮助。

4

2 回答 2

7

当您可以在单行中使用 pandas 时,这两种解决方案似乎都过大了:

In [7]: df
Out[7]: 
  Sequence  Position Strand  Score
0    Gene1         0      +   1.00
1    Gene1         1      +   0.25
2    Gene1         0      -   1.00
3    Gene1         1      -   0.50
4    Gene2         0      +   0.00
5    Gene2         1      +   0.10
6    Gene2         0      -   0.00
7    Gene2         1      -   0.50

In [8]: df.groupby(['Sequence', 'Position']).Score.sum().unstack('Position')
Out[8]: 
Position  0     1
Sequence         
Gene1     2  0.75
Gene2     0  0.60

如果您无法将文件加载到内存中,那么其他答案中的核外解决方案也将起作用。

于 2013-10-11T22:31:25.447 回答
0

解决此类问题的简单方法是使用 adict或一对,甚至一对collections.Counters:

positions, scores = Counter(), Counter()
for sequence, position, strand, score in reader:
    positions[sequence] += position
    scores[sequence] += scores

for sequence in positions:
    writer.writerow(sequence, positions[sequence], scores[sequence])

问题是这可能太大而无法放入内存。

我当然会先试试看。1GB 的输入文件并不意味着您需要 1GB 的内存。请记住,您只跟踪每个不同基因的总和,而不是输入文件中每一行的总和。在您的示例中,这意味着八个值中只有两个基因。


但是如果你不能把它放在内存中,你需要一个数据库。在这里,您真的只需要一个简单的键值数据库,它的作用类似于dict,而不是花哨的东西。Python 内置了它,如dbm.

例如(写得过于冗长以确保它易于理解):

import csv
import shelve

with dbm.open('p.db', 'w') as positions, dbm.open('s.db', 'w') as scores:
    with open('input.tsv') as infile:
        for row in csv.DictReader(infile, delimiter='\t'):
            sequence = row['Sequence']
            position = row['Position']
            score = row['Score']
            old_position = positions.get(sequence, '0')
            positions[sequence] = str(int(old_position) + int(position))
            old_score = scores.get(sequence, '0')
            scores[sequence] = str(int(old_score) + int(score))
   with open('output.tsv', 'w') as outfile:
       writer = csv.writer(outfile, delimiter='\t')
       for sequence in positions:
           writer.writerow((sequence, positions[sequence], scores[sequence]))

如果您需要做一些更复杂的事情,而简单的键值数据库将无法工作,那么您可能需要用 SQL 重写您的逻辑并使用该sqlite3模块为您执行它。

如果你的数据库太大以至于 SQLite 无法处理,你可以看看 MySQL 或其他外部数据库引擎。

于 2013-09-23T22:08:59.540 回答