2013-09-14 4 views
2

Я занимаюсь исследованием биоинформатики, и я новичок в python. Я написал этот код для интерпретации файла, содержащего последовательности белка. Файл «bulk_sequences.txt» содержит 71 423 строки информации внутри себя. Три строки относятся к одной последовательности белка, эта первая строка дает информацию, включая год, в который был найден белок (вот что такое материал «/ 1945»). «С меньшим образцом из 1000 строк он работает отлично.Есть ли способ упростить этот код?

Он предназначен для сортировки файла, сортировки его по годам обнаружения, сортировки по нему, а затем назначить все три линии данных последовательности белка к элементу в массиве «sortedsqncs»

import time 
    start = time.time() 



    file = open("bulk_sequences.txt", "r") 
    fileread = file.read() 
    bulksqncs = fileread.split("\n") 
    year = 1933 
    newarray = [] 
    years = [] 
    thirties = ["/1933","/1934","/1935","/1936","/1937","/1938","/1939","/1940","/1941","/1942"]## years[0] 
    forties = ["/1943","/1944","/1945","/1946","/1947","/1948","/1949","/1950","/1951","/1952"]## years[1] 
    fifties = ["/1953","/1954","/1955","/1956","/1957","/1958","/1959","/1960","/1961","/1962"]## years[2] 
    sixties = ["/1963","/1964","/1965","/1966","/1967","/1968","/1969","/1970","/1971","/1972"]## years[3] 
    seventies = ["/1973","/1974","/1975","/1976","/1977","/1978","/1979","/1980","/1981","/1982"]## years[4] 
    eighties = ["/1983","/1984","/1985","/1986","/1987","/1988","/1989","/1990","/1991","/1992"]## years[5] 
    nineties = ["/1993","/1994","/1995","/1996","/1997","/1998","/1999","/2000","/2001","/2002"]## years[6] 
    twothsnds = ["/2003","/2004","/2005","/2006","/2007","/2008","/2009","/2010","/2011","/2012"]## years[7] 

    years = [thirties,forties,fifties,sixties,seventies,eighties,nineties,twothsnds] 
    count = 0 
    sortedsqncs = [] 


    for x in range(len(years)): 
     for i in range(len(years[x])): 
       for y in bulksqncs: 
         if years[x][i] in y: 
          for n in range(len(bulksqncs)): 
           if y in bulksqncs[n]: 
            sortedsqncs.append(bulksqncs[n:n+3]) 
            count +=1 
    print len(sortedsqncs) 

    end = time.time() 
    print round((end - start),4) 
+3

Это поможет, если вы предоставили несколько строк ввода и вывода. – Thomas

+0

