NumPy 配列の形状変更とサイズ変更
NumPy には、配列の形状を変更するための 2つの関数(およびメソッド)があります reshape
と resize
です。これらには大きな違いがあるため、この章で説明します。
numpy.reshape()
配列の形状を変更する関数 reshape()
から始めましょう。
import numpy as np
arrayA = np.arange(8)
# arrayA = array([0, 1, 2, 3, 4, 5, 6, 7])
np.reshape(arrayA, (2, 4))
# array([[0, 1, 2, 3],
# [4, 5, 6, 7]])
8 要素のベクトルを (4, 2)
の形状の配列に変換します。形状変更の前後の要素の量が同じであるため、正常に実行できます。数値が異なる場合、ValueError
エラーがトリガーされます。
In[1]: np.reshape(arrayA, (3, 4))
---------------------------------------------------------------------------
ValueError Traceback(most recent call last)
ValueError: cannot reshape array of size 8 into shape(3, 4)
再形成された配列を詳しく見てみましょう。最初の行は arrayA
の最初の 4つのデータであり、2 番目の行は最後の 4 を取ります。この形状変換では、行の順序でデータを充填します。
データを充填する順序を列にする場合は、パラメーター order
を変更する必要があります。
In[1]: np.reshape(arrayA, (2, 4), order="F")
Out[1]: array([[0, 2, 4, 6], [1, 3, 5, 7]])
order
のデフォルトは C
です。これは、C
のようなインデックス順、または単純な単語で、行の順序でデータを読み書きすることを意味します。F
は、Fortan
のようなインデックス順で、または column
の順序でデータを読み書きすることを意味します。さまざまなインデックス方法の詳細については、NumPy の公式ドキュメント を参照してください。
ndarray.reshape()
reshape
関数に加えて、行列形状の変化はデータ darray
オブジェクト内の reshpe
方法で行うことができます。メソッドには関数と同じパラメーターがありますが、パラメーターとして指定された配列はありません。
In[1]: arrayB = arrayA.reshape((2, 4))
In[2]: arrayB
Out[2]: array([[0, 1, 2, 3], [4, 5, 6, 7]])
In[1]: arrayA
Out[2]: array([0, 1, 2, 3, 4, 5, 6, 7])
使い方は rehape
関数と似ていると見られます。また、ndarray.reshape()
メソッドは元の配列のデータと形状を変更せず、新しい ndarray
インスタンスを返すことにも注意する必要があります。
reshape()
関数/メソッド共有メモリ
reshape
関数またはメソッドで変換された配列は、元の配列と同じメモリを共有します。Python の shallow copy
ように考えることができます。1つの配列のデータを変更すると、他の配列の対応するデータも変更されます。
In [1]: arrayA = np.arange(8)
arrayB = arrayA.reshape((2, 4))
arrayB
Out[2]: array([[0, 1, 2, 3],
[4, 5, 6, 7]])
In [2]: arrayA[0] = 10
arrayA
Out[2]: array([10, 1, 2, 3, 4, 5, 6, 7])
In [3]: arrayB
Out[3]: array([[10, 1, 2, 3],
[4, 5, 6, 7]])
numpy.resize()
numpy.resize()
は、形状変換の意味で、reshape
に少し似ています。ただし、いくつかの重要な違いがあります。
order
パラメーターがありません。resize
の順序はreshape
のorder='C'
と同じです。- ターゲット配列の要素数が元の配列と同じでない場合、サイズ変更を強制しますが、エラーは発生しません。
具体的に 2 番目の違いを見に行きます。
In [1]: arrayA = np.arange(8)
arrayB = np.resize(arrayA, (2, 4))
Out[1]: array([[0, 1, 2, 3],
[4, 5, 6, 7]])
要素番号が同じ場合、結果は reshpae
の結果と同じです。
In [1]: arrayC = np.resize(arrayA, (3, 4))
arrayC
Out[1]: array([[0, 1, 2, 3],
[4, 5, 6, 7],
[0, 1, 2, 3]])
In [2]: arrayD = np.resize(arrayA, (4, 4))
arrayD
Out[2]: array([[0, 1, 2, 3],
[4, 5, 6, 7],
[0, 1, 2, 3],
[4, 5, 6, 7]])
新しい配列にさらに行がある場合、元の配列のデータを繰り返しますが、エラーは発生しません。
In [1]: arrayE = np.resize(arrayA, (2, 2))
arrayE
Out[1]: array([[0, 1],
[2, 3]])
In [2]: np.resize(arrayA, (1,4))
Out[2]: array([[0, 1, 2, 3]])
新しい配列の要素の数が少ない場合、元の行列から必要な個数のデータを読み出して、先に行を充填して新しい行列要素に値を付けます。
resize
関数/メソッドのメモリ
新しい配列は、resize
関数/メソッドの元の配列と同じメモリを共有しません。1つの配列のデータ変更は、他の配列にマップされません。
In [1]: arrayA = np.arange(8)
arrayB = arrayA.reshape((2, 4))
arrayB
Out[2]: array([[0, 1, 2, 3],
[4, 5, 6, 7]])
In [2]: arrayA[0] = 10
arrayA
Out[2]: array([10, 1, 2, 3, 4, 5, 6, 7])
In [3]: arrayB
Out[3]: array([[0, 1, 2, 3],
[4, 5, 6, 7]])