簡體   English   中英

Numpy 僅按行 shuffle 多維數組,保持列順序不變

[英]Numpy shuffle multidimensional array by row only, keep column order unchanged

如何僅在 Python 中按行對多維數組進行混洗(因此不要對列進行混洗)。

我正在尋找最有效的解決方案,因為我的矩陣非常大。 是否也可以在原始數組上高效地執行此操作(以節省內存)?

例子:

import numpy as np
X = np.random.random((6, 2))
print(X)
Y = ???shuffle by row only not colls???
print(Y)

我現在期望的是原始矩陣:

[[ 0.48252164  0.12013048]
 [ 0.77254355  0.74382174]
 [ 0.45174186  0.8782033 ]
 [ 0.75623083  0.71763107]
 [ 0.26809253  0.75144034]
 [ 0.23442518  0.39031414]]

輸出打亂行而不是列,例如:

[[ 0.45174186  0.8782033 ]
 [ 0.48252164  0.12013048]
 [ 0.77254355  0.74382174]
 [ 0.75623083  0.71763107]
 [ 0.23442518  0.39031414]
 [ 0.26809253  0.75144034]]

您可以使用numpy.random.shuffle()

此函數僅沿多維數組的第一個軸對數組進行洗牌。 子數組的順序改變了,但它們的內容保持不變。

In [2]: import numpy as np                                                                                                                                                                                  

In [3]:                                                                                                                                                                                                     

In [3]: X = np.random.random((6, 2))                                                                                                                                                                        

In [4]: X                                                                                                                                                                                                   
Out[4]: 
array([[0.71935047, 0.25796155],
       [0.4621708 , 0.55140423],
       [0.22605866, 0.61581771],
       [0.47264172, 0.79307633],
       [0.22701656, 0.11927993],
       [0.20117207, 0.2754544 ]])

In [5]: np.random.shuffle(X)                                                                                                                                                                                

In [6]: X                                                                                                                                                                                                   
Out[6]: 
array([[0.71935047, 0.25796155],
       [0.47264172, 0.79307633],
       [0.4621708 , 0.55140423],
       [0.22701656, 0.11927993],
       [0.20117207, 0.2754544 ],
       [0.22605866, 0.61581771]])

對於其他功能,您還可以查看以下功能:

函數random.Generator.permuted是在 Numpy 的 1.20.0 版本中引入的。

新函數與shufflepermutation不同之處在於,對軸索引的子數組進行了排列,而不是將軸視為其他索引的每個組合的單獨一維數組。 例如,現在可以置換二維數組的行或列。

您還可以使用np.random.permutation生成行索引的隨機排列,然后使用np.takeaxis=0索引到X的行。 此外, np.take有助於使用out=選項覆蓋輸入數組X本身,這將節省我們的內存。 因此,實現看起來像這樣 -

np.take(X,np.random.permutation(X.shape[0]),axis=0,out=X)

樣品運行 -

In [23]: X
Out[23]: 
array([[ 0.60511059,  0.75001599],
       [ 0.30968339,  0.09162172],
       [ 0.14673218,  0.09089028],
       [ 0.31663128,  0.10000309],
       [ 0.0957233 ,  0.96210485],
       [ 0.56843186,  0.36654023]])

In [24]: np.take(X,np.random.permutation(X.shape[0]),axis=0,out=X);

In [25]: X
Out[25]: 
array([[ 0.14673218,  0.09089028],
       [ 0.31663128,  0.10000309],
       [ 0.30968339,  0.09162172],
       [ 0.56843186,  0.36654023],
       [ 0.0957233 ,  0.96210485],
       [ 0.60511059,  0.75001599]])

額外的性能提升

這是一個使用np.argsort()加速np.random.permutation(X.shape[0])np.argsort() -

np.random.rand(X.shape[0]).argsort()

加速結果 -

In [32]: X = np.random.random((6000, 2000))

In [33]: %timeit np.random.permutation(X.shape[0])
1000 loops, best of 3: 510 µs per loop

In [34]: %timeit np.random.rand(X.shape[0]).argsort()
1000 loops, best of 3: 297 µs per loop

因此,洗牌解決方案可以修改為 -

np.take(X,np.random.rand(X.shape[0]).argsort(),axis=0,out=X)

運行時測試 -

這些測試包括兩種方法在這篇文章中列出np.shuffle基於一個在@Kasramvd's solution

In [40]: X = np.random.random((6000, 2000))

In [41]: %timeit np.random.shuffle(X)
10 loops, best of 3: 25.2 ms per loop

In [42]: %timeit np.take(X,np.random.permutation(X.shape[0]),axis=0,out=X)
10 loops, best of 3: 53.3 ms per loop

In [43]: %timeit np.take(X,np.random.rand(X.shape[0]).argsort(),axis=0,out=X)
10 loops, best of 3: 53.2 ms per loop

