2010-10-31 24 views
12
  1. 什麼是最快(或最 「Python化」)的方式來的Python/numpy的:將布爾變量的列表unsigned int類型

    x = [False, False, True, True] 
    

    轉換爲12? (如果有這種方式)

  2. 如果x是bools的代替numpy.array?有沒有特別的命令?

我有一個大的m乘N陣列的布爾值,其中,每個n元素行代表一個高維特徵向量的單一低維散列。 (在上面的例子中,n = 4)。我想知道答案,以便儘可能壓縮我的數據。謝謝。


編輯:謝謝你的回覆!使用下面的測試代碼,

t = 0 
for iter in range(500): 
    B = scipy.signbit(scipy.randn(1000,20)) 
    for b in B: 
     t0 = time.clock() 
     # test code here 
     t1 = time.clock() 
     t += (t1-t0) 
print t 

...這裏是我的Thinkpad筆記本的運行時間:

當然,我歡迎可以證實或反駁我的數據的任何獨立測試!


編輯:在我的回答如下,改變int(j)簡單j仍然有效,但運行六倍慢!那麼如果bool使用int來鑄造,其他答案可能會變得更快。但我懶得再次測試一切。


編輯:liori發佈的獨立測試here結果。

+0

將[False,False,True,True]轉換爲12的規則是什麼? – 2010-10-31 23:34:17

+0

'x [0]'是LSB,'x [-1]'是MSB。 – 2010-10-31 23:35:52

+2

請使用'timeit'進行測試,它不太容易出錯。我的時代:http://pastebin.com/x1FEP9gY – liori 2010-11-01 02:16:52

回答

10

從各種其他的答案以各種想法,這裏是另一種方式來做到這一點:

sum(1<<i for i, b in enumerate(x) if b) 

這是在我的測試相當快 - 右即使它像瘋了一樣溢出,也可以使用大量位的numpy方法。我使用了liori的測試模塊進行測試。史蒂夫的方法,與我所建議的改變,只是幾乎沒有更快。但是,如果需要一次完成很多類型的轉換(並且不需要太多比特),我敢打賭,numpy會更快。

+1

'sum(b << i爲i,b在枚舉(x))' – kennytm 2010-11-01 06:52:15

+0

@ KennyTM。聰明,但我認爲它的原始速度大約快20%。這是迄今爲止最快的。 – aaronasterling 2010-11-01 07:08:31

1

是這樣的嗎?

>>> x = [False, False, True, True] 
>>> sum([int(y[1])*2**y[0] for y in enumerate(x)]) 
12 

您可以使用list()抹上numpy的陣列轉換爲常規列表。

>>> a = numpy.array([1,2,3,4]) 
>>> a 
array([1, 2, 3, 4]) 
>>> list(a) 
[1, 2, 3, 4] 
+1

'0 ** 0'是1,所以如果第一個元素是False,那麼你會得到一個錯誤的錯誤。 – liori 2010-10-31 23:56:58

+0

@ liori,我不相信這適用於我的代碼,因爲我實際上並沒有這樣做嗎?儘管如此,仍然有趣。不知道。 – 2010-11-01 01:22:09

+0

'int(False)* 2 == 0'。 'enumerate'給出的第一個索引是'0'。 – liori 2010-11-01 01:24:47

6

大多數Python的可能是這樣的:

sum(2**i*b for i, b in enumerate(x)) 

這是很難說,如果它也是最快的。

在numpy的,我會用

numpy.sum(2**numpy.arange(len(x))*x) 

,但這不會是小數組x更快,因爲機器尺寸整數用於替代蟒蛇任意精度的整數它不會大陣列x工作。

+0

謝謝!對於某些陣列大小,第二種解決方案工作得很好,但對於其他解決方案則沒有。 – 2010-11-01 00:38:02

+0

@Steve - numpy解決方案的另一個優點是可以避免遍歷每一行。使用上面測試代碼中的''B'「數組:'numpy.sum(2 ** numpy.arange(B.shape [1])* B,axis = 1)''。與循環遍歷數組中的每一行相比,這應該會有很大的加速...完整的500倍循環在我的機器上執行時間不到一秒... – 2010-11-01 02:19:49

+1

由於numpy不像Python一樣處理大整數,所以要注意真正的大數字。如果數字越大,則可以通過在arange()中執行'dtype = numpy.longlong'來獲得更多的信息。此外,通過使用生成的numpy數組的sum方法,而不是使用numpy.sum,會有非常非常小的速度。 – 2010-11-01 05:17:26

