Ваш код более векторизуем, чем вы думаете. В дополнение к векторизации вы можете более подходящим образом использовать существующие функции.
Для генерации целочисленного диапазона np.arange
работает лучше, чем np.linspace
:
r_base = np.arange(5.)
a_array = np.arange(1., 4.)
Случайные числа могут можно сделать за один вызов с одним умножением:
np.random.seed(0)
r_mat = r_base * np.random.uniform(0.9, 1.1, (3, 5))
Я думаю, что проще всего было бы создать выходной массив и заполнить его на основе различных условий:
out = np.empty_like(r_mat)
Было бы полезно превратить a_array
в столбец, который соответствует количеству строк в r_mat
:
a = a_array[:, None]
Следующее, что вам нужно сделать, это сделать маски для условий. Первый - это построчная маска для r_row.mean() > 2
. Второе - это поэлементное r_row >= a
условие:
row_mask = (r_mat.mean(axis=1) > 2)[:, None]
elem_mask = r_mat >= a
Индекс [:, None]
на row_mask
превращает его в вектор-столбец для целей широковещания. Теперь вы можете оценить выбор, используя прямое маскирование и ключевое слово where
для соответствующего ufunc
s:
np.subtract(r_mat, a, out=out, where=row_mask & elem_mask)
np.add(r_mat, a, out=out, where=~row_mask & elem_mask)
out[row_mask & ~elem_mask] = np.nan
out[~row_mask & ~elem_mask] = 0