因此,似乎使用這些基於np.take的方法只能在內存受到關注的情況下使用,否則基於np.random.shuffle的解決方案看起來像是要走的路。

經過一些實驗 (i) 找到了在 nD 數組中對數據(按行)進行混洗的最內存和最省時的方法。 首先,對數組的索引進行混洗,然后使用混洗后的索引獲取數據。 例如

rand_num2 = np.random.randint(5, size=(6000, 2000))
perm = np.arange(rand_num2.shape[0])
np.random.shuffle(perm)
rand_num2 = rand_num2[perm]

更詳細地
在這里,我使用memory_profiler來查找內存使用情況和 python 的內置“time”模塊來記錄時間並比較所有以前的答案

def main():
    # shuffle data itself
    rand_num = np.random.randint(5, size=(6000, 2000))
    start = time.time()
    np.random.shuffle(rand_num)
    print('Time for direct shuffle: {0}'.format((time.time() - start)))
    
    # Shuffle index and get data from shuffled index
    rand_num2 = np.random.randint(5, size=(6000, 2000))
    start = time.time()
    perm = np.arange(rand_num2.shape[0])
    np.random.shuffle(perm)
    rand_num2 = rand_num2[perm]
    print('Time for shuffling index: {0}'.format((time.time() - start)))
    
    # using np.take()
    rand_num3 = np.random.randint(5, size=(6000, 2000))
    start = time.time()
    np.take(rand_num3, np.random.rand(rand_num3.shape[0]).argsort(), axis=0, out=rand_num3)
    print("Time taken by np.take, {0}".format((time.time() - start)))

時間結果

Time for direct shuffle: 0.03345608711242676   # 33.4msec
Time for shuffling index: 0.019818782806396484 # 19.8msec
Time taken by np.take, 0.06726956367492676     # 67.2msec

內存分析器結果

Line #    Mem usage    Increment   Line Contents
================================================
    39  117.422 MiB    0.000 MiB   @profile
    40                             def main():
    41                                 # shuffle data itself
    42  208.977 MiB   91.555 MiB       rand_num = np.random.randint(5, size=(6000, 2000))
    43  208.977 MiB    0.000 MiB       start = time.time()
    44  208.977 MiB    0.000 MiB       np.random.shuffle(rand_num)
    45  208.977 MiB    0.000 MiB       print('Time for direct shuffle: {0}'.format((time.time() - start)))
    46                             
    47                                 # Shuffle index and get data from shuffled index
    48  300.531 MiB   91.555 MiB       rand_num2 = np.random.randint(5, size=(6000, 2000))
    49  300.531 MiB    0.000 MiB       start = time.time()
    50  300.535 MiB    0.004 MiB       perm = np.arange(rand_num2.shape[0])
    51  300.539 MiB    0.004 MiB       np.random.shuffle(perm)
    52  300.539 MiB    0.000 MiB       rand_num2 = rand_num2[perm]
    53  300.539 MiB    0.000 MiB       print('Time for shuffling index: {0}'.format((time.time() - start)))
    54                             
    55                                 # using np.take()
    56  392.094 MiB   91.555 MiB       rand_num3 = np.random.randint(5, size=(6000, 2000))
    57  392.094 MiB    0.000 MiB       start = time.time()
    58  392.242 MiB    0.148 MiB       np.take(rand_num3, np.random.rand(rand_num3.shape[0]).argsort(), axis=0, out=rand_num3)
    59  392.242 MiB    0.000 MiB       print("Time taken by np.take, {0}".format((time.time() - start)))

您可以使用np.vectorize()函數按行對二維數組A進行混洗:

shuffle = np.vectorize(np.random.permutation, signature='(n)->(n)')

A_shuffled = shuffle(A)

我嘗試了很多解決方案,最后我使用了這個簡單的解決方案:

from sklearn.utils import shuffle
x = np.array([[1, 2],
              [3, 4],
              [5, 6]])
print(shuffle(x, random_state=0))

輸出:

[
[5 6]  
[3 4]  
[1 2]
]

如果您有 3d 數組,請循環遍歷第一個軸(軸 = 0)並應用此函數,例如:

np.array([shuffle(item) for item in 3D_numpy_array])

我對此有一個問題(或者可能是答案)假設我們有一個形狀為 =(1000,60,11,1) 的 numpy 數組 X 還假設 X 是一個大小為 60x11 且通道數 = 的圖像數組1 (60x11x1)。

如果我想打亂所有這些圖像的順序,並且要做到這一點,我將在 X 的索引上使用打亂。

def shuffling( X):
 indx=np.arange(len(X))          # create a array with indexes for X data
 np.random.shuffle(indx)
 X=X[indx]
 return X

那行得通嗎? 據我所知 len(X) 將返回最大的尺寸大小。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM