亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何將兩個 2d numpy 數組復制到預分配數組

如何將兩個 2d numpy 數組復制到預分配數組

翻過高山走不出你 2022-10-11 21:10:28
我有兩個行數相同但列數不同的大型 2d numpy 數組。假設 arr1 的形狀為 (num_rows1, num_cols1),而 arr2 的形狀為 (num_rows1, num_cols2)。我預先分配了一個大小為 (num_rows1, num_cols1 + num_cols2) 的 numpy 數組 arr12。將 arr1 和 arr2 復制到 arr12 以使 arr1 與 arr2 連接的最有效方法是什么?使用這種預分配方法是否比 numpy 的連接方法更有效?
查看完整描述

2 回答

?
繁星淼淼

TA貢獻1775條經驗 獲得超11個贊

基準測試

我們將僅對各種數據集進行基準測試并從中得出結論。

計時

使用benchit包(幾個基準測試工具打包在一起;免責聲明:我是它的作者)對建議的解決方案進行基準測試。

基準代碼:

import numpy as np

import benchit


def numpy_concatenate(a, b):

    return np.concatenate((a,b),axis=1)


def numpy_hstack(a, b):

    return np.hstack((a,b))


def preallocate(a, b):

    m,n = a.shape[1], b.shape[1]

    out = np.empty((a.shape[0],m+n), dtype=np.result_type((a.dtype, b.dtype)))

    out[:,:m] = a

    out[:,m:] = b

    return out

    

funcs = [numpy_concatenate, numpy_hstack, preallocate]

R = np.random.rand 


inputs = {n: (R(1000,1000), R(1000,n)) for n in [100, 200, 500, 1000, 200, 5000]}

t = benchit.timings(funcs, inputs, multivar=True,   input_name='Col length of b')

t.plot(logy=False, logx=True, savepath='plot_1000rows.png')

http://img1.sycdn.imooc.com//63456b8300017ed617490894.jpg

結論:它們在時間上具有可比性。


內存分析

在內存方面,np.hstack應該類似于np.concatenate. 因此,我們將使用其中之一。


讓我們設置一個帶有大型二維數組的輸入數據集。我們將做一些內存基準測試。


設置代碼:


# Filename : memprof_npconcat_preallocate.py

import numpy as np

from memory_profiler import profile


@profile(precision=10)

def numpy_concatenate(a, b):

    return np.concatenate((a,b),axis=1)


@profile(precision=10)

def preallocate(a, b):

    m,n = a.shape[1], b.shape[1]

    out = np.empty((a.shape[0],m+n), dtype=np.result_type((a.dtype, b.dtype)))

    out[:,:m] = a

    out[:,m:] = b

    return out


R = np.random.rand

a,b = R(1000,1000), R(1000,1000)


if __name__ == '__main__':

    numpy_concatenate(a, b)


if __name__ == '__main__':

    preallocate(a, b)  

所以,a是 1000x1000,對于b.


跑 :


$ python3 -m memory_profiler memprof_npconcat_preallocate.py 

Filename: memprof_npconcat_preallocate.py


Line #    Mem usage    Increment   Line Contents

================================================

     9  69.3281250000 MiB  69.3281250000 MiB   @profile(precision=10)

    10                             def numpy_concatenate(a, b):

    11  84.5546875000 MiB  15.2265625000 MiB       return np.concatenate((a,b),axis=1)



Filename: memprof_npconcat_preallocate.py


Line #    Mem usage    Increment   Line Contents

================================================

    13  69.3554687500 MiB  69.3554687500 MiB   @profile(precision=10)

    14                             def preallocate(a, b):

    15  69.3554687500 MiB   0.0000000000 MiB       m,n = a.shape[1], b.shape[1]

    16  69.3554687500 MiB   0.0000000000 MiB       out = np.empty((a.shape[0],m+n), dtype=np.result_type((a.dtype, b.dtype)))

    17  83.6484375000 MiB  14.2929687500 MiB       out[:,:m] = a

    18  84.4218750000 MiB   0.7734375000 MiB       out[:,m:] = b

    19  84.4218750000 MiB   0.0000000000 MiB       return out

因此,對于preallocatemethod 來說,總的 mem 消耗為14.2929687500+ 0.7734375000,略小于15.2265625000.


將輸入數組的大小更改為 5000x5000a和b-


$ python3 -m memory_profiler memprof_npconcat_preallocate.py

Filename: memprof_npconcat_preallocate.py


Line #    Mem usage    Increment   Line Contents

================================================

     9 435.4101562500 MiB 435.4101562500 MiB   @profile(precision=10)

    10                             def numpy_concatenate(a, b):

    11 816.8515625000 MiB 381.4414062500 MiB       return np.concatenate((a,b),axis=1)



Filename: memprof_npconcat_preallocate.py


Line #    Mem usage    Increment   Line Contents

================================================

    13 435.5351562500 MiB 435.5351562500 MiB   @profile(precision=10)

    14                             def preallocate(a, b):

    15 435.5351562500 MiB   0.0000000000 MiB       m,n = a.shape[1], b.shape[1]

    16 435.5351562500 MiB   0.0000000000 MiB       out = np.empty((a.shape[0],m+n), dtype=np.result_type((a.dtype, b.dtype)))

    17 780.3203125000 MiB 344.7851562500 MiB       out[:,:m] = a

    18 816.9296875000 MiB  36.6093750000 MiB       out[:,m:] = b

    19 816.9296875000 MiB   0.0000000000 MiB       return out

同樣,預分配的總數較少。


結論:預分配方法具有稍好的內存優勢,這在某種程度上是有道理的。使用連接,我們有三個涉及 src1 + src2 -> dst 的數組,而使用預分配,只有 src 和 dst,雖然分兩步,但內存擁塞較少。


查看完整回答
反對 回復 2022-10-11
?
幕布斯7119047

TA貢獻1794條經驗 獲得超8個贊

numpy編譯的代碼,例如concatenate通常確定它需要多大的返回數組,創建該數組,并將值復制到它。它通過 C-API 調用實現這一點的事實對內存使用沒有任何影響。concatenate不會覆蓋或重用參數使用的任何內存。


In [465]: A, B = np.ones((1000,1000)), np.zeros((1000,500))

一些時間比較:


In [466]: timeit np.concatenate((A,B), axis=1)                                                         

6.73 ms ± 338 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)


In [467]: C = np.zeros((1000,1500))                                                                    

In [468]: timeit np.concatenate((A,B), axis=1, out=C)                                                  

6.44 ms ± 174 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)


In [469]: %%timeit 

     ...: C = np.zeros((1000,1500)) 

     ...: np.concatenate((A,B), axis=1, out=C)                                                                                               

11.5 ms ± 358 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)


In [470]: %%timeit 

     ...: C = np.zeros((1000,1500)) 

     ...: C[:,:1000]=A; C[:,1000:]=B                                                                                             

11.5 ms ± 282 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)


In [471]: %%timeit 

     ...: C[:,:1000]=A; C[:,1000:]=B                                                                                              

6.29 ms ± 160 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)

因此,如果目標數組已經存在,請使用它。但是,僅僅為了這個目的而創建一個似乎并沒有太大的優勢。


查看完整回答
反對 回復 2022-10-11
  • 2 回答
  • 0 關注
  • 126 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號