次のdoctestに合格するために2つの行列を追加する関数を作成しようとしています。
>>> a = [[1, 2], [3, 4]]
>>> b = [[2, 2], [2, 2]]
>>> add_matrices(a, b)
[[3, 4], [5, 6]]
>>> c = [[8, 2], [3, 4], [5, 7]]
>>> d = [[3, 2], [9, 2], [10, 12]]
>>> add_matrices(c, d)
[[11, 4], [12, 6], [15, 19]]
だから私は関数を書いた:
def add(x, y):
return x + y
そして、私は次の関数を書きました:
def add_matrices(c, d):
for i in range(len(c)):
print map(add, c[i], d[i])
そして私はsort正しい答えを得る。
これをサポートするnumpy
モジュールを使用できます。
>>> import numpy as np
>>> a = np.matrix([[1, 2], [3, 4]])
>>> b = np.matrix([[2, 2], [2, 2]])
>>> a+b
matrix([[3, 4],
[5, 6]])
自分で実装したい場合は、次の機構を設定します。これにより、任意のペアワイズ操作を定義できます。
from pprint import pformat as pf
class Matrix(object):
def __init__(self, arrayOfRows=None, rows=None, cols=None):
if arrayOfRows:
self.data = arrayOfRows
else:
self.data = [[0 for c in range(cols)] for r in range(rows)]
self.rows = len(self.data)
self.cols = len(self.data[0])
@property
def shape(self): # myMatrix.shape -> (4,3)
return (self.rows, self.cols)
def __getitem__(self, i): # lets you do myMatrix[row][col
return self.data[i]
def __str__(self): # pretty string formatting
return pf(self.data)
@classmethod
def map(cls, func, *matrices):
assert len(set(m.shape for m in matrices))==1, 'Not all matrices same shape'
rows,cols = matrices[0].shape
new = Matrix(rows=rows, cols=cols)
for r in range(rows):
for c in range(cols):
new[r][c] = func(*[m[r][c] for m in matrices], r=r, c=c)
return new
ペアワイズメソッドの追加は、パイと同じくらい簡単です。
def __add__(self, other):
return Matrix.map(lambda a,b,**kw:a+b, self, other)
def __sub__(self, other):
return Matrix.map(lambda a,b,**kw:a-b, self, other)
例:
>>> a = Matrix([[1, 2], [3, 4]])
>>> b = Matrix([[2, 2], [2, 2]])
>>> b = Matrix([[0, 0], [0, 0]])
>>> print(a+b)
[[3, 4], [5, 6]]
>>> print(a-b)
[[-1, 0], [1, 2]]
ペアごとのべき乗、否定、二項演算などを追加することもできます。行列の乗算と行列のべき乗には*と**を残すのがおそらく最善であるため、ここでは説明しません。
2つのネストされたリスト行列のみに操作をマップする非常に簡単な方法が必要な場合は、次のように実行できます。
def listmatrixMap(f, *matrices):
return \
[
[
f(*values)
for c,values in enumerate(Zip(*rows))
]
for r,rows in enumerate(Zip(*matrices))
]
デモ:
>>> listmatrixMap(operator.add, a, b, c))
[[3, 4], [5, 6]]
追加のif-elseおよびkeyword引数を使用すると、ラムダでインデックスを使用できます。以下は、行列の行順enumerate
関数を作成する方法の例です。わかりやすくするために、if-elseとキーワードは上記では省略されています。
>>> listmatrixMap(lambda val,r,c:((r,c),val), a, indices=True)
[[((0, 0), 1), ((0, 1), 2)], [((1, 0), 3), ((1, 1), 4)]]
編集
したがって、上記のadd_matrices
次のように機能します:
def add_matrices(a,b):
return listmatrixMap(add, a, b)
デモ:
>>> add_matrices(c, d)
[[11, 4], [12, 6], [15, 19]]
def addM(a, b):
res = []
for i in range(len(a)):
row = []
for j in range(len(a[0])):
row.append(a[i][j]+b[i][j])
res.append(row)
return res
from itertools import izip
def add_matrices(c, d):
return [[a+b for a, b in izip(row1, row2)] for row1, row2 in izip(c, d)]
ただし、前述のように、車輪の再発明は必要ありません。numpy
を使用するだけで、より高速で柔軟性が高くなる可能性があります。
もう1つの解決策:
map(lambda i: map(lambda x,y: x + y, matr_a[i], matr_b[i]), xrange(len(matr_a)))