2

優雅,Python的,始終工作方式是這樣的:

def powers(x): 
    """yield powers of x, starting from x**0 forever""" 
    power = 1 
    while True: 
     yield power 
     power *= x 

def bools_to_int(bools): 
    # in Python 2, use itertools.izip! 
    return sum(int(place) * place_weight for place_weight, place in 
       zip(powers(2), bools)) 

請注意,您可以得到(通過枚舉和在修真平方,其他答案做)擺脫powers - 但也許這種方式更清晰。

+0

你的答案與其他答案不一樣。用'bools'替換'bools''修復它。 – 2010-11-01 05:07:04

+0

@Justin Peel:再來一次?我已經注意到,在回答之後不久,添加了「反轉」... – delnan 2010-11-01 12:53:29

+0

嘗試使用OP給出的示例在此處提供的代碼。當它應該是12時,我得到3作爲答案。你不需要把'反向'放進去。 – 2010-11-01 15:55:36

3
reduce(lambda a,b:2*a+b, reversed(x)) 

如果您在數組末尾有最低有效位,您可以擺脫reversed()。這也適用於numpy.array,並且不需要枚舉()。從我的測試看起來也更快:不需要使用指數運算。

+0

謝謝你的優雅解決方案!我第一次看到它時被吹走了。不幸的是,它似乎運行速度最慢,有或沒有「反轉」。可能有人知道爲什麼? – 2010-11-01 00:33:41

+0

@Steve:在我的電腦上,它比sum +冪指數更快。有趣的事情......你用了多長時間?你用'timeit'測試性能嗎? – liori 2010-11-01 01:27:28

2

我的初步嘗試,僅供參考:

def bool2int(x): 
    y = 0 
    for i,j in enumerate(x): 
     if j: y += int(j)<<i 
    return y 
+0

等一下,這很有趣:把'int(j)'改爲'j'仍然可以,但是運行速度慢六倍! – 2010-11-01 00:46:39

+3

如果您只是將'int(j)'更改爲1,那麼您的速度最快。 – 2010-11-01 05:07:51

+0

等等......呃!謝謝!我真笨。 – 2010-11-01 12:36:16

0

如果您願意爲混音添加另一個擴展名,我將pack()和unpack()添加到gmpy的開發分支。我的測試表明它可能快2倍或3倍。

>>> import gmpy2 
>>> gmpy2.pack([0,0,1,1],1) 
mpz(12) 
>>> gmpy2.unpack(12,1) 
[mpz(0), mpz(0), mpz(1), mpz(1)] 

聲明:開發版本被稱爲gmpy2,可以與穩定版本共存。它仍處於alpha階段,但有望在幾周內成爲beta。您需要安裝GMP和MPFR庫。源可在http://code.google.com/p/gmpy/source/checkout

1

如果你有一個矩陣,你可能想要做這樣的:

#precompute powers of two 
vals = 2.**np.arange(20) 

B = .... 
compressed = np.dot(B, vals) # matrix multiplication. 

np.dot應該比Python中的任何循環更快。快多了。

1

我試圖ipython %timeit,似乎執行以下操作速度更快:

y = 0 
for i,j in enumerate(x): 
    if j: y += 1<<i 

此外,如果你的布爾向量是numpy.ndarray,將其轉換爲蟒蛇陣列x.tolist()和運行相同的似乎在這種情況下工作更快。這一切都是邊緣化的,但一致,以及在這些速度下,邊際收益很好。

1

numpy具有packbits功能。 它還支持操作沿軸:

In [3]: B = scipy.signbit(scipy.randn(1000,8)).astype("i1") 

In [3]: B[0] 
Out[3]: array([0, 1, 0, 0, 0, 1, 0, 0], dtype=int8) 

In [4]: np.packbits(B[0]) 
Out[4]: array([68], dtype=uint8) 

In [5]: %timeit np.packbits(B, axis=1) 
10000 loops, best of 3: 37 µs per loop 

它爲int8的尺寸,你必須轉向更大尺寸和或

In [8]: x # multiple of 8 
Out[8]: array([1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1], dtype=int8) 

In [9]: r = np.packbits(x).astype(np.int32); r 
Out[9]: array([171, 129], dtype=uint8) 

In [10]: r[0] << 8 | r[1] 
Out[10]: 33237 

In [11]: sum(1<<i for i, b in enumerate(x[::-1]) if b) 
Out[11]: 33237 

如果x是沒有的8個多就得墊零

相關問題