dtypeはNumPyの配列(ndarray)の属性の1つで、配列の要素のデータ型を保持しています。
ここでは、どのようなdtypeが存在するのかの一覧と、dtypeの参照・指定・変更方法を解説していきます。
1. NumPyのdtypeの参照・指定・変更
dtypeはndarrayの要素のデータ型を保持しています。これを参照するには、以下のようにndarray.dtypeと書きます。
なおdtypeは、numpy.ndarrayクラスのインスタンス変数です。クラスやインスタンス変数については、『【Python】オブジェクト指向プログラミングの概念と書き方』や『Pythonでのクラス(class)の使い方』で解説していますので、目を通してみてください。
書き方:
ndarray.dtype
一緒に確認したい属性と関数:
- ndarray.shape: 配列の形状を保持する属性
- ndarray.size: 配列の要素数を保持する属性
- ndarray.astype: 配列のデータ型を変換
それでは詳しく見ていきましょう。
1.1. 配列のdtypeを参照する
まずは配列のdtypeを参照してみましょう。
以下のコードをご覧ください。配列の要素が整数(int型)なので、dtypeはint型です。
import numpy as np
# 要素が整数の配列
arr1 = np.array([1, 2, 3])
arr1.dtype
intの後に64という数字が入っていますが、これはビット数を表します。これについては後ほど解説します。
要素が浮動小数点数なら、dtypeの属性はfloat型です。
# 要素が浮動小数点数の配列
arr2 = np.array([0.1, 0.2, 0.3])
arr2.dtype
要素がブール値なら、dtype属性はbool型です。
# 要素がブール値の配列
arr3 = np.array([True, False])
arr3.dtype
要素が文字列なら、dtype属性はunicode型(文字列型)です。
# 要素が文字列の配列
arr4 = np.array(['python', 'numpy'])
arr4.dtype
文字列の場合は、上のように、ユニコードを意味するUと、リトルエンディアンの < が表示されます。数字は要素の中の最長の文字列の長さを表します。この例では’python’が6文字なので、その数字が表示されています。
なお、numpyの配列は基本的に、1つの配列の中に異なるデータ型は共存できません。
例えば、以下のコードでは、numpy.arrayで配列を生成する際に、float型、文字列型、int型のデータを渡しています。そして、生成された配列を見てみると、配列全体のdtypeは文字列型になっています。
''' 通常、1つの配列に異なるデータ型は共存できない '''
# 例えば、float、文字列、intが混在しているとdtypeは文字列型になる。
np.array([0.9, 'str', 1])
このようにNumPyの配列では、基本的に1つのndarrayには1つのデータ型しか存在しません。
ただし、例外として、構造化配列といって、異なるデータ型を格納できるものもあります。これについては後述します。
1.2. dtype(データ型)の種類の一覧
さて、ここまで見てきたように、ndarrayのdtype属性は配列のデータ型を保持しています。
それでは、配列のデータ型にはどのようなものがあるのでしょうか。それを表にしたものが以下です(型コードについては、配列生成時の型指定のところで触れます)。
データ型 | 説明 | 型コード |
int | 符号ありの整数型(8, 16, 32, 64ビット) | i1, i2, i4, i8 |
unit | 符号なしの整数型(8, 16, 32, 64ビット) | u1, u2, u4, u8 |
float | 浮動小数点数型(16, 32, 64, 128ビット) | f2, f4, f8, f16 |
complex | 複素数型(64, 128, 156ビット) | c8, c16, c32 |
bool | ブール型( True or False) | ? |
Unicode | Unicode文字列 | U |
object | Pythonオブジェクト | O |
int型やfloat型にはビットの異なるものがあります。int8の型コードはi1、float32の型コードはf8というように対応しています。
ビット数についても解説しておきましょう。
ビット数は簡潔に言うとデータのサイズです。ビット数が大きくなるほど、データのサイズが大きくなります。そのため、ビットが小さなデータを使って処理した方が高速になります。
例えば、float64とfloat32の場合の、計算の処理速度を見てみましょう。
まず、float64の場合です。
import numpy as np
arr1 = np.zeros(100000, dtype=np.float64)
%timeit arr1*arr1
次に、float32の場合です。
arr2 = np.zeros(100000, dtype=np.float32)
%timeit arr2 * arr2
全く同じ処理をしていますが、float64では平均40.5マイクロ秒に対して、float32では平均22.5マイクロ秒と倍近い違いがあります。
ただし、このようなデータ型の細かいことについて、必ずしも知っておかなければいけないのか、小さなビット数のデータ型を使わなければいけないのか、というと決してそうではありません。どちらかというと、そうした必要性はほとんどないと言っても良いでしょう。
むしろ、サイズが小さいからと言って、ビットサイズの小さなものを使っていると、本当に思わぬところで、数値の丸め方の違いによる誤差が起きます。そのため、本当に必要だと確信できる場合以外は、通常のPython3環境である、int64, float64, complex128を使うようにしましょう。
1.3. 配列生成時にdtypeを指定する
numpy.arrayなどの関数で配列を生成する時に、dtypeを指定することができます。dtypeを指定する時にはいくつかの書き方があります。
例えば、int型を指定する場合は、
- int
- np.int
- ‘int’(文字列型)
のいずれの書き方でも可能です。
以下のコードでご確認ください。
''' 以下のどの書き方でも可能です。'''
import numpy as np
# intと書く
arr = np.array([1, 2, 3], dtype=int)
# 文字列で書く
arr = np.array([1, 2, 3], dtype='int')
# np.int
arr = np.array([1, 2, 3], dtype=np.int)
print(arr)
print(arr.dtype)
Python3の通常環境ではint型は64ビットなので、int64の要素の配列になります。
float型やcomplex型など、他の型を指定する場合も同様です。
''' float型を指定する場合も同様です。 '''
# floatと書く
arr = np.arange(5, dtype=float)
# 文字列で書く
arr = np.arange(5, dtype='float')
# np.floatと書く
arr = np.arange(5, dtype=np.float)
print(arr)
print(arr.dtype)
Python3の通常環境では、float型も64ビットです。complex型は128ビットです。
int32やfloat8などの、Python3標準以外のビット数を指定したい場合は、np.○○、もしくは文字列型で’float32’というように渡します。
''' ビット数を指定する場合 '''
# np.int32やfloat32と書く
arr1 = np.array([1, 2, 3], dtype=np.int32)
print(arr1)
print(arr1.dtype, '\n')
arr2 = np.array([1, 2, 3], dtype='float32')
print(arr2)
print(arr2.dtype)
以下のように、型コードで渡すことも可能です。型コードで指定する際も、’ ‘ で囲って文字列型で渡します。
''' 型コードで指定することも可能です。 '''
arr3 = np.arange(5, dtype='i2')
print(arr3)
print(arr3.dtype, '\n')
arr4 = np.arange(5, dtype='f2')
print(arr4)
print(arr4.dtype)
文字列型を指定する場合は、strや’U’と書きます。
''' 文字列型に指定する場合 '''
# strと指定する
arr5 = np.array([1, 2, 3], dtype=str)
print(arr5)
print(arr5.dtype, '\n')
# 'U'と指定する
arr6 = np.array([1, 2, 3], dtype='U')
print(arr6)
print(arr6.dtype, '\n')
# 配列内の最長文字数を指定する
arr10 = np.array([1, 2, 3], dtype='U3')
print(arr10)
print(arr10.dtype)
上の方でも少し触れましたが、Uの先頭に付いている、< や > はリトルエンディアン、ビッグエンディアンと言います。
例えば、<U3 なら、配列の要素は最大3文字ということを表します。そして、配列生成時に「dtype=’U3’」と指定すると、1つの要素に対して最大3文字分のメモリを確保することになるため、これを超える文字列は切り捨てられます。
もし文字列を指定する場合は、その配列に追加する可能性のある文字列の長さを考えて、十分な長さを確保しましょう。
1.4. ndarray.astypeでdtypeを変更する
なお、既存の配列のdtypeを変更するには、ndarray.astypeを使います。このメソッドは、元の配列を変更するのではなく、dtypeを変更した新しい配列を生成します。
これは『numpy.ndarray.astype – 配列のデータ型を変更』で、詳しく解説しているのであわせてご確認ください。
それでは、以下のint型の配列を例に、実際のコードで見てみましょう。
import numpy as np
arr = np.array([1, 2, 3])
print(arr)
print(arr.dtype)
これをfloat型に変換するには、次のように指定します。配列の生成の際にdtypeを指定する時と同じで、引数の書き方は、複数の方法があります。
''' astype()でdtypeをfloatに変換 '''
# 直接指定
arr_f = arr.astype(float)
# np.folatで指定
arr_f = arr.astype(np.float)
# 文字列型で指定
arr_f = arr.astype('float')
# 型コードで指定
arr_f = arr.astype('f8')
print(arr_f)
print(arr_f.dtype)
Python3標準のビット数以外に変更する時は、以下の3つの方法のいずれかで書かなければいけない点も、配列生成時のdtype指定と同じです。
''' ビット数も変更する場合は以下の書き方で '''
# np.○○を渡す
arr_f2 = arr.astype(np.float32)
# 文字列型を渡す
arr_f2 = arr.astype('float32')
# 型コードを渡す
arr_f2 = arr.astype('f4')
print(arr_f2)
print(arr_f2.dtype)
なお、ndarray.astypeの注意点として以下の2つをおさえておきましょう。
- float型をint型に変換すると小数点以下は切り捨て(四捨五入ではない)。
- complex型からint型、float型に変換するとエラーになる。
これらについては『numpy.ndarray.astype – 配列のデータ型を変更』で解説しているので確認しておくと良いでしょう。
2. 構造化配列(Structured Array)の生成
さて、ここまで見てきたようにNumPyの配列は、通常は異なるデータ型は共存できません。1つの配列には1つのデータ型です。
しかし、NumPyの配列には、構造化配列(Structured Array)というものがあります。そして、構造化配列では1つの配列に複数のデータ型が共存することができます。
以下のコードをご覧ください。
''' 構造化配列(Structured Array)では異なるデータ型が共存できる '''
np.array( [('山田', 178.5, 28), ('佐藤', 183.2, 24)], \
dtype=([('name', 'U2'), ('height', float), ('age', int)]))
numpy.arrayで配列を生成しているのですが、タプルの中に3つの値をカンマ区切りで入力しています。そして、オプション引数のdtypeで、タプルの中のデータのフィールドとデータ型を1つずつ指定しています。
つまり、タプルの中の最初の要素は、’name’フィールドで文字列型データが入る、2番目の要素は’height’フィールドでfloat型データが入る、3番目の要素は’age’フィールドでint型データが入るようになっています。
構造化配列では、様々な操作を行うことができます。
まず、以下のコードで、この構造化配列を変数arrに代入します。
arr = np.array( [('山田', 178.5, 28), ('佐藤', 183.2, 24)], \
dtype=([('name', 'U2'), ('height', float), ('age', int)]))
各データフィールドでスライスすると、指定のデータフィールドの値を参照することができます。
# nameデータを確認
arr['name']
# heightデータを確認
arr['height']
# ageデータを確認
arr['age']
こうしてデータフィールドで値のdtypeを指定しているので、例えば、numpy.sortでソートする時に、指定のデータフィールドを基準にソートするということが可能になります。
# データフィールドを指定してソート
np.sort(arr, order='age')
3. まとめ
以上がNumPy配列のdtype属性です。
最後にポイントをまとめておきましょう。
- dtype属性はNumPy配列(ndarray)の要素の型を保持しているインスタンス変数。
- 原則として1つの配列には1つのdtype。
- 配列のdtypeを参照するには「nderray.dtype」と書く。
- 配列を生成する時にdtypeを指定することができる。
- ndarray.astypeで既存の配列のdtypeを変更することができる。
- 構造化配列といって複数のdtypeが混在する配列を生成することもできる。
ぜひ、参考にして頂ければと思います。
また、NumPyのndarrayの属性としてよく使うものは他に、次の2つがあります。
- ndarray.shape: 配列の形状を保持する属性
- ndarray.size: 配列の要素数を保持する属性
これらも併せて確認しておくと良いでしょう。
コメント