Используйте встроенный профилировщик python (http://stackoverflow.com/questions/582336/how-can-you-profile-a-python-script), чтобы выяснить, каковы ваши узкие места. Существуют ли определенные функции, занимающие большую часть времени? Можете ли вы сделать их быстрее? Кроме того, посмотрите, как вы зацикливаетесь ... это разумный способ петли над данными? Это похоже на чрезвычайно сложный цикл, поэтому вы могли бы сделать это гораздо быстрее. – Kitsune

+0

Вы используете python 3 или 2? – smac89

ответ

4

проблема заключается в том, что вы зацикливание над гигантским файлом абсурдного количества раз. вы можете сделать это за один проход :

from itertools import izip_longest 

#http://docs.python.org/2/library/itertools.html 
def grouper(iterable, n, fillvalue=None): 
    "Collect data into fixed-length chunks or blocks" 
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx 
    args = [iter(iterable)] * n 
    return izip_longest(fillvalue=fillvalue, *args) 

# fold your list into a list of length 3 tuples 
data = [n for n in grouper(bulksqncs, 3)] 
# sort the list 
# tuples will 'do the right thing' by default if the line starts with the year 
data.sort() 

Если год линия не начинается с года, вам нужно будет использовать key kwarg для решения sort

data.sort(key=lamdba x: extract_year(x[0])) 
5

tcaswell с itertools.izip_longest() очень элегантный, но если вы не используют инструменты итерации более высокого уровня очень часто, вы можете забыть, как это работает, и код может стать трудно понять в будущем для вас.

Но принципиальное право tcaswell, что вы слишком много перебираете файл. Другая неэффективность, по крайней мере с точки зрения удобочитаемости и обслуживания, - это предопределенные массивы года. Также вы почти никогда не будете использовать range(len(seq)) - там почти всегда есть лучший (более пифонический) способ. Наконец, используйте readlines(), если вам нужен список строк из файла.

Более пешеход решение будет:

  1. Написать функцию extract_year(), как было предложено tcaswell вернуть год из строки ввода (bulksqncs), или None, если год не найдено. Вы можете использовать регулярное выражение, или если вы знаете положение года в строке, используйте это.

  2. Прокрутите ввод и извлеките все последовательности, назначив каждому кортеж (год, три строки последовательности) и добавив кортежи в список. Это также позволяет вводить файлы, которые не имеют последовательности, чередующиеся с последовательностями.

  3. Отсортировать список кортежей по годам.

  4. Извлечь последовательности из отсортированного списка кортежей.

Пример кода - это даст вам список Python отсортированных последовательностей:

bulksqncs = infile.readlines() 
sq_tuple = [] 
for idx, line in enumerate(bulksqncs): 
    if extract_year(line): 
    sq_tuple.append((extract_year(line), bulksqncs[idx:idx+3])) 
sq_tuple.sort() 
sortedsqncs = ['\n'.join(item[1]) for item in sq_tuple] 
+0

Первый удар по поиску google-сайта «izip_longest» - это официальные документы, поэтому, даже если вы забудете, что нетрудно напомнить себе:), также отредактировал мой номер циклов. – tacaswell

+0

Ну, да, и я * делаю * как ваше решение много. Но есть два подхода для новичка (и OP явно не опытный ветеран Python) в такой ситуации a) найти соответствующую стандартную библиотечную функцию более высокого уровня; б) решить проблему шаг за шагом с помощью соответствующих базовых инструментов. Вы сделали a) очень хорошо. Я занялся б). Оба имеют ценность. – chryss

+0

Справедливо, но я думаю, что вы комментируете намного лучше, чем первый абзац вашего ответа. – tacaswell

3

Проблема заключается в том, что каждый раз, когда вы нашли год в строке, вы петлю через файл в другое время (for n in range(len(bulksqncs))), так что в итоге у вас есть что-то вроде 136 миллиардов (= 71423 * (71423/3) * 80) итераций. Вы можете уменьшить это до менее 6 миллионов (71423 * 80), что по-прежнему займет немного времени, но должно быть управляемым.

Простое исправление для вашего основного цикла будет использовать enumerate, чтобы получить номер строки, вместо того, чтобы перебрать весь файл с начала снова:

for decade in decades: 
    for year in decade: 
     for n, line in enumerate(bulksqncs): 
      if year in line: 
       sortedsqncs.append(bulksqncs[n:n + 3]) 
       count += 1 

Однако время может быть уменьшено путем ставя цикл цикла внутри цикла, который считывает строки из файла. Я бы подумал об использовании словаря и прочтении одной строки за раз из файла (вместо того, чтобы сразу прочитать все это с помощью read()). Когда вы найдете год в строке, вы можете использовать next, чтобы захватить следующие две строки, а также тот, в котором вы сейчас находитесь. Затем программа break s из цикла циклов, избегая ненужных итераций (при условии, что в одной строке не может быть более одного года).

years = ['/' + str(y) for y in range(1933, 2013)] 
sequences = dict((year, []) for year in years) 

with open("bulk_sequences.txt", "r") as bulk_sequences: 
    for line in bulk_sequences: 
     for year in years: 
      if year in line: 
       sequences[year].append((line, 
             bulk_sequences.next(), 
             bulk_sequences.next())) 
       break 

отсортированного списка, то можно получить как

[sequences[year] for year in years] 

В качестве альтернативы использовать OrderedDict, чтобы держать последовательности в порядке.

+0

Я был обеспокоен тем, что у меня был счетчик пропусков .... – tacaswell

+0

Приятная вещь в том, что вы можете делать другие интересные вещи со словарем теперь, когда вы это сделали. – tacaswell

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