Remrinのpython攻略日記

python3に入門しました。python3についてあれこれとサンプルコードとか。

Numpyの使い方(13) 結合・分割

Numpyの配列の結合・分割について。
 

np.concatenate()

 2個以上の配列を軸指定して結合する。
 軸指定オプションのaxisはデフォルトが0
 マスクは保存されない。(マスクについては別の記事で)
 

import numpy as np

a1 = np.array([[1, 2, 3], [4, 5, 6]])
a2 = np.array([[7, 8, 9], [0, 11, 12]])

print(np.concatenate([a1, a2], axis=0))
# [[  1  2  3]
#  [  4  5  6]
#  [  7  8  9]
#  [ 10 11 12]]

print(np.concatenate([a1, a2], axis=1))
# [[ 1  2  3   7  8  9]
#  [ 4  5  6  10 11 12]]

 
・軸axisの指定はすでに存在している軸のみ。
 (Join a sequence of arrays along an existing axis.)
 1次元配列:axis=0
 2次元配列:axis=0, axis=1
 3次元配列:axis=0, axis=1, axis=2
 N次元配列:axis=[0, N)  0以上N未満

v1 = np.array([1, 2, 3])
v2 = np.array([4, 5, 6])

print(np.concatenate([v1, v2], axis=0))
# [1 2 3 4 5 6]

# print(np.concatenate([v1, v2], axis=1))
# IndexError: axis 1 out of bounds [0, 1)

 
・結合の方向にかかわらず、配列の次元が同じでないと結合できない。

a1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) # 2次元配列
a2 = np.array([10, 11, 12])                      # 1次元配列
print(np.concatenate([a1, a2], axis=0))
# ValueError: all the input arrays must have same number of dimensions

 
行列(2次元配列)にベクトル(1次元配列)を結合させるとエラーだが、
ベクトルを2次元で表記すると結合できる。

a1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
a2 = np.array([[10, 11, 12]])   # 2重の[[]]でベクトルを2次元で表記

print(np.concatenate([a1, a2], axis=0))
# [[ 1  2  3]
#  [ 4  5  6]
#  [ 7  8  9]
#  [10 11 12]]

print(np.concatenate([a1, a2.T], axis=1))
# [[ 1  2  3 10]
#  [ 4  5  6 11]
#  [ 7  8  9 12]]

 
・ベクトル(1次元配列)を行列(2次元配列)に変換する方法

# ndim=1 のベクトルを ndim=2の横ベクトルに変換
v1 = np.array([1, 2, 3])
v2 =np.reshape(v1, (1, v1.shape[0]))
print(v2.shape)  # (1, 3)
print(v2)        # [[1 2 3]]

# ndim=1 のベクトルを ndim=2の縦ベクトルに変換
v1 = np.array([1, 2, 3])
v3 =np.reshape(v1, (v1.shape[0], 1))
print(v3.shape)  # (3, 1)
print(v3)
# [[1]
#  [2]
#  [3]]

 
・shapeが異なっていても結合できるが、結合方向は揃える。

a1 = np.array([[1, 2, 3], [4, 5, 6]])
a2 = np.array([[7, 8, 9], [10, 11, 12], [13, 14, 15]])

print(np.concatenate([a1, a2], axis=0))
# [[ 1  2  3]
#  [ 4  5  6]
#  [ 7  8  9]
#  [10 11 12]
#  [13 14 15]]

#print(np.concatenate([a1, a2], axis=1))
# ValueError: all the input array dimensions except for the concatenation axis must match exactly

 

np.vstack(), np.hstack()、np.row_stack()、np.column_stack()、np.dstack()

 concatenate()は汎用で軸の指定をできるが、それぞれの軸に対応した関数もある。
 縦方向の結合:vstack()、row_stack()
 横方向の結合:hstack()、column_stack()
 深さ方向(axis=2)の結合:dstack()

