以前、DataFrameの縦持ち・横持ちの変換につ いてまとめましたが、今回はNumPyの行列を縦持ちから横持ちへ変換する小ワザを紹介します。
以下のような5行3列の値を、列1の値を行インデックス、列2を列インデックス、列3を各要素の値として行列化します。前提として、行と列になる値 (ここでは列1と列2) の組み合わせはユニークである必要があります (合計・平均などの集計が必要な場合は、事前に行ってください) 。
列1 | 列2 | 列3 |
---|---|---|
1 | 1 | 1 |
1 | 2 | 2 |
2 | 1 | 2 |
2 | 3 | 1 |
3 | 3 | 3 |
↓
変換の実装は以下です。
キモはnumpy.uniqueメソッドの使い方です。
return_inverce
をTrueにすると、ユニーク値のarrayに加えて、引数 (array) の各要素をユニーク値リストのインデックスに変換したarrayの2つがタプルで返ってきます。例えば、np.unique([1, 2, 1, 3, 3], return_inverse=True)
では、array([1, 2, 3]), array([0, 1, 0, 2, 2])
が返り値となります (引数の0番目と2番目の要素に、ユニーク値arrayの0番目の要素、つまり1であることを意味します)。
あとは、列1のユニーク値数×列2のユニーク値数の行列を作り、インデックス (uniqueの2つ目の返り値) を使って、列3の値をセットしてます。
import numpy as np # 縦持ち行列 vertical_matrix = np.array([[1, 1, 1], [1, 2, 2], [2, 1, 2], [2, 3, 1], [3, 3, 3]]) #array([[1, 1, 1], # [1, 2, 2], # [2, 1, 2], # [2, 3, 1], # [3, 3, 3]]) # 行・列のインデックスを取得 rows, row_pos = np.unique(vertical_matrix[:, 0], return_inverse=True) cols, col_pos = np.unique(vertical_matrix[:, 1], return_inverse=True) # 横持ち行列の初期化 horizontal_matrix = np.zeros((len(rows), len(cols))) # 行・列のインデックスを指定して、3列目の値をセット horizontal_matrix[row_pos , col_pos ] = vertical_matrix[:, 2] #array([[ 1., 2., 0.], # [ 2., 0., 1.], # [ 0., 1., 3.]])