Python: написать внешний продукт с помощью карты и уменьшить - PullRequest
0 голосов
/ 29 мая 2020

Предположим, у меня есть матрица

import numpy as np
from functools import reduce
np.random.seed(123)
X = np.random.normal(size=(5, 2))

, и я хочу вычислить X ^ t X без использования функций numpy и использования функций map, reduce и lambda. Поскольку мы можем записать X ^ t X как сумму внешних произведений, моей целью было бы:

def outer_product(x):
    """Computes outer product of a vector with itself"""
    pass

map(outer_product, X)

Однако я не могу найти эффективный способ записать все это с помощью map reduce.

Моя попытка

def outer(x):
    xxx = np.repeat(x, len(x))
    yyy = np.array(list(x) * len(x))
    return np.reshape(list(map(lambda x, y: x*y, xxx, yyy)), (len(x), len(x)))

так, чтобы

outer(X[0, ])

И затем я написал матрицу ковариаций следующим образом:

def cov(X):
    return np.array(reduce(lambda x, y: x + y, list(map(outer, X)))) / np.size(X, 0)

Ответы [ 2 ]

1 голос
/ 29 мая 2020
In [40]: X = np.arange(10).reshape(5,2)   

Используя outer и список / карту из принятого ответа:

In [41]: outer = lambda V: np.array([[x*x1 for x in V] for x1 in V])                     
In [43]: list(map(outer, X))                                                             
Out[43]: 
[array([[0, 0],
        [0, 1]]),
 array([[4, 6],
        [6, 9]]),
 array([[16, 20],
        [20, 25]]),
 array([[36, 42],
        [42, 49]]),
 array([[64, 72],
        [72, 81]])]

Используя numpy широковещательную рассылку:

In [44]: X[:,:,None]*X[:,None,:]                                                         
Out[44]: 
array([[[ 0,  0],
        [ 0,  1]],

       [[ 4,  6],
        [ 6,  9]],

       [[16, 20],
        [20, 25]],

       [[36, 42],
        [42, 49]],

       [[64, 72],
        [72, 81]]])

Для (5,2 ) X результат представляет собой массив (5,2,2).

Некоторые небольшие временные тесты:

In [55]: timeit list(map(outer, X))                                                      
51.8 µs ± 1.29 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [57]: timeit [outer(i) for i in X]                                                    
49.8 µs ± 65.9 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [58]: timeit X[:,:,None]*X[:,None,:]                                                  
5.37 µs ± 11.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

list/map имеет примерно такую ​​же скорость, как и понимание списка. В общем, я считаю, что понимание списка более четкое. Но широковещательные операции numpy обычно выполняются намного быстрее.

Если вы собираетесь выполнять итерацию, подумайте о работе со списками; обычно быстрее:

In [61]: timeit [outer(i) for i in X.tolist()]                                           
24.3 µs ± 63.6 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [62]: outer0 = lambda V: [[x*x1 for x in V] for x1 in V] 
In [64]: timeit [outer0(i) for i in X.tolist()]                                          
7.33 µs ± 16 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
1 голос
/ 29 мая 2020

Чтобы ответить на ваш вопрос, внешний продукт может быть определен как вложенная карта, например

outer = lambda V: np.array(list(map(lambda x: list(map(lambda y: x*y, V)), V)))

X = np.random.normal(size=(5, 2))
>>> outer(X[1])
array([[ 0.08007683, -0.42624902], [-0.42624902,  2.26892377]])

На самом деле проще использовать понимание списка

outer = lambda V: np.array([[x*x1 for a in V] for x1 in V])

даст вам тот же результат . Затем вы можете сопоставить свою матрицу, например,

>>> list(map(outer, X))
[array([[ 1.17859381, -1.08274874],
       [-1.08274874,  0.99469794]]), array([[ 0.08007683, -0.42624902],
       [-0.42624902,  2.26892377]]), array([[ 0.33477825, -0.9555216 ],
       [-0.9555216 ,  2.72724264]]), array([[5.88877215, 1.04083337],
       [1.04083337, 0.18396604]]), array([[ 1.60259461, -1.0972381 ],
       [-1.0972381 ,  0.75123892]])]

. Кстати, ваша часть сокращения довольно приятна и лаконична. Я не думаю, что эта часть требует дальнейшего рефакторинга.

...