[英]Padding elements of a numpy array
讓我們說我有以下numpy array
:
[[1,1,1]
[1,1,1]
[1,1,1]]
我需要填充數組中的每個元素,兩邊都是零(而不是numpy.pad()
行和列的numpy.pad()
)。 最終結果如下:
[ [0,1,0,0,1,0,0,1,0]
[0,1,0,0,1,0,0,1,0]
[0,1,0,0,1,0,0,1,0] ]
有沒有更有效的方法來創建一個空數組並使用嵌套循環?
注意:我的偏好是盡可能快速和記憶。 單個陣列最多可以達到12000 ^ 2個元素,我同時使用其中的16個,所以我的邊距非常薄,在32位
編輯:應該已指定,但填充不總是1,填充必須是可變的,因為我通過依賴於具有最高分辨率的陣列的因子對數據進行上采樣。 給出3個具有形狀的陣列(121,121); (1200,1200); (12010,12010)我需要能夠將前兩個陣列填充到(12010,12010)的形狀(我知道這些數字不具有共同的因素,這不是一個問題,因為在索引或兩個實際位置是可以接受的,這個填充只需要將它們變成相同的形狀,通過填充末端的行來填充數字是可以接受的)
工作解決方案:調整@Kasramvd解決方案可以解決問題。 這是適合我的問題的應用程序的代碼。
import numpy as np
a = np.array([[1, 2, 3],[1, 2, 3], [1, 2, 3]])
print(a)
x, y = a.shape
factor = 3
indices = np.repeat(np.arange(y + 1), 1*factor*2)[1*factor:-1*factor]
a=np.insert(a, indices, 0, axis=1)
print(a)
結果是:
[[1 2 3]
[1 2 3]
[1 2 3]]
[[0 0 0 1 0 0 0 0 0 0 2 0 0 0 0 0 0 3 0 0 0]
[0 0 0 1 0 0 0 0 0 0 2 0 0 0 0 0 0 3 0 0 0]
[0 0 0 1 0 0 0 0 0 0 2 0 0 0 0 0 0 3 0 0 0]]
這是一種使用zeros-initialization
的方法 -
def padcols(arr,padlen):
N = 1+2*padlen
m,n = arr.shape
out = np.zeros((m,N*n),dtype=arr.dtype)
out[:,padlen+np.arange(n)*N] = arr
return out
樣品運行 -
In [118]: arr
Out[118]:
array([[21, 14, 23],
[52, 70, 90],
[40, 57, 11],
[71, 33, 78]])
In [119]: padcols(arr,1)
Out[119]:
array([[ 0, 21, 0, 0, 14, 0, 0, 23, 0],
[ 0, 52, 0, 0, 70, 0, 0, 90, 0],
[ 0, 40, 0, 0, 57, 0, 0, 11, 0],
[ 0, 71, 0, 0, 33, 0, 0, 78, 0]])
In [120]: padcols(arr,2)
Out[120]:
array([[ 0, 0, 21, 0, 0, 0, 0, 14, 0, 0, 0, 0, 23, 0, 0],
[ 0, 0, 52, 0, 0, 0, 0, 70, 0, 0, 0, 0, 90, 0, 0],
[ 0, 0, 40, 0, 0, 0, 0, 57, 0, 0, 0, 0, 11, 0, 0],
[ 0, 0, 71, 0, 0, 0, 0, 33, 0, 0, 0, 0, 78, 0, 0]])
在本節中,我在運行時和內存使用基准在這個帖子貼的方法: padcols
和@ Kasramvd的解決方案FUNC: padder
的各種填充長度相當於一個中型陣列上。
時序分析
In [151]: arr = np.random.randint(10,99,(300,300))
# Representative of original `3x3` sized array just bigger
In [152]: %timeit padder(arr,1)
100 loops, best of 3: 3.56 ms per loop
In [153]: %timeit padcols(arr,1)
100 loops, best of 3: 2.13 ms per loop
In [154]: %timeit padder(arr,2)
100 loops, best of 3: 5.82 ms per loop
In [155]: %timeit padcols(arr,2)
100 loops, best of 3: 3.66 ms per loop
In [156]: %timeit padder(arr,3)
100 loops, best of 3: 7.83 ms per loop
In [157]: %timeit padcols(arr,3)
100 loops, best of 3: 5.11 ms per loop
內存分析
用於這些內存測試的腳本 -
import numpy as np
from memory_profiler import profile
arr = np.random.randint(10,99,(300,300))
padlen = 1 # Edited to 1,2,3 for the three cases
n = padlen
@profile(precision=10)
def padder():
x, y = arr.shape
indices = np.repeat(np.arange(y+1), n*2)[n:-n]
return np.insert(arr, indices, 0, axis=1)
@profile(precision=10)
def padcols():
N = 1+2*padlen
m,n = arr.shape
out = np.zeros((m,N*n),dtype=arr.dtype)
out[:,padlen+np.arange(n)*N] = arr
return out
if __name__ == '__main__':
padder()
if __name__ == '__main__':
padcols()
內存使用量輸出 -
情況1:
$ python -m memory_profiler timing_pads.py
Filename: timing_pads.py
Line # Mem usage Increment Line Contents
================================================
8 42.4492187500 MiB 0.0000000000 MiB @profile(precision=10)
9 def padder():
10 42.4492187500 MiB 0.0000000000 MiB x, y = arr.shape
11 42.4492187500 MiB 0.0000000000 MiB indices = np.repeat(np.arange(y+1), n*2)[n:-n]
12 44.7304687500 MiB 2.2812500000 MiB return np.insert(arr, indices, 0, axis=1)
Filename: timing_pads.py
Line # Mem usage Increment Line Contents
================================================
14 42.8750000000 MiB 0.0000000000 MiB @profile(precision=10)
15 def padcols():
16 42.8750000000 MiB 0.0000000000 MiB N = 1+2*padlen
17 42.8750000000 MiB 0.0000000000 MiB m,n = arr.shape
18 42.8750000000 MiB 0.0000000000 MiB out = np.zeros((m,N*n),dtype=arr.dtype)
19 44.6757812500 MiB 1.8007812500 MiB out[:,padlen+np.arange(n)*N] = arr
20 44.6757812500 MiB 0.0000000000 MiB return out
案例#2:
$ python -m memory_profiler timing_pads.py
Filename: timing_pads.py
Line # Mem usage Increment Line Contents
================================================
8 42.3710937500 MiB 0.0000000000 MiB @profile(precision=10)
9 def padder():
10 42.3710937500 MiB 0.0000000000 MiB x, y = arr.shape
11 42.3710937500 MiB 0.0000000000 MiB indices = np.repeat(np.arange(y+1), n*2)[n:-n]
12 46.2421875000 MiB 3.8710937500 MiB return np.insert(arr, indices, 0, axis=1)
Filename: timing_pads.py
Line # Mem usage Increment Line Contents
================================================
14 42.8476562500 MiB 0.0000000000 MiB @profile(precision=10)
15 def padcols():
16 42.8476562500 MiB 0.0000000000 MiB N = 1+2*padlen
17 42.8476562500 MiB 0.0000000000 MiB m,n = arr.shape
18 42.8476562500 MiB 0.0000000000 MiB out = np.zeros((m,N*n),dtype=arr.dtype)
19 46.1289062500 MiB 3.2812500000 MiB out[:,padlen+np.arange(n)*N] = arr
20 46.1289062500 MiB 0.0000000000 MiB return out
案例#3:
$ python -m memory_profiler timing_pads.py
Filename: timing_pads.py
Line # Mem usage Increment Line Contents
================================================
8 42.3906250000 MiB 0.0000000000 MiB @profile(precision=10)
9 def padder():
10 42.3906250000 MiB 0.0000000000 MiB x, y = arr.shape
11 42.3906250000 MiB 0.0000000000 MiB indices = np.repeat(np.arange(y+1), n*2)[n:-n]
12 47.4765625000 MiB 5.0859375000 MiB return np.insert(arr, indices, 0, axis=1)
Filename: timing_pads.py
Line # Mem usage Increment Line Contents
================================================
14 42.8945312500 MiB 0.0000000000 MiB @profile(precision=10)
15 def padcols():
16 42.8945312500 MiB 0.0000000000 MiB N = 1+2*padlen
17 42.8945312500 MiB 0.0000000000 MiB m,n = arr.shape
18 42.8945312500 MiB 0.0000000000 MiB out = np.zeros((m,N*n),dtype=arr.dtype)
19 47.4648437500 MiB 4.5703125000 MiB out[:,padlen+np.arange(n)*N] = arr
20 47.4648437500 MiB 0.0000000000 MiB return out
您可以根據數組的形狀使用np.repeat
創建相關索引,然后在該索引中插入0。
>>> def padder(arr, n):
... x, y = arr.shape
... indices = np.repeat(np.arange(y+1), n*2)[n:-n]
... return np.insert(arr, indices, 0, axis=1)
...
>>>
>>> padder(a, 1)
array([[0, 1, 0, 0, 1, 0, 0, 1, 0],
[0, 1, 0, 0, 1, 0, 0, 1, 0],
[0, 1, 0, 0, 1, 0, 0, 1, 0]])
>>>
>>> padder(a, 2)
array([[0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0]])
>>> padder(a, 3)
array([[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]])
上述方法在一行中:
np.insert(a, np.repeat(np.arange(a.shape[1] + 1), n*2)[n:-n], 0, axis=1)
展平數組,將每個1轉換為[0,1,0],然后再次重新整形為3行。 在以下代碼中,ones數組在var a中:
a = np.ones([3,3])
b = [[0, x, 0] for x in a.ravel()]
c = np.reshape(b, (a.shape[0], -1))
print(c)
輸出:
[[0 1 0 0 1 0 0 1 0]
[0 1 0 0 1 0 0 1 0]
[0 1 0 0 1 0 0 1 0]]
這些方法的時間和內存比較問題是它將insert
視為黑盒子。 但該函數是可以讀取和復制的Python代碼。 雖然它可以處理各種輸入,但在這種情況下我認為它
new
目標數組 insert
不可能比Divakar's
padcols
更有效。
讓我們看看我是否可以清楚地復制insert
:
In [255]: indices = np.repeat(np.arange(y + 1), 1*factor*2)[1*factor:-1*factor]
In [256]: indices
Out[256]: array([0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3])
In [257]: numnew = len(indices)
In [258]: order = indices.argsort(kind='mergesort')
In [259]: indices[order] += np.arange(numnew)
In [260]: indices
Out[260]:
array([ 0, 1, 2, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 18, 19,
20])
這些是將采用0
填充值的列。
In [266]: new = np.empty((3,21),a.dtype)
In [267]: new[:,indices] = 0 # fill
# in this case with a lot of fills
# np.zeros((3,21),a.dtype) would be just as good
In [270]: old_mask = np.ones((21,),bool)
In [271]: old_mask[indices] = False
In [272]: new[:,old_mask] = a
In [273]: new
Out[273]:
array([[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0]])
與padcols
的主要區別在於它使用布爾掩碼進行索引而不是列號。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.