numpy .fffunction с указанным массивом, не похожим на arange - PullRequest
1 голос
/ 03 апреля 2020

Я определил функцию;

def f(x,y):
    return (1+x)**3.2 * np.cos(y**2.31+x)

и у меня есть два следующих массива:

x = np.linspace(10,20,10)
y = np.linspace(5,8,5)

Теперь я sh создам матрицу 10 x 5, где каждый ( i, j) элемент задается как f(x[i],x[j]). Это легко достигается с помощью for для l oop:

result = np.zeros(len(x)*len(y)).reshape((len(x),len(y)))
for i in range(len(x)):
    for j in range(len(y)):
        result[i][j] = f(x[i],y[j])

Однако я хочу значительно увеличить время вычислений, поэтому я ищу не-для l oop подход. Казалось бы, np.fromfunction отчасти приводит меня туда:

result = np.fromfunction(lambda x, y: f(x,y), (10, 5), dtype=int)

Однако для того, чтобы x и y были похожи на странности, требуется элемент x = 0,1, ..., 9 и у = 0,1, ..., 4. Есть ли способ сказать этой функции, что я хочу, чтобы она приняла мои ранее определенные массивы для х и у. Если это невозможно с np.fromfunction, есть ли другой способ добиться того же результата, который я получаю с моим для l oop, но с меньшим временем вычислений?

Ответы [ 2 ]

2 голосов
/ 03 апреля 2020

Если ваша функция написана так, что она принимает целые массивы, вы можете просто передать x и y, чтобы они broadcast вместе.

In [472]: x = np.linspace(10,20,10) 
     ...: y = np.linspace(5,8,5)                                                               
In [473]: def f(x,y): 
     ...:     return (1-x)**3.2 * np.cos(y**2.31+x) 
     ...:                                                                                      

Make x (10,1 ) массив, который затем вещает с (5,) y для получения результата (10,5):

In [474]: f(x[:,None], y)                                                                      
/usr/local/bin/ipython3:2: RuntimeWarning: invalid value encountered in power

Out[474]: 
array([[nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan],
       [nan, nan, nan, nan, nan]])

Все, что fromfunction делает, генерирует indices и передает их вашей функции:

In [478]: np.indices((3,4))                                                                    
Out[478]: 
array([[[0, 0, 0, 0],
        [1, 1, 1, 1],
        [2, 2, 2, 2]],

       [[0, 1, 2, 3],
        [0, 1, 2, 3],
        [0, 1, 2, 3]]])
#function(*indices...)

Если ваша функция ожидает значения, не индексы i,j fromfunction ничего не сделают для вас !. он просто заставляет вас использовать дополнительный уровень индексации f(x[i],y[j]). Если ваша функция обрабатывает массивы, fromfunction не ускоряет вычисления. И если ваша функция может принимать только скаляры, fromfunction не работает вообще.

Почему nan?

In [489]: f(x[0],y[0])                                                                         
/usr/local/bin/ipython3:2: RuntimeWarning: invalid value encountered in double_scalars

Out[489]: nan

===

С исправлено f:

In [494]: def f(x,y): 
     ...:     return (1+x)**3.2 * np.cos(y**2.31+x) 
     ...:                                                                                      
In [495]: x,y                                                                                  
Out[495]: 
(array([10.        , 11.11111111, 12.22222222, 13.33333333, 14.44444444,
        15.55555556, 16.66666667, 17.77777778, 18.88888889, 20.        ]),
 array([5.  , 5.75, 6.5 , 7.25, 8.  ]))

ix_ может использоваться для добавления измерения вещания к x:

In [496]: np.ix_(x,y)                                                                          
Out[496]: 
(array([[10.        ],
        [11.11111111],
        [12.22222222],
        [13.33333333],
        [14.44444444],
        [15.55555556],
        [16.66666667],
        [17.77777778],
        [18.88888889],
        [20.        ]]), 
 array([[5.  , 5.75, 6.5 , 7.25, 8.  ]]))

И эти массивы затем могут быть переданы в f (как я делал в [474]):

In [497]: f(*np.ix_(x,y))                                                                      
Out[497]: 
array([[  1322.50123614,  -1353.39115671,  -1702.96842965,
          2039.59858593,   2149.99822839],
       [ -1268.79441897,   1220.20345147,    572.47038806,
           401.57578676,   1322.04810644],
       [ -3873.89288421,   3872.45293387,   3741.19176848,
         -3203.15416244,  -2320.43820171],
       [ -2274.83634272,   2356.4885057 ,   3316.20257628,
         -4368.07920439,  -4932.15975126],
       [  3805.32723978,  -3710.95441159,  -2413.75855025,
           343.98082438,  -1742.79381001],
       [  7825.16462628,  -7850.07869311,  -7934.59775682,
          7309.08041012,   5891.07144208],
       [  2696.9980712 ,  -2869.31389573,  -4956.11491324,
          7455.17663401,   9114.69519122],
       [ -8800.47513177,   8651.89940176,   6527.58767232,
         -2896.13626079,   1015.66697767],
       [-13326.47899275,  13419.77502789,  14202.98227539,
        -13981.08503081, -12233.58338808],
       [ -1484.09855587,   1795.12675239,   5660.63236478,
        -10620.54747276, -14370.53381538]])

Применительно к 3 массивам:

In [503]: np.ix_([100,200],[10,20,30],[1,2,3,4])                                               
Out[503]: 
(array([[[100]],

        [[200]]]), array([[[10],
         [20],
         [30]]]), array([[[1, 2, 3, 4]]]))

производит (2,1,1), (1,3,1) и (1,1,4) массивы, которые будут транслироваться вместе для получения (2,3,4) результата.

def ff(x,y,z): return x+y+z  
In [504]: ff(*_)                                                                               
Out[504]: 
array([[[111, 112, 113, 114],
        [121, 122, 123, 124],
        [131, 132, 133, 134]],

       [[211, 212, 213, 214],
        [221, 222, 223, 224],
        [231, 232, 233, 234]]])
1 голос
/ 03 апреля 2020

вы можете использовать:

np.fromfunction(lambda i, j:  f(x[i],y[j]), (len(x),len(y)), dtype=int)

вы должны указать dtype=int в противном случае тип данных координаты будет float, который нельзя использовать в качестве индексов в f(x[i],y[j])

...