2016-06-03 4 views
2

У меня есть две матрицы, которые мне нужно использовать, чтобы создать большую матрицу. Каждая матрица представляет собой просто текстовый файл с разделителями табуляции, который читается. Каждая матрица имеет 48 столбцов с одинаковыми идентификаторами на матрицу с разным количеством строк. Первая матрица - 108887x48, вторая - 55482x48. Записи в каждой позиции для каждой матрицы могут быть 0 или 1, поэтому двоичные. Конечный результат должен содержать первые идентификаторы строк матрицы в виде строк, а вторая строка матрицы - как столбцы, поэтому итоговая матрица равна 55482x10887.Сравните две матрицы разных размеров, чтобы сделать одну большую матрицу - Улучшения скорости?

Что должно произойти здесь, так это то, что для каждого pos в каждой строке в первой матрице для каждой строки во второй матрице, если pos (col) для каждой матрицы равно 1, тогда счетчик окончательной матрицы будет расти 1. Наибольшим значением любой pos в финальной матрице может быть 48, и ожидается, что осталось 0.

Пример:

mat1 
    A B C D 
1id1 0 1 0 1 
1id2 1 1 0 0 
1id3 1 1 1 1 
1id4 0 0 1 0 

mat2 
    A B C D 
2id1 1 1 0 0 
2id2 0 1 1 0 
2id3 1 1 1 1 
2id4 1 0 1 0 

final 
    2id1 2id2 2id3 2id4 
1id1 1 1 2 0 
1id2 2 1 2 1 
1id3 2 2 4 2 
1id4 0 1 1 1 

У меня есть код, чтобы сделать это, однако это крайне медленно, что, где я в основном с просьбой о помощи. Я попытался максимально ускорить алгоритм. Он работает 24 часа и составляет всего около 25% пути. Я разрешил ему работать до и окончательный выходной файл составляет 20 ГБ. Я не имею опыта с базами данных и могу реализовать его здесь, если osomeone может помочь мне в том, как это сделать, с учетом фрагмента кода ниже.

#!/usr/bin/env python 

import sys 

mat1in = sys.argv[1] 
mat2in = sys.argv[2] 

print '\n######################################################################################' 
print 'Generating matrix by counts from smaller matrices.' 
print '########################################################################################\n' 

with open(mat1in, 'r') as f: 
     cols = [''] + next(f).strip().split('\t')    # First line of matrix is composed of 48 cols 
     mat1 = [line.strip().split('\t') for line in f]   # Each line in matrix = 'ID': 0 or 1 per col id 

with open(mat2in, 'r') as f: 
     next(f)             # Skip first row, col IDs are taken from mat1 
     mat2 = [line.strip().split('\t') for line in f]   # Each line in matrix = 'ID': 0 or 1 per col id 

out = open('final_matrix.txt', 'w')        # Output file 

#matrix = [] 
header = []              # Final matrix header 
header.append('')            # Add blank as first char in large matrix header 
for i in mat2: 
     header.append(i[0])          # Composed of all mat2 row ids 
#matrix.append(header) 

print >> out, '\t'.join(header)         # First print header to output file 

print '\nTotal mat1 rows: ' + str(len(mat1))     # Get total mat1 rows 
print 'Total mat2 rows: ' + str(len(mat2)), '\n'    # Get total mat2 rows 
print 'Progress: '            # Progress updated as each mat1 id is read 

length = len(header)           # Length of header, i.e. total number of mat2 ids 
totmat1 = len(mat1)            # Length of rows (-header), i.e. total number of mat1 ids 

total = 0              # Running total - for progress meter 
for h in mat1:             # Loop through all mat1 ids - each row in the HC matrix 
     row = []            # Empty list for new row for large matrix 
     row.append(h[0])          # Append mat1 id, as first item in each row 
     for i in xrange(length-1):        # For length of large matrix header (add 0 to each row) - header -1 for first '\t' 
       row.extend('0') 
     for n in xrange(1,49):         # Loop through each col id 
       for k in mat2:         # For every row in mat2 
         if int(h[n]) == 1 and int(k[n]) == 1: # If the pos (count for that particular col id) is 1 from mat1 and mat2 matrix; 
           pos = header.index(k[0])  # Get the position of the mat2 id 
           row[pos] = str(int(row[pos]) + 1)  # Add 1 to current position in row - [i][j] = [mat1_id][mat2_id] 
     print >> out, '\t'.join(row)       # When row is completed (All columns are compared from both mat1 and mat2 matrices; print final row to large matrix 
     total += 1            # Update running total 
     sys.stdout.write('\r\t' + str(total) + '/' + str(tvh)) # Print progress to screen 
     sys.stdout.flush() 

print '\n######################################################################################' 
print 'Matrix complete.' 
print '########################################################################################\n' 

Вот что профилирование первых 30 итераций для ид в MAT1:

###################################################################################### 
Generating matrix by counts from smaller matrices. 
######################################################################################## 


Total mat1 rows: 108887 
Total mat2 rows: 55482 

