Создать матрицу из функции - PullRequest
2 голосов
/ 26 апреля 2019

Я хочу создать матрицу из функции, чтобы матрица C (3,3) имела значения, равные 1, если индекс строки меньше заданного порогового значения k.

import numpy as np

k = 3
C = np.fromfunction(lambda i,j: 1 if i < k else 0, (3,3))

Однако этокусок кода выдает ошибку

«Значение истинности массива с более чем одним элементом неоднозначно. Используйте a.any () или a.all ()», и я не очень понимаю, почему.

Ответы [ 3 ]

2 голосов
/ 26 апреля 2019

Код для fromfunction:

dtype = kwargs.pop('dtype', float)
args = indices(shape, dtype=dtype)
return function(*args, **kwargs)

Вы видите, что он вызывает function только один раз - со всем массивом indices. Это не итеративно.

In [672]: idx = np.indices((3,3))                                                    
In [673]: idx                                                                        
Out[673]: 
array([[[0, 0, 0],
        [1, 1, 1],
        [2, 2, 2]],

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

Ваша лямбда ожидает скалярные i,j значения, а не трехмерный массив

 lambda i,j: 1 if i < k else 0

idx<3 - это трехмерный логический массив. Ошибка возникает при использовании в контексте if.

np.vectorize или np.frompyfunc лучше, если вы хотите применить скалярную функцию к набору массивов:

In [677]: np.vectorize(lambda i,j: 1 if i < 2 else 0)(idx[0],idx[1])                 
Out[677]: 
array([[1, 1, 1],
       [1, 1, 1],
       [0, 0, 0]])

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

Один из многих подходов к целому массиву:

In [680]: np.where(np.arange(3)[:,None]<2, np.ones((3,3),int), np.zeros((3,3),int))  
Out[680]: 
array([[1, 1, 1],
       [1, 1, 1],
       [0, 0, 0]])
1 голос
/ 26 апреля 2019

Проблема в том, что np.fromfunction не выполняет итерацию по всем элементам, а только возвращает индексы в каждом измерении. Вы можете использовать np.where() для применения условия на основе этих индексов, выбирая один из двух вариантов в зависимости от условия:

import numpy as np

k = 3
np.fromfunction(lambda i, j: np.where(i < k, 1, 0), (5,3))

, что дает:

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

Это позволяет избежать именования лямбды, при этом все становится слишком громоздким. На моем ноутбуке этот подход был примерно в 20 раз быстрее, чем np.vectorize().

1 голос
/ 26 апреля 2019

Как подсказывает @MarkSetchell, вам нужно векторизовать вашу функцию:

k = 3
f = lambda i,j: 1 if i < k else 0

C = np.fromfunction(np.vectorize(f), (3,3))

и вы получите:

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