2013-09-23 4 views
2

Мне интересно, как лучше всего разбирать данные с длинными формами в широком формате в python. Раньше я делал такую ​​задачу в R, но на самом деле это происходит до тех пор, пока мои файлы могут превышать 1 ГБ. Вот некоторые фиктивные данные:Анализ данных от длинного до широкоформатного в Python

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

Я уверен, что python будет хорошим инструментом для работы, но вы пренебрегли объяснением того, что вам нужно делать. –

+0

Я подозреваю, что вы захотите посмотреть на [pandas] (http://pandas.pydata.org), но конкретный пример облегчит вам помощь. (Будет ли это быстрее или нет, это открытый вопрос.) – DSM

+1

Вы говорите о разборе фиксированной ширины csv? «длинная форма» и «широкая форма» не являются четко определенными условиями. Вы хотите преобразовать матрицу? – vish

ответ

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 

Если вы не можете загрузить файл в память, то раствор вне ядра в других ответы тоже будут работать.

0

Самый простой способ решить проблему, как это с помощью dict, или пару из них, или даже пару collections.Counter с:

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]) 

Проблема заключается в том, что это может быть слишком большим, чтобы вписывается в память.

Я бы обязательно попробовал и посмотрел сначала. Входной файл 1 ГБ не означает, что вам нужно 1 ГБ памяти. Помните, что вы только отслеживаете суммы для каждого отдельного гена, а не для каждой строки входного файла. В вашем примере это означает только два гена, из восьми значений.


Но если вы не можете поместить его в память, вам нужна база данных. Здесь вам просто нужна простая база данных с ключом, которая действует как 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 или другой внешний механизм базы данных.

Смежные вопросы