2016-03-05 2 views
0

У меня около 650 csv-матриц. Я планирую на загрузку каждого из них с помощью Numpy, как в следующем примере:Множественные матричные умножения с Numpy

m1 = numpy.loadtext(open("matrix1.txt", "rb"), delimiter=",", skiprows=1) 

Есть matrix2.txt, matrix3.txt, ..., matrix650.txt файлы, которые мне нужно обработать.

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

Вот пример того, что я имею в виду с матрицами, определенными от 1 до n: M1, M2, M3, .., Mn.

M1 * M2 * M3 * ... * Mn

Размеры на всех матриц одинаковы. Матрицы не квадратные. Есть 197 строк и 11 столбцов. Ни одна из матриц не разрешена, и каждая ячейка вступает в игру.

Что является лучшим/наиболее эффективным способом сделать это в python?

EDIT: Я взял то, что было предложено, и получил его для работы, взяв транспонирование, поскольку он не является квадратной матрицей. В качестве дополнения к вопросу, i Есть ли способ в Numpy для умножения элементов на элементы?

+0

Есть ли определенный этап процесса, на котором вы застряли? –

+0

Каков размер матриц? дорогостоящая задача считывается, поэтому загружайте максимум их в каждый момент времени. –

+0

Часто есть разница между лучшими (элегантными) и эффективными. Вы можете читать их в нескольких потоках, если cpu не имеет значения, или только 2 матрицы одновременно, если память имеет значение, если имеет значение время. Насколько они большие? Имеет ли значение память? – Kordi

ответ

2
раствор

python3, если «каждая матрица друг на друга» на самом деле означает просто умножив их в ряд и матриц имеют совместимые размеры ((п, т) · (м, о) · (о, р) · ...), что вы намекаете на с "(1 продолжающуюся и 1, что ...)", а затем использовать (если таковые имеются):

from functools import partial 
fnames = map("matrix{}.txt".format, range(1, 651)) 
np.linalg.multi_dot(map(partial(np.loadtxt, delimiter=',', skiprows=1), fnames)) 

или:

from functools import reduce, partial 
fnames = map("matrix{}.txt".format, range(1, 651)) 
matrices = map(partial(np.loadtxt, delimiter=',', skiprows=1), fnames) 
res = reduce(np.dot, matrices) 

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

Делая все комбинации лениво, учитывая, что матрицы имеют одинаковую форму (будет делать много перечитывание данных):

from functools import partial 
from itertools import starmap, combinations 
map_loadtxt = partial(map, partial(np.loadtxt, delimiter=',', skiprows=1)) 
fname_combs = combinations(map("matrix{}.txt".format, range(1, 651)), 2) 
res = list(starmap(np.dot, map(map_loadtxt, fname_combs))) 

Использование немного группирования для уменьшения перегрузки файлов:

from itertools import groupby, combinations, chain 
from functools import partial 
from operator import itemgetter 

loader = partial(np.loadtxt, delimiter=',', skiprows=1) 
fname_pairs = combinations(map("matrix{}.txt".format, range(1, 651)), 2) 
groups = groupby(fname_pairs, itemgetter(0)) 
res = list(chain.from_iterable(
    map(loader(k).dot, map(loader, map(itemgetter(1), g))) 
    for k, g in groups 
)) 

Поскольку матрицы не квадратные, но имеют одинаковые размеры, вам нужно будет добавить транспорты перед умножением в соответствии с размерами. Например, loader(k).T.dot или map(np.transpose, map(loader, ...)).

Если, с другой стороны, вопрос фактически предназначался для решения проблемы умножения элементов, замените np.dot на np.multiply.

+0

Он не хочет, чтобы все играли по очереди. Посмотрите на вопрос: «умножайте каждую матрицу друг на друга», означает (1,2), (1,3) и т. Д. – Kordi

+0

Я получаю сообщение об ошибке: у объекта «module» нет атрибута «multi_dot» после строки np.linalg.multi_dot. Я пробую ваше первое решение. Любая идея, как исправить эту ошибку? – jonnyd42

+0

Вот почему я добавил «если доступно» :). Он добавлен в версию 1.11.0, которая все еще находится в разработке, я думаю. –

1

1. Вариант: Хороший код, но читает все матрицы сразу

matrixFileCount = 3 
matrices = [np.loadtxt(open("matrix%s.txt" % i), delimiter=",", skiprows=1) for i in range(1,matrixFileCount+1)] 
allC = itertools.combinations([x for x in range(matrixFileCount)], 2) 
allCMultiply = [np.dot(matrices[c[0]], matrices[c[1]]) for c in allC] 
print allCMultiply 

2. Вариант: только нагрузка 2 Файлы сразу, хороший код, но много перегрузочных

allCMulitply = [] 
fileList = ["matrix%s.txt" % x for x in range(1,matrixFileCount+1)] 
allC = itertools.combinations(fileList, 2) 
for c in allC: 
    m = [np.loadtxt(open(file), delimiter=",", skiprows=1) for file in c] 
    allCMulitply.append(np.dot(m[0], m[1])) 
print allCMulitply 

3. Вариант: как второй, но избегайте загрузки каждый раз. Но только 2 матрицы в одной точке памяти

Причина, по которой перестановки, созданные с помощью itertools, равны (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4), вы можете избежать загрузки обеих двух матриц.

matrixFileCount = 3 
allCMulitply = [] 
mLoaded = {'file' : None, 'matrix' : None} 
fileList = ["matrix%s.txt" % x for x in range(1,matrixFileCount+1)] 
allC = itertools.combinations(fileList, 2) 
for c in allC: 
    if c[0] is mLoaded['file']: 
     m = [mLoaded['matrix'], np.loadtxt(open(c[1]), delimiter=",", skiprows=1)] 
    else: 
     mLoaded = {'file' : None, 'matrix' : None} 
     m = [np.loadtxt(open(file), delimiter=",", skiprows=1) for file in c] 
    mLoaded = {'file' : c[0], 'matrix' : m[0]} 
    allCMulitply.append(np.dot(m[0], m[1])) 
print allCMulitply 

Performance

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

0.943613052368 (Part 1: 10 Matrices a 2,2 with 1000 executions) 
7.75622487068 (Part 2: 10 Matrices a 2,2 with 1000 executions) 
4.83783197403 (Part 3: 10 Matrices a 2,2 with 1000 executions) 
+0

@ B.M. Большое спасибо за уведомление, изменившее мой код. Надеюсь, сейчас уберите ваш downvoting ;-). Спасибо – Kordi

0

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

import numpy as np 

def get_dot_product(fnames): 
    assert len(fnames) > 0 
    accum_val = np.loadtxt(fnames[0], delimiter=',', skiprows=1) 
    return reduce(_product_from_file, fnames[1:], initializer=accum_val) 

def _product_from_file(running_product, fname): 
    return running_product.dot(np.loadtxt(fname, delimiter=',', skiprows=1)) 

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

0

Как насчет действительно простого решения, избегая map, reduce и т.п.? Объект массива по умолчанию numpy по умолчанию выполняет поэтапное умножение.

size = (197, 11) 

result = numpy.ones(size) 
for i in range(1, 651): 
    result *= numpy.loadtext(open("matrix{}.txt".format(i), "rb"), 
          delimiter=",", skiprows=1)