2014-11-17 2 views
4

Я думаю, что у меня большой сценарий данных (N = 1e6 и размер = 3). Мне нужно несколько раз манипулировать матрицей, например einsum, инвертирование матрицы и т. Д. В моем коде. Чтобы дать идею, я хочу сделать что-то вроде ниже.Массирование матрицы больших данных Python

import numpy.random as rd 

ndata, kdata = 1e6, 1e5 

x = rd.normal(0,1,(ndata, kdata,3,3)) 

y = rd.normal(0,1,(ndata, kdata,3,3)) 

Для малых NDATA, kdata следующее было бы эффективным и удобным подход,

xy = einsum('pqrs, pqsu -> pqru', x, y) 

Поскольку у меня есть большой NDATA и kdata выше подхода становится связанной проблемой памяти так, следующая ставка будет скалярное произведение с вложенный для цикла по NDATA и kdata следующим образом:

xyloop1 = np.empty((ndata, kdata, 3, 3)) 

for j in xrange(ndata): 

    for k in xrange(kdata): 

     xyloop1[j,k] = np.dot(x[j,k], y[j,k]) 

Учитывая то, что я преподавала петлю противные в питоне. Кроме того, я хочу использовать преимущество Numpy так думал блок матричного подхода был бы предпочтительнее что-то вроде следующие:

nstep = 200 
ndiv = ndata/nstep 

kstep = 200 
kdiv = kdata/kstep 

xyloop2 = np.empty((ndata, kdata, 3, 3)) 

for j in xrange(ndiv): 

    ji, jf = j*nstep, (j+1)*nstep  

    for k in xrange(kdiv): 

     ki, kf = k*kstep, (k+1)*kstep  

     xyloop2[ji:jf,ki:kf] = einsum('pqrs, pqsu -> pqru', x[ji:jf,ki:kf], y[ji:jf,ki:kf]) 

Кроме того, мне нужен этот х или xyloop1 или xyloop2 для моего дальнейшего расчета. Поэтому я должен писать и читать его после каждого вычисления. Учитывая пропускную способность системного ввода-вывода, вы считаете, что наилучшим подходом будет подход 3, поскольку это означает меньше ввода-вывода, а также небольшое количество итераций по сравнению с подходом 2? Если у вас есть какая-либо другая идея или вам нужна дополнительная информация, пожалуйста, дайте мне знать.

Я новичок в стеке, поэтому, пожалуйста, будьте нежны со мной :). Любая помощь будет высоко оценена. BTW Я пытаюсь решить проблему моделирования смеси для больших данных. Благодаря!

+1

Это очень хороший вопрос, но в конец, вы единственный, кто может ответить на него правильно. :) Просматривайте вещи и смотрите, что быстрее для вашей конкретной проблемы. Оба являются хорошими подходами. Именно тот подход, который будет самым быстрым, будет в значительной степени зависеть от размера ваших входных данных и того, что вы делаете. Вы также можете рассмотреть возможность изменения вашей первой версии для векторизации вычисления вдоль одной оси и петли над другой. Векторизация - это компромисс между использованием памяти и скоростью. Часто бывает лучше удалить только одну часть вложенного цикла, если проблема с памятью является проблемой. –

+0

Спасибо @JoeKington за комментарий. Для ясности я упомянул только точечный продукт во внутреннем контуре. В таком случае, как и указанная векторизация внутренней петли, безусловно, путь. Тем не менее, на самом деле я делаю несколько матричных алгебр, включая инверсию, транспонирование, пару более точечных продуктов и т. Д. Поэтому я предполагаю, что векторизация или использование понимания списка для внутреннего цикла не является хорошей идеей. В отношении первой части вашего комментария я сделаю профилирование и опубликую его. Мне нравится добавить, что использование ** cvxopt ** пакета LAPACK и BLAS и подхода 2 равно скорости приближения 3. – evernomer

ответ

2

Хотя я согласен с комментарием, что единственный способ узнать наверняка - это профайл для себя, есть несколько руководящих принципов, которые могут помочь вам написать эффективный код numpy с первой попытки. Вот несколько советов для вашей проблемы:

  • над головой для создания нового Numpy массива имеет порядок 1000 раз стоимости дополнения/умножение, поэтому подход 2 должен быть неэффективным, поскольку каждый вызов np.dot создает массив но выполняет только 27 умножений.
  • Если у вас будет медленный цикл for-loop в python, сделайте это по большей левой оси, если это возможно (для C-упорядоченных массивов).
  • Очень сложно написать очень общий N-мерный код эффективно, поэтому я предполагаю, что, поскольку серия более простых вызовов numpy будет более эффективной, чем np.einsum. Попробуйте C = np.sum(A[...,:,None] * B[...,:,:], axis=-2) (это довольно спекулятивно).

Так что я хотел бы попробовать что-то вроде следующего:

xyloop2 = np.empty((ndata, kdata, 3, 3)) 

for i in xrange(ndata): 
    xyloop2[i] = np.sum(x[i,:,:,:,None] * y[i,:,None,:,:], axis=-2) 

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

1

По-видимому, когда-то einsum эффективен.Примеры с P, Q, R, S, чтобы быть 100, 50, 3, 3

Пример I:

%timeit tt=np.einsum('pqrs, pqsu->pqru',x,y) 
100 loops, best of 3: 3.45 ms per loop 

%timeit zz= np.sum(x[:,:,:,None,:]*y[:,:,:,None],axis=-2) 
10000 loops, best of 3: 153 µs per loop 

Пример II:

%timeit zz= np.sum(x[:,:,:,None,:]*y[:,:,:,None,None],axis=-2) 
1000 loops, best of 3: 274 µs per loop 

%timeit tt=np.einsum('pqrs, pqs->pqr',x,y) 
10000 loops, best of 3: 151 µs per loop 

np.allclose(zz,tt) 
True 
Смежные вопросы