Progress: 
     30/108887^C   2140074 function calls in 101.234 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 70.176 70.176 101.234 101.234 build_matrix.py:3(<module>) 
     4 0.000 0.000 0.000 0.000 {len} 
    55514 0.006 0.000 0.006 0.000 {method 'append' of 'list' objects} 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
    1719942 1.056 0.000 1.056 0.000 {method 'extend' of 'list' objects} 
     30 0.000 0.000 0.000 0.000 {method 'flush' of 'file' objects} 
    35776 29.332 0.001 29.332 0.001 {method 'index' of 'list' objects} 
     31 0.037 0.001 0.037 0.001 {method 'join' of 'str' objects} 
    164370 0.589 0.000 0.589 0.000 {method 'split' of 'str' objects} 
    164370 0.033 0.000 0.033 0.000 {method 'strip' of 'str' objects} 
     30 0.000 0.000 0.000 0.000 {method 'write' of 'file' objects} 
     2 0.000 0.000 0.000 0.000 {next} 
     3 0.004 0.001 0.004 0.001 {open} 

Я также приуроченный каждую итерацию, которая занимает около 2.5-3s на MAT1 идентификатору, и если я правильное заняло бы около 90 часов, чтобы завершить все это. Это о том, что нужно для полного запуска всего скрипта.

Я отредактировал некоторые из основных бит, чтобы удалить строки, добавив и xrange, чтобы сделать список за один шаг, умножив '0' на длину заголовков. Кроме того, я сделал словарь в MAT2 идентификаторах с индексом в качестве значений, думая Dict поиска будет быстрее, чем индекс ..

headdict = {} 
for k,v in enumerate(header): 
     headdict[v] = k 

total = 0              # Running total - for progress meter 
for h in mat1:             # Loop through all mat1 ids - each row in the HC matrix 
     timestart = time.clock() 
     row = [h[0]] + ['0']*(length-1)     # Empty list for new row for large matrix 
     #row.append(h[0])          # Append mat1 id, as first item in each row 
     #for i in xrange(length-1):        # For length of large matrix header (add 0 to each row) - header -1 for first '\t' 
     #  row.append('0') 
     for n in xrange(1,49):         # Loop through each col id 
       for k in mat2:         # For every row in mat2 
         if int(h[n]) == 1 and int(k[n]) == 1: # If the pos (count for that particular col id) is 1 from mat1 and mat2 matrix; 
           pos = headdict[k[0]] #header.index(k[0])  # Get the position of the mat2 id 
           row[pos] = str(int(row[pos]) + 1)  # Add 1 to current position in row - [i][j] = [mat1_id][mat2_id] 
     print >> out, '\t'.join(row)       # When row is completed (All columns are compared from both mat1 and mat2 matrices; print final row to large matrix 
     total += 1            # Update running total 
     sys.stdout.write('\r\t' + str(total) + '/' + str(totmat1)) # Print progress to screen 
     #sys.stdout.flush() 
     timeend = time.clock() 
     print timestart - timeend 
+3

Хотя я вижу некоторые недостатки в вашем коде, ничего особенного не выделяется. Единственный способ эффективно оптимизировать его - сначала профилировать его, но никто не может этого сделать. К счастью, это довольно простая задача - см. [_Как вы можете профилировать скрипт Python? _] (Http://stackoverflow.com/questions/582336/how-can-you-profile-a-python-script). Результаты будут расскажите, какие части работают, чтобы получить максимальную скорость. – martineau

+1

Ваши объяснения очень неясны. Что означает «если значение pos (col) для каждой матрицы равно 1»? Когда вы говорите «тогда конечный счетчик матрицы будет расти до 1», на какой счет вы ссылаетесь? Где будет храниться этот счет? Это звучит неопределенно, как будто вы просто хотите, чтобы матрица умножала первую матрицу на транспонирование второй, но это невозможно точно сказать. – user2357112

+0

@ user2357112- Я добавил небольшой пример того, чего я надеюсь выполнить (быстро). Значение pos по col для каждой матрицы основано на id (n в xrange (1,49)). Строки на каждый мат1 id изначально заполняются 0. Если 1 существует в mat2 для одного и того же col-id, счетчик увеличивается до 1 путем итерации через все идентификаторы mat2 (заголовок в новой матрице). Значения сохраняются в строке, заданной mat1 id, и после того, как этот идентификатор завершен, он записывается в outfile. Я сравниваю все строки mat1 по id с каждым символом mat2 с помощью заголовка col для каждой итерации. –

ответ

2

Это всего лишь матричное умножение. Вы хотите умножить первую матрицу на транспонирование второй. Для эффективных операций с матрицами получите NumPy.

Если вы читаете ваши два входных матриц в NumPy массивы DTYPE numpy.int8, то вычисление просто

m1.dot(m2.T) 

Это займет пару минут, топы.

0

Я не совсем понимаю, что делает этот код (единственная буква имен переменных Безразлично 't помочь).

Мое предложение: попробуйте уменьшить количество операций, выполняемых в самых внутренних циклах. Например, вам нужно пересчитать pos на внутреннем уровне?

pos = header.index(k[0]) 

Если это возможно, чтобы изменить порядок вложенных циклов k, h и n, вы можете быть в состоянии сократить дорогостоящие list.index, который является O (п) операции.

+0

см. Последнее изменение для изменения индекса индекса для поиска в dict. Мне нужен индекс k [0], чтобы получить позицию в заголовке, чтобы узнать, какое значение обновить в строке большой матрицы, учитывая mat1 id (h). Мне нужно перебрать все mat2 ids (k) для каждого mat1 id (h), перейдя col на col в mat1 и mat2, чтобы найти, где значения одинаковы. Если они тогда [mat1] [mat2], позиции в комбинированной матрице будут увеличиваться на 1. –