在Python中将数据从长格式解析为宽格式

时间:2013-09-23 21:14:58

标签: python parsing pandas reshape

我想知道在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

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

2 个答案:

答案 0 :(得分:7)

这两种解决方案似乎都有点矫枉过正,你可以用一个单行的大熊猫来做这件事:

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

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

答案 1 :(得分:0)

解决此类问题的简便方法是使用dict或其中一对,或甚至一对collections.Counter s:

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中重写你的逻辑并使用{​​{3}}模块为你执行它

如果您的数据库太大而SQLite无法处理它,您可以查看MySQL或其他外部数据库引擎。