4

私の目標は、2 つの配列の modulo-2 乗算 (乗算 = and、加算 = xor) を実行する関数を作成することです。ここに私が今持っているコードがあります。感謝して受け取ったこれを改善する方法についての提案-特に、リスト内包表記を適切な形状の配列に直接変換するにはどうすればよいですか?

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
4

2 に答える 2

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 です!

于 2013-01-19T00:01:15.700 に答える
2

sに対して一般的な行列乗算を実行しint、続いて modulo-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   |
+---------------+---------+-----------+----------+

これは、非常に大きな配列の場合、またはプログラムがこの操作を頻繁に行う場合に問題になる可能性があります。
私はこのアプローチとセバーグの解決策とハイメによって提案されたそれへの修正を計りました。
さまざまな機能を実装する方法は次のとおりです。

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)

1000x1000 のタイミングの記録を次に示します (すべてのケースで結果が同じであることも確認しました)。

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
于 2013-01-19T23:14:46.073 に答える