Создание матрицы NumPy заданного размера в векторизации - PullRequest
2 голосов
/ 29 мая 2019

Если есть встроенная функция NumPy или какой-либо векторизованный подход для генерации следующих 2D матриц NumPy для значения n> 1? Позвольте мне привести несколько примеров для желаемых матриц для n, равных 2, 3 и 4.

Один из подходов заключается в построении матрицы из 1 в нижней треугольной части, а затем просто умножении на вектор np.arange(1, n+1). Любые другие альтернативы?

import numpy as np

Для n = 2

n = 2
arr = np.array([[1, 0], [2, 2]])

# array([[1, 0],
#        [2, 2]])

Для n = 3

n = 3
arr = np.array([[1, 0, 0], [2, 2, 0], [3, 3, 3]])

# array([[1, 0, 0],
#        [2, 2, 0],
#        [3, 3, 3]])

Для n = 4

n = 4
arr = np.array([[1, 0, 0, 0], [2, 2, 0, 0], [3, 3, 3, 0], [4, 4, 4, 4]])

# array([[1, 0, 0, 0],
#        [2, 2, 0, 0],
#        [3, 3, 3, 0],
#        [4, 4, 4, 4]])

Моя попытка (пример для n = 4) с использованием вложенных циклов for. Работает для любого значения n> 1:

import numpy as np

n = 4
arr = np.zeros((n, n))

for i in range(n):
    for j in range(0, i+1):
        arr[i][j] = i+1 

# array([[1., 0., 0., 0.],
#        [2., 2., 0., 0.],
#        [3., 3., 3., 0.],
#        [4., 4., 4., 4.]])    

Ответы [ 3 ]

5 голосов
/ 29 мая 2019

Вы можете использовать np.tril и np.broadcast_to для создания исходного варианта arange.

import numpy as np

n = 4
np.tril(np.broadcast_to(np.arange(1, n+1)[:, None], (n, n)))

array([[1, 0, 0, 0],
       [2, 2, 0, 0],
       [3, 3, 3, 0],
       [4, 4, 4, 4]])
4 голосов
/ 29 мая 2019

Мы могли бы использовать ранжированный массив, умноженный на маску нижнего треугольника -

In [44]: n = 5

In [45]: np.arange(1,n+1)[:,None]*np.tri(n,dtype=bool)
Out[45]: 
array([[1, 0, 0, 0, 0],
       [2, 2, 0, 0, 0],
       [3, 3, 3, 0, 0],
       [4, 4, 4, 4, 0],
       [5, 5, 5, 5, 5]])

Он легко переносим на numexpr, чтобы использовать многоядерные системы для больших данных, учитывая арифметически-ориентированный характер -

import numexpr as ne

ne.evaluate('A*B',{'A':np.arange(1,n+1)[:,None],'B':np.tri(n,dtype=bool)})

Сравнительный анализ

Включая все опубликованные решения здесь.

Сценарий сравнительного анализа -

import numpy as np
import perfplot

import numexpr as ne

def numexpr_range_broadcast(n):
    return ne.evaluate('A*B',{'A':np.arange(1,n+1)[:,None],'B':np.tri(n,dtype=bool)})

def where_method(n):
    x = np.arange(1,n+1)
    return np.where(x[:,None]>=x,x[:,None],0)

perfplot.show(
    setup=lambda n: n,
    kernels=[
        lambda n: where_method(n),
        lambda n: np.tril(np.broadcast_to(np.arange(1, n+1)[:, None], (n, n))),
        lambda n: np.arange(1,n+1)[:,None]*np.tri(n,dtype=bool),
        lambda n: numexpr_range_broadcast(n),
        ],
    labels=['where','tril_broadacast','range_broadcast','numexpr_range_broadcast'],
    n_range=[10, 20, 50, 80, 100, 200, 500, 800, 1000, 2000, 5000],
    xlabel='n',
    logx=True,
    logy=True,
    )

Вывод -

enter image description here

Следовательно, на более низком n's чуть раньше 100, np.where на основе выигрывает его, а на большем n's, numexpr светит.

2 голосов
/ 29 мая 2019

Вот решение с использованием np.where и вещанием:

x = np.arange(1,n+1)
np.where(x[:,None]>=x,x[:,None],0)
# array([[1, 0, 0, 0],
#        [2, 2, 0, 0],
#        [3, 3, 3, 0],
#        [4, 4, 4, 4]])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...