#python #function #numpy #list-comprehension
#python #функция #numpy #список-понимание
Вопрос:
Я хочу сделать что-то простое, но я не нашел разумного способа сделать это.
Предполагая, что у меня есть numpy
массив с 3 строками, подобными этому:
import numpy as np
a = np.array([[0.514, 0.966, 0.443, 0.95 , 0.524, 0.423, 0.75 , 0.463, 0.721, 0.089],
[0.929, 0.014, 0.275, 0.521, 0.739, 0.612, 0.366, 0.469, 0.575, 0.533],
[0.235, 0.084, 0.994, 0.713, 0.421, 0.851, 0.66 , 0.231, 0.699, 0.216]])
Я хочу применить следующую функцию к каждой паре строк и накапливать результаты , т.е. (row0 с row1) -> (вывод предыдущего шага со строкой 3) и так далее:
def myfunc(x,y):
return x**2 y**2 - x*y
Вручную это будет выглядеть примерно так:
tmp1 = myfunc(a[0],a[1])
results = myfunc(tmp1,a[2])
Теперь я хочу разумно обобщить это для общего N (N = a.shape[0])
.
Я пробовал подходы, основанные на понимании списка, но я не могу обобщить его для любого N.
Редактировать 1:
Пример для N = 4:
tmp1 = myfunc(a[0],a[1])
tmp2 = myfunc(tmp1,a[2])
results = myfunc(tmp2,a[3])
Комментарии:
1.Используйте
for
цикл. Или используйтеfunctools.reduce
функцию (py3).numpy
ufunc
также естьreduce
метод.2. Привет. Цикл for был бы в порядке, но я попытался использовать цикл for, и снова я не нахожу способа его обобщить.
3. Уточните, что вы хотите с более высоким N, 4 или 5 и т.д.
4. См. Редактирование 1 для N = 4
Ответ №1:
Вот наивный способ ее решения с использованием for
цикла по первому измерению (т.Е. Оси-0):
# your custom function; slightly rewritten because
# * based multiplication is faster than `pow()`
In [93]: def myfunc(x,y):
...: return x*x y*y - x*y
# to be replenished after each iteration
In [95]: res = a[0]
# go over rows and compute the results using `myfunc()`
In [96]: for i in range(a.shape[0]-1):
...: curr_step_res = myfunc(res, a[i 1])
...: res = curr_step_res[:]
# final result
In [97]: res
Out[97]:
array([0.32468859, 0.775874 , 0.861402 , 0.4852772 , 0.18264236,
0.56028635, 0.33515591, 0.05036018, 0.37391415, 0.05364418])
проверка работоспособности с помощью ручных вызовов
In [99]: tmp1 = myfunc(a[0],a[1])
In [100]: results = myfunc(tmp1,a[2])
In [101]: np.allclose(results, res)
Out[101]: True
результаты для вашего случая с N = 4
# sample array to work with
In [102]: a = np.random.random_sample((4, 6))
# to be replenished after each iteration
In [103]: res = a[0]
In [104]: for i in range(a.shape[0]-1):
...: curr_step_res = myfunc(res, a[i 1])
...: res = curr_step_res[:]
In [105]: res
Out[105]:
array([0.51971283, 0.61377465, 0.0838452 , 0.2201938 , 0.54028219,
0.19318569])
# compute using manual calls
In [106]: tmp1 = myfunc(a[0],a[1])
...: tmp2 = myfunc(tmp1,a[2])
...: results = myfunc(tmp2,a[3])
# sanity check for equality of both results
In [107]: np.allclose(results, res)
Out[107]: True
PS это должно быть обобщено на любой N
, где N = arr.shape[0]
. Также обратите внимание, что нет простого способа распараллелить это, поскольку вычисления выполняются последовательно.
Комментарии:
1. это именно то, что мне было нужно.
Ответ №2:
Упрощенная версия вашей функции и a
которая должна выделить действие:
In [344]: def myfunc(x,y):
...: return 2*x y
...: a = np.eye(5)
In [345]: a
Out[345]:
array([[1., 0., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.],
[0., 0., 0., 0., 1.]])
In [346]: res = myfunc(a[0],a[1])
In [347]: res
Out[347]: array([2., 1., 0., 0., 0.])
In [348]: for i in a[2:]:
...: res = myfunc(res,i)
...:
In [349]: res
Out[349]: array([16., 8., 4., 2., 1.])
В Python есть reduce
функция для повторного применения функции к списку. В Py3 это в functools
:
In [355]: functools.reduce(myfunc, a)
Out[355]: array([16., 8., 4., 2., 1.])
Или начиная с нуля res
и применяя ко всему массиву:
In [357]: res = np.zeros(a.shape[1])
In [358]: for i in a:
...: res = myfunc(res,i)
...:
In [359]: res
Out[359]: array([16., 8., 4., 2., 1.])
Для сохранения промежуточных результатов:
In [361]: res = [np.zeros(a.shape[1])]
...: for i in a:
...: temp = myfunc(res[-1],i)
...: res.append(temp)
In [362]: res
Out[362]:
[array([0., 0., 0., 0., 0.]),
array([1., 0., 0., 0., 0.]),
array([2., 1., 0., 0., 0.]),
array([4., 2., 1., 0., 0.]),
array([8., 4., 2., 1., 0.]),
array([16., 8., 4., 2., 1.])]
Это концепция accumulate
. numpy
ufunc
иметь оба reduce
и accumulate
, и будет быстрее, если myfunc
их можно записать с их помощью. Но это не работает в общем случае.
In [363]: np.add.accumulate(a,axis=0)
Out[363]:
array([[1., 0., 0., 0., 0.],
[1., 1., 0., 0., 0.],
[1., 1., 1., 0., 0.],
[1., 1., 1., 1., 0.],
[1., 1., 1., 1., 1.]])