2014-01-09 79 views
9

我有一個包含行的大型10,000,000+長度的數組。我需要單獨洗牌這些行。例如:每行numpy的快速列洗牌

[[1,2,3] 
[1,2,3] 
[1,2,3] 
... 
[1,2,3]] 

[[3,1,2] 
[2,1,3] 
[1,3,2] 
... 
[1,2,3]] 

我目前使用

map(numpy.random.shuffle, array) 

但它是一個Python(不與NumPy)循環和它採取的我的執行時間的99%。可悲的是,PyPy JIT沒有實現numpypy.random,所以我運氣不好。有沒有更快的方法?我願意用任何庫(pandasscikit-learnscipytheano等,只要它使用一個numpy的ndarray或衍生物。)

如果不是這樣,我想我會求助於用Cython或C++。

+0

'numpy.apply_along_axis(numpy.random.shuffle,1,array)'可能會快一點。我沒有計時。 – user2357112

+0

謝謝,我會研究它。 – PythonNut

+0

它實際上是一個很好的處理(≈10x),因爲它需要一個內存拷貝('shuffle'已經到位,所以你需要使用'permutation'來代替)。 – PythonNut

回答

5

這裏有一些想法:

In [10]: a=np.zeros(shape=(1000,3)) 

In [12]: a[:,0]=1 

In [13]: a[:,1]=2 

In [14]: a[:,2]=3 

In [17]: %timeit map(np.random.shuffle, a) 
100 loops, best of 3: 4.65 ms per loop 

In [21]: all_perm=np.array((list(itertools.permutations([0,1,2])))) 

In [22]: b=all_perm[np.random.randint(0,6,size=1000)] 

In [25]: %timeit (a.flatten()[(b+3*np.arange(1000)[...,np.newaxis]).flatten()]).reshape(a.shape) 
1000 loops, best of 3: 393 us per loop 

如果只有幾列,那麼所有可能的排列的數量比行陣列的數量少得多(在這種情況下,當有隻有3列,只有6個可能的排列)。使其更快的一種方法是首先將所有排列組合起來,然後通過從所有可能的排列中隨機選取一個排列來重新排列每一排。

這似乎仍然是快10倍甚至更大尺寸:

#adjust a accordingly 
In [32]: b=all_perm[np.random.randint(0,6,size=1000000)] 

In [33]: %timeit (a.flatten()[(b+3*np.arange(1000000)[...,np.newaxis]).flatten()]).reshape(a.shape) 
1 loops, best of 3: 348 ms per loop 

In [34]: %timeit map(np.random.shuffle, a) 
1 loops, best of 3: 4.64 s per loop 
+0

不錯。這比我的方法快。 – unutbu

+0

@unutbu,我的靈感來自你的'perms ='......必須承認,我的機器上有MKL,所以也許這會讓它更快一點。在你的身上它大約是6倍。 –

+0

不錯!由於每次實施都獲勝,因此讓計算機減少工作總是更好。 @CT朱,我在Fedora BLAS上得到了12x,所以這是完全合理的。 – PythonNut

7

如果列的排列是枚舉,那麼你可以這樣做:

import itertools as IT 
import numpy as np 

def using_perms(array): 
    nrows, ncols = array.shape 
    perms = np.array(list(IT.permutations(range(ncols)))) 
    choices = np.random.randint(len(perms), size=nrows) 
    i = np.arange(nrows).reshape(-1, 1) 
    return array[i, perms[choices]] 

N = 10**7 
array = np.tile(np.arange(1,4), (N,1)) 
print(using_perms(array)) 

收益率(像)

[[3 2 1] 
[3 1 2] 
[2 3 1] 
[1 2 3] 
[3 1 2] 
... 
[1 3 2] 
[3 1 2] 
[3 2 1] 
[2 1 3] 
[1 3 2]] 

下面是一個基準比較它與

def using_shuffle(array): 
    map(numpy.random.shuffle, array) 
    return array 

In [151]: %timeit using_shuffle(array) 
1 loops, best of 3: 7.17 s per loop 

In [152]: %timeit using_perms(array) 
1 loops, best of 3: 2.78 s per loop 

編輯: CT朱的方法比我快:

def using_Zhu(array): 
    nrows, ncols = array.shape  
    all_perm = np.array((list(itertools.permutations(range(ncols))))) 
    b = all_perm[np.random.randint(0, all_perm.shape[0], size=nrows)] 
    return (array.flatten()[(b+3*np.arange(nrows)[...,np.newaxis]).flatten()] 
      ).reshape(array.shape) 

In [177]: %timeit using_Zhu(array) 
1 loops, best of 3: 1.7 s per loop 

這裏是朱的方法的輕微變化,這甚至可能更快一點:

def using_Zhu2(array): 
    nrows, ncols = array.shape  
    all_perm = np.array((list(itertools.permutations(range(ncols))))) 
    b = all_perm[np.random.randint(0, all_perm.shape[0], size=nrows)] 
    return array.take((b+3*np.arange(nrows)[...,np.newaxis]).ravel()).reshape(array.shape) 

In [201]: %timeit using_Zhu2(array) 
1 loops, best of 3: 1.46 s per loop 
+0

你的答案需要大量的時間和內存,''np.array(list(IT.permutations(range(ncols))))'當我爲我的機器學習算法做的時候崩潰了我的程序 – suku

0

您也可以嘗試在pandas

apply功能
import pandas as pd 

df = pd.DataFrame(array) 
df = df.apply(lambda x:np.random.shuffle(x) or x, axis=1) 

然後從數據幀中提取numpy數組

print df.values 
+3

不幸的是,它慢了大約70倍。我懷疑熊貓增加了更多的開銷,並且正在發生內存拷貝(可能是兩個)。然而,這個'或'技巧非常酷。 – PythonNut

0

我相信我有一個備用,相當於戰略,立足於這個以前的答案:

# original sequence 
a0 = np.arange(3) + 1 

# length of original sequence 
L = a0.shape[0] 

# number of random samples/shuffles 
N_samp = 1e4 

# from above 
all_perm = np.array((list(itertools.permutations(np.arange(L))))) 
b = all_perm[np.random.randint(0, len(all_perm), size=N_samp)] 

# index a with b for each row of b and collapse down to expected dimension 
a_samp = a0[np.newaxis, b][0] 

我不知道這是如何比較性能,但我喜歡它的可讀性。