a1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
a2 = np.array([[10, 11, 12]])   # 2重の[[]]でベクトルを2次元で表記

print(np.vstack([a1, a2]))
# [[ 1  2  3]
#  [ 4  5  6]
#  [ 7  8  9]
#  [10 11 12]]

print(np.hstack([a1, a2.T]))
# [[ 1  2  3 10]
#  [ 4  5  6 11]
#  [ 7  8  9 12]]

 
・dstack()の例

a1 = np.array([[1, 2, 3], [2, 3, 4]])
a2 = np.array([[5, 6, 7], [6, 7, 8]])

a1 = np.reshape(a1, (*a1.shape, 1))
a2 = np.reshape(a2, (*a2.shape, 1))

print(np.dstack([a1, a2]))   
# [[[1 5]
#   [2 6]
#   [3 7]]
#
#  [[2 6]
#   [3 7]
#   [4 8]]]

3次元配列って、思っていたのとかなり違う。
軸変換しないと脳内のイメージと全然あわないですね。
 
f:id:rare_Remrin:20170513132338p:plain
 
イメージしていたのはこれです。

a1 = np.array([[1, 2, 3], [2, 3, 4]])
a2 = np.array([[5, 6, 7], [6, 7, 8]])
a1 = np.reshape(a1, (1, *a1.shape))
a2 = np.reshape(a2, (1, *a2.shape))

print(a1)
# [[[1 2 3]
#   [2 3 4]]]

print(np.vstack([a1, a2]))   
# [[[1 2 3]
#   [2 3 4]]
#
#  [[5 6 7]
#   [6 7 8]]]

 

np.c_(), np.r_()

 concatenate()の代わりに使えて、スライスからも配列を生成できる。

a1 = np.arange(6).reshape(2, 3)
a2 = np.arange(100, 700, 100).reshape(2, 3)

print(np.r_[a1, a2])
# [[  0   1   2]
#  [  3   4   5]
#  [100 200 300]
#  [400 500 600]]

print(np.c_[a1, a2])
# [[  0   1   2 100 200 300]
#  [  3   4   5 400 500 600]]

print(np.c_[np.r_[a1, a2, a1], np.arange(6)])
# [[  0   1   2   0]
#  [  3   4   5   1]
#  [100 200 300   2]
#  [400 500 600   3]
#  [  0   1   2   4]
#  [  3   4   5   5]]


# スライスから配列を作れる
print(np.r_[:4, 10, 10, 4:0:-1])
# [ 0  1  2  3 10 10  4  3  2  1]

print(np.c_[:4, [10]*4, 4:0:-1])
# [[ 0 10  4]
#  [ 1 10  3]
#  [ 2 10  2]
#  [ 3 10  1]]

 

np.split()

 配列の分割。

a = np.arange(12).reshape(6, 2)
print(a)
# [[ 0  1]
#  [ 2  3]
#  [ 4  5]
#  [ 6  7]
#  [ 8  9]
#  [10 11]]

a1, a2, a3 =np.split(a, [1, 3]) #1行目と3行目の手前でsplit
print(a1)
# [[0 1]]

print(a2)
# [[2 3]
#  [4 5]]

print(a3)
# [[ 6  7]
#  [ 8  9]
#  [10 11]]

a1, a2 =np.split(a, 2, axis=0) # 2等分
print(a1)
# [[0 1]
#  [2 3]
#  [4 5]]
print(a2)
# [[ 6  7]
#  [ 8  9]
#  [10 11]]

a1, a2 =np.split(a, 2, axis=1) # 2等分
print(a1)
# [[ 0]
#  [ 2]
#  [ 4]
#  [ 6]
#  [ 8]
#  [10]]
print(a2)
# [[ 1]
#  [ 3]
#  [ 5]
#  [ 7]
#  [ 9]
#  [11]]

 
その他の分割関数

np.hsplit() hstackの逆
np.vsplit() vstackの逆
np.dsplit() dstackの逆