2013-01-18 20 views
4

我的目標是編寫一個函數,執行兩個數組(multiplication =和addition = xor)的模2乘法。這是我現在的代碼。關於如何提高這種感覺的任何建議 - 特別是,我應該如何讓列表理解直接進入適當形狀的陣列?這個雙列表理解能直接進入一個數組嗎(有更多的Pythonic方法嗎?)

import numpy as np 
import operator 

def m2mult(a,b): 

    c = np.ndarray([reduce(operator.xor, np.logical_and(a[x,:],b[:,y])) 
     for x in range(0,a.shape[0]) for y in range (0, b.shape[1])]) 
    c.shape = (a.shape[0], b.shape[1]) 

    return c 
+0

我覺得itertools.imap可能對你有用。 – Vetsin

回答

4

你不應該那樣做,在所有:

a = np.random.randint(0,2,(4,4)) 
b = np.random.randint(0,2,(4,4)) 

# Now note that this is true: 
# (I will let you figure that out, its a lot of neat broadcasting. 
# b.T would be enough as well, because of it) 
np.multiply(a[:,None,:], b.T[None,:,:]).sum(-1) == np.dot(a,b) 
# note also that .sum(-1) is the same as np.add.reduce(array, axis=-1) 

# now we can do the same thing for your logical operations: 
a = np.random.randint(0,2,(4,4)).astype(bool) 
b = np.random.randint(0,2,(4,4)).astype(bool) 

def m2mult(a, b): 
    mult = np.logical_and(a[:,None,:], b.T[None,:,:]) 
    return np.logical_xor.reduce(mult, axis=-1) 

而且其完全矢量化,速度更快,只是numpy的!

+2

+1但爲什麼不'mult = np.logical_and(a [...,None],b)'然後'np.logical_xor.reduce(mult,axis = 1)'?放棄轉位不是更好嗎? – Jaime

+0

@Jaime好點,我想快點試試我到了那裏,因爲在我的大腦中,它看起來有點像矩陣乘法(如果可能的話) – seberg

+0

好了!我非常尊重你答案的質量,並想知道你是否正在利用一些神祕的優化,通過在最後一個軸上執行'reduce'... – Jaime

2

你可以做普通的矩陣乘法上int秒,然後模2減,然後再轉換回bool

np.mod(np.dot(a.astype('u1'), b), 2).astype('bool') 

它比seberg的解決方案和Jaime的修改更快。

+---------------+---------+-----------+----------+ 
|    | 10x10 | 1000x1000 | 750x1250 | 
+---------------+---------+-----------+----------+ 
| m2mult_tz  | 33 us | 7.27 s | 4.68 s | 
| m2mult_jaime | 56.7 us | 20.4 s | 14.2 s | 
| m2mult_seberg | 62.9 us | 20.5 s | 14.3 s | 
+---------------+---------+-----------+----------+ 

這可能是一個問題的真正的大陣列,或者如果你的程序做這個手術了很多。
我對這種方法和seberg的解決方案以及Jaime提出的修改進行了定時。
這裏是我是如何實現不同的功能:

import numpy as np 

def create_ab(n, m): 
    a = np.random.randint(0, 2, (n, m)).astype(bool) 
    b = np.random.randint(0, 2, (m, n)).astype(bool) 
    return a, b 


def m2mult_tz(a, b): 
    return np.mod(np.dot(a.astype('u1'), b), 2).astype(bool) 


def m2mult_seberg(a, b): 
    return np.logical_xor.reduce(
       np.logical_and(a[:,None,:], b.T[None,:,:]), 
       axis=-1) 


def m2mult_jaime(a, b): 
    return np.logical_xor.reduce(
       np.logical_and(a[:, :, None], b), 
       axis=1) 

這裏的1000×1000的定時的記錄(我還檢查的結果是相同的在所有情況下):

In [19]: a, b = create_ab(1000, 1000) 

In [20]: timeit m2mult_tz(a, b) 
1 loops, best of 3: 7.27 s per loop 

In [21]: timeit m2mult_jaime(a, b) 
1 loops, best of 3: 20.4 s per loop 

In [22]: timeit m2mult_seberg(a, b) 
1 loops, best of 3: 20.5 s per loop 

In [23]: r_tz = m2mult_tz(a, b) 

In [24]: r_jaime = m2mult_jaime(a, b) 

In [25]: r_seberg = m2mult_seberg(a, b) 

In [26]: np.all(r_tz == r_jaime) 
Out[26]: True 

In [27]: np.all(r_tz == r_seberg) 
Out[27]: True 
相關問題