V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
sunhk25
V2EX  ›  Python

Python numpy 如何优雅的进行矩阵的并行计算

  •  
  •   sunhk25 · 2021-04-19 17:13:00 +08:00 · 2767 次点击
    这是一个创建于 1348 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有一列表对其自身的矩阵求和。 现在是通过双循环来计算的,numpy 有什么优雅的写法吗?

    import numpy as np
    def how(x, y):
        return x + y
    arr = [1, 2, 3, 4, 5, 6]
    match_arr = np.zeros((len(arr), len(arr)))
    for i in range(0, len(arr)):
        for j in range(0, len(arr)):
            if j >= i:
                X = how(arr[i], arr[j])
                match_arr[i, j] = X
                match_arr[j, i] = X
    
    print(match_arr)
    [[ 2.  3.  4.  5.  6.  7.]
     [ 3.  4.  5.  6.  7.  8.]
     [ 4.  5.  6.  7.  8.  9.]
     [ 5.  6.  7.  8.  9. 10.]
     [ 6.  7.  8.  9. 10. 11.]
     [ 7.  8.  9. 10. 11. 12.]]
    
    
    18 条回复    2021-04-21 07:20:06 +08:00
    hsfzxjy
        1
    hsfzxjy  
       2021-04-19 17:24:35 +08:00 via Android
    arr = np.array([...])
    match_arr = arr[None] + arr[:, None]
    geelaw
        2
    geelaw  
       2021-04-19 17:28:07 +08:00 via iPhone
    arr = np.array(arr)
    match_arr = np.reshape(arr, (-1, 1)) + np.reshape(arr, (1, -1))

    大概是这么个意思,参考 broadcast 的概念。

    如果每个元素的计算过程不能用 numpy 内置的运算表达则无法实现,因为 GIL 的存在。
    princelai
        3
    princelai  
       2021-04-19 18:05:47 +08:00
    ```python
    a,b = np.meshgrid(arr,arr)
    match_arr = a+b
    ```
    不一定高效,但是简单
    princelai
        4
    princelai  
       2021-04-19 18:11:08 +08:00   ❤️ 1
    还有一种方法,原理一样
    ```python
    match_arr = np.mgrid[1:7,1:7].sum(axis=0)
    ```
    sunhk25
        5
    sunhk25  
    OP
       2021-04-19 18:17:56 +08:00 via Android
    @geelaw 那就是说用自定义的 how 函数来循环计算时还是没有优化方法呗
    sunhk25
        6
    sunhk25  
    OP
       2021-04-19 18:19:49 +08:00 via Android
    @princelai sum 是我自定义的一个函数
    princelai
        7
    princelai  
       2021-04-19 18:25:03 +08:00
    @sunhk25 #6 你是想说 how 是你自定义的函数?你不是简单的相加是吗?那上 numba,循环放到 numba 里很快,比 numpy 还快。或者你都有两个传播好的 array 了,你改一下 how 函数不就完了
    sunhk25
        8
    sunhk25  
    OP
       2021-04-19 18:32:56 +08:00
    @princelai 对 是这个意思。我研究一下 numba,谢谢
    nikan999
        9
    nikan999  
       2021-04-19 18:49:26 +08:00   ❤️ 1
    先用 numba 如果还想快 就上进程
    hsfzxjy
        10
    hsfzxjy  
       2021-04-19 18:50:36 +08:00 via Android   ❤️ 1
    除了 numba,cython 也可以试试。门槛有点高,但是性能优化的上限也高
    kickcellardoor
        11
    kickcellardoor  
       2021-04-19 19:58:50 +08:00
    numba,数据量够大甚至可以 PyTorch, GPU 上来并行
    Harry1993
        12
    Harry1993  
       2021-04-20 06:22:33 +08:00
    樓上說 PyTorch,那我來說 TensorFlow 吧
    necomancer
        13
    necomancer  
       2021-04-20 23:41:49 +08:00
    In [4]: from numba import guvectorize, float64, jit
    In [5]: @jit(nopython=True)
    ...: def how(x, y):
    ...: return x + y
    In [6]: @guvectorize([(float64[:], float64[:,:])], '(n)->(n, n)', nopython=True)
    ...: def f(arr, ret):
    ...: for i in range(arr.shape[0]):
    ...: for j in range(arr.shape[0]):
    ...: if j >= i:
    ...: tmp = how(arr[i], arr[j])
    ...: ret[i, j] = tmp
    ...: ret[j, i] = tmp
    In [11]: arr = [np.arange(3), np.arange(10, 13)]

    In [12]: f(arr)
    Out[12]:
    array([[[ 0., 1., 2.],
    [ 1., 2., 3.],
    [ 2., 3., 4.]],

    [[20., 21., 22.],
    [21., 22., 23.],
    [22., 23., 24.]]])
    In [13]: arr = np.arange(3)

    In [14]: f(arr)
    Out[14]:
    array([[0., 1., 2.],
    [1., 2., 3.],
    [2., 3., 4.]])
    necomancer
        14
    necomancer  
       2021-04-20 23:42:20 +08:00
    想要速度一定要用 nopython=True,但是代码得注意一定不能有 object
    necomancer
        15
    necomancer  
       2021-04-20 23:43:18 +08:00
    这狗 shit 的排版……
    necomancer
        16
    necomancer  
       2021-04-20 23:47:29 +08:00
    另,guvectorize 可以 target='cpu', 'gpu', 'parallel'
    necomancer
        17
    necomancer  
       2021-04-21 00:07:49 +08:00   ❤️ 1
    我测试了一下,有个简单一点的方法,但是会慢一些:
    arr = np.arange(3)
    def how(x, y):
    ....if x < y:
    ........return x + y
    ....return x * y
    np.frompyfunc(how, 2, 1)(arr[:,None], arr)

    frompyfunc 会返回一个 ufunc,从而让 numpy 可以 broadcast 自定义的函数。但是效率似乎没有 numba 的 vectorize/guvectorize 高,尤其是 numba 可以 target='gpu'或者'parallel'
    sunhk25
        18
    sunhk25  
    OP
       2021-04-21 07:20:06 +08:00 via Android
    @necomancer target 参数学习了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2566 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 04:18 · PVG 12:18 · LAX 20:18 · JFK 23:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.