Numpy: создание векторизованной матрицы - PullRequest
0 голосов
/ 10 октября 2018

Если я хочу создать матрицу, я просто вызываю

m = np.matrix([[x00, x01],
               [x10, x11]])

, где x00, x01, x10 и x11 - это числа.Однако я хотел бы векторизовать этот процесс.Например, если x - это одномерные массивы длиной l, то я бы хотел, чтобы m стал массивом матриц или l x2x2-мерным массивом.К сожалению,

zeros = np.zeros(10)
ones = np.ones(10)
m = np.matrix([[zeros, ones],
               [zeros, ones]])

вызывает ошибку («матрица должна быть двумерной»), а

m = np.array([[zeros, ones],
              [zeros, ones]])

дает вместо этого 2x2x l -мерный массив.Чтобы решить эту проблему, я мог бы позвонить np.moveaxis(m, 2, 0), но я ищу прямое решение, которому не нужно менять порядок осей (потенциально огромного) массива.Это также устанавливает порядок осей вправо только в том случае, если я передаю одномерные массивы в качестве значений для моей матрицы, но не в том случае, если они имеют более высокий размер.

Существует ли общий и эффективный способ векторизации созданияматрицы?

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Давайте попробуем 2d (4d после объединения):

In [374]: ones = np.ones((3,4),int)
In [375]: arr = np.array([[ones*0, ones],[ones*2, ones*3]])
In [376]: arr
Out[376]: 
array([[[[0, 0, 0, 0],
         [0, 0, 0, 0],
         [0, 0, 0, 0]],

        [[1, 1, 1, 1],
         [1, 1, 1, 1],
         [1, 1, 1, 1]]],


       [[[2, 2, 2, 2],
         [2, 2, 2, 2],
         [2, 2, 2, 2]],

        [[3, 3, 3, 3],
         [3, 3, 3, 3],
         [3, 3, 3, 3]]]])
In [377]: arr.shape
Out[377]: (2, 2, 3, 4)

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

Мы можем легко транспонировать оси:

In [378]: arr.transpose(2,3,0,1)
Out[378]: 
array([[[[0, 1],
         [2, 3]],

        [[0, 1],
         [2, 3]],

      ...

        [[0, 1],
         [2, 3]]]])

Теперь это 12 (2,2) массивы.Это view, использующий буфер данных arr's.Он просто отличается по форме и шагам.Выполнение этой транспонирования довольно эффективно и не медленнее, когда arr очень большой.И большая часть математики в транспонированном массиве будет почти такой же эффективной, как и в оригинальном arr (из-за многопоточности).Если есть различия в скорости, это будет связано с кэшированием на глубоком уровне.

Но для некоторых действий потребуется копия.Например, транспонированный массив нельзя копировать без копии.Исходные 0, 1 и т. Д. Больше не вместе.

In [379]: arr.transpose(2,3,0,1).ravel()
Out[379]: 
array([0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1,
       2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
       0, 1, 2, 3])

Я мог бы создать тот же массив 1d с помощью

In [380]: tarr = np.empty((3,4,2,2), int)
In [381]: tarr[...,0,0] = ones*0
In [382]: tarr[...,0,1] = ones*1
In [383]: tarr[...,1,0] = ones*2
In [384]: tarr[...,1,1] = ones*3
In [385]: tarr.ravel()
Out[385]: 
array([0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1,
       2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
       0, 1, 2, 3])

. Это tarr - это то, что вы пытаетесь создать. 'напрямую '.

Еще один способ взглянуть на эту конструкцию - присвоить значения массиву .flat с шагами - вставьте 0 в каждый 4-й слот, 1 в соседние и т. д.:

In [386]: tarr.flat[0::4] = ones*0
In [387]: tarr.flat[1::4] = ones*1
In [388]: tarr.flat[2::4] = ones*2
In [389]: tarr.flat[3::4] = ones*3

Вот еще один «прямой» способ - используйте np.stack (версия concatenate) для создания (3,4,4) массива, который затем можно изменить:

np.stack((ones*0,ones*1,ones*2,ones*3),2).reshape(3,4,2,2)

То, что stack, по сути:

In [397]: ones1 = ones[...,None]
In [398]: np.concatenate((ones1*0, ones1*1, ones1*2, ones1*3),axis=2)

Обратите внимание, что эта цель (3,4,2,2) может быть преобразована в (12,4) (и vv) бесплатно.Таким образом, возникает первоначальная проблема: легче ли построить (4,12) и транспонировать, или сначала построить (12,4)?Это действительно двумерная проблема, а не (m + n) d.

0 голосов
/ 10 октября 2018

np.matrix должен быть двумерным массивом.Из пустой документации np.matrix

Возвращает матрицу из массива-подобного объекта или из строки данных.Матрица - это специализированный двумерный массив, который сохраняет свою двумерную природу посредством операций.Он имеет определенные специальные операторы, такие как * (умножение матриц) и ** (мощность матриц).

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

Есть ли причина, по которой вы хотите использовать np.matrix?Большинство недопустимых операций должны выполняться в объекте массива, поскольку класс матрицы квази-устаревший.

В вашем примере я попытался использовать метод транспонирования (.T):

zeros = np.zeros(10)
ones = np.ones(10)
twos = np.ones(10) * 2
threes = np.ones(10) * 3
m = np.array([[zeros, ones], [twos, threes]]).T
>> array([[0,2],[1,3]],...)

или

m = np.transpose(np.array([[zeros, ones], [twos, threes]]), (2,0,1))
>> array([[0,1],[2,3]],...)

Это дает (10, 2, 2) массив

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...