NumPyのdtype属性の一覧と参照・指定・変更方法

dtypeはNumPyの配列(ndarray)の属性の1つで、配列の要素のデータ型を保持しています。

ここでは、どのようなdtypeが存在するのかの一覧と、dtypeの参照・指定・変更方法を解説していきます。

目次

1. NumPyのdtypeの参照・指定・変更

dtypeはndarrayの要素のデータ型を保持しています。これを参照するには、以下のようにndarray.dtypeと書きます。

なおdtypeは、numpy.ndarrayクラスのインスタンス変数です。クラスやインスタンス変数については、『【Python】オブジェクト指向プログラミングの概念と書き方』や『Pythonでのクラス(class)の使い方』で解説していますので、目を通してみてください。

numpy.ndarray.dtype

書き方:

ndarray.dtype

一緒に確認したい属性と関数:

それでは詳しく見ていきましょう。

1.1. 配列のdtypeを参照する

まずは配列のdtypeを参照してみましょう。

以下のコードをご覧ください。配列の要素が整数(int型)なので、dtypeはint型です。

In [1]:
import numpy as np
#  要素が整数の配列
arr1 = np.array([1, 2, 3])
arr1.dtype
Out[1]:
dtype('int64')

intの後に64という数字が入っていますが、これはビット数を表します。これについては後ほど解説します。

要素が浮動小数点数なら、dtypeの属性はfloat型です。

In [2]:
#  要素が浮動小数点数の配列
arr2 = np.array([0.1, 0.2, 0.3])
arr2.dtype
Out[2]:
dtype('float64')

要素がブール値なら、dtype属性はbool型です。

In [3]:
#  要素がブール値の配列
arr3 = np.array([True, False])
arr3.dtype
Out[3]:
dtype('bool')

要素が文字列なら、dtype属性はunicode型(文字列型)です。

In [4]:
#  要素が文字列の配列
arr4 = np.array(['python', 'numpy'])
arr4.dtype
Out[4]:
dtype('<U6')

文字列の場合は、上のように、ユニコードを意味するUと、リトルエンディアンの < が表示されます。数字は要素の中の最長の文字列の長さを表します。この例では’python’が6文字なので、その数字が表示されています。

なお、numpyの配列は基本的に、1つの配列の中に異なるデータ型は共存できません。

例えば、以下のコードでは、numpy.arrayで配列を生成する際に、float型、文字列型、int型のデータを渡しています。そして、生成された配列を見てみると、配列全体のdtypeは文字列型になっています。

In [5]:
'''  通常、1つの配列に異なるデータ型は共存できない  '''
#  例えば、float、文字列、intが混在しているとdtypeは文字列型になる。
np.array([0.9, 'str', 1])
Out[5]:
array(['0.9', 'str', '1'], dtype='<U32')

このように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)?
UnicodeUnicode文字列U
objectPythonオブジェクトO

int型やfloat型にはビットの異なるものがあります。int8の型コードはi1、float32の型コードはf8というように対応しています。

ビット数についても解説しておきましょう。

ビット数は簡潔に言うとデータのサイズです。ビット数が大きくなるほど、データのサイズが大きくなります。そのため、ビットが小さなデータを使って処理した方が高速になります。

例えば、float64とfloat32の場合の、計算の処理速度を見てみましょう。

まず、float64の場合です。

In [1]:
import numpy as np
arr1 = np.zeros(100000, dtype=np.float64)
%timeit arr1*arr1
40.5 µs ± 741 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

次に、float32の場合です。

In [2]:
arr2 = np.zeros(100000, dtype=np.float32)
%timeit arr2 * arr2
22.5 µs ± 192 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

全く同じ処理をしていますが、float64では平均40.5マイクロ秒に対して、float32では平均22.5マイクロ秒と倍近い違いがあります。

ただし、このようなデータ型の細かいことについて、必ずしも知っておかなければいけないのか、小さなビット数のデータ型を使わなければいけないのか、というと決してそうではありません。どちらかというと、そうした必要性はほとんどないと言っても良いでしょう。

むしろ、サイズが小さいからと言って、ビットサイズの小さなものを使っていると、本当に思わぬところで、数値の丸め方の違いによる誤差が起きます。そのため、本当に必要だと確信できる場合以外は、通常のPython3環境である、int64, float64, complex128を使うようにしましょう。

1.3. 配列生成時にdtypeを指定する

numpy.arrayなどの関数で配列を生成する時に、dtypeを指定することができます。dtypeを指定する時にはいくつかの書き方があります。

例えば、int型を指定する場合は、

  • int
  • np.int
  • ‘int’(文字列型)

のいずれの書き方でも可能です。

以下のコードでご確認ください。

In [1]:
'''  以下のどの書き方でも可能です。'''

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)
[1 2 3]
int64

Python3の通常環境ではint型は64ビットなので、int64の要素の配列になります。

float型やcomplex型など、他の型を指定する場合も同様です。

In [2]:
'''  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)
[0. 1. 2. 3. 4.]
float64

Python3の通常環境では、float型も64ビットです。complex型は128ビットです。

int32やfloat8などの、Python3標準以外のビット数を指定したい場合は、np.○○、もしくは文字列型で’float32’というように渡します。

In [3]:
'''  ビット数を指定する場合  '''

#  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)
[1 2 3]
int32 

[1. 2. 3.]
float32

以下のように、型コードで渡すことも可能です。型コードで指定する際も、’ ‘ で囲って文字列型で渡します。

In [4]:
'''  型コードで指定することも可能です。  '''

arr3 = np.arange(5, dtype='i2')
print(arr3)
print(arr3.dtype, '\n')

arr4 = np.arange(5, dtype='f2')
print(arr4)
print(arr4.dtype)
[0 1 2 3 4]
int16 

[0. 1. 2. 3. 4.]
float16

文字列型を指定する場合は、strや’U’と書きます。

In [5]:
'''  文字列型に指定する場合  '''

#  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)
['1' '2' '3']
<U1 

['1' '2' '3']
<U1 

['1' '2' '3']
<U3

上の方でも少し触れましたが、Uの先頭に付いている、< や > はリトルエンディアン、ビッグエンディアンと言います。

例えば、<U3 なら、配列の要素は最大3文字ということを表します。そして、配列生成時に「dtype=’U3’」と指定すると、1つの要素に対して最大3文字分のメモリを確保することになるため、これを超える文字列は切り捨てられます。

もし文字列を指定する場合は、その配列に追加する可能性のある文字列の長さを考えて、十分な長さを確保しましょう。

1.4. ndarray.astypeでdtypeを変更する

なお、既存の配列のdtypeを変更するには、ndarray.astypeを使います。このメソッドは、元の配列を変更するのではなく、dtypeを変更した新しい配列を生成します。

これは『numpy.ndarray.astype – 配列のデータ型を変更』で、詳しく解説しているのであわせてご確認ください。

それでは、以下のint型の配列を例に、実際のコードで見てみましょう。

In [1]:
import numpy as np
arr = np.array([1, 2, 3])
print(arr)
print(arr.dtype)
[1 2 3]
int64

これをfloat型に変換するには、次のように指定します。配列の生成の際にdtypeを指定する時と同じで、引数の書き方は、複数の方法があります。

In [2]:
'''  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)
[1. 2. 3.]
float64

Python3標準のビット数以外に変更する時は、以下の3つの方法のいずれかで書かなければいけない点も、配列生成時のdtype指定と同じです。

In [3]:
'''  ビット数も変更する場合は以下の書き方で  '''

#  np.○○を渡す
arr_f2 = arr.astype(np.float32)
#  文字列型を渡す
arr_f2 = arr.astype('float32')
#  型コードを渡す
arr_f2 = arr.astype('f4')

print(arr_f2)
print(arr_f2.dtype)
[1. 2. 3.]
float32

なお、ndarray.astypeの注意点として以下の2つをおさえておきましょう。

  • float型をint型に変換すると小数点以下は切り捨て(四捨五入ではない)。
  • complex型からint型、float型に変換するとエラーになる。

これらについては『numpy.ndarray.astype – 配列のデータ型を変更』で解説しているので確認しておくと良いでしょう。

2. 構造化配列(Structured Array)の生成

さて、ここまで見てきたようにNumPyの配列は、通常は異なるデータ型は共存できません。1つの配列には1つのデータ型です。

しかし、NumPyの配列には、構造化配列(Structured Array)というものがあります。そして、構造化配列では1つの配列に複数のデータ型が共存することができます。

以下のコードをご覧ください。

In [1]:
'''  構造化配列(Structured Array)では異なるデータ型が共存できる  '''
np.array( [('山田', 178.5, 28), ('佐藤', 183.2, 24)], \
         dtype=([('name', 'U2'), ('height', float), ('age', int)]))
Out[1]:
array([('山田', 178.5, 28), ('佐藤', 183.2, 24)],
      dtype=[('name', '<U2'), ('height', '<f8'), ('age', '<i8')])

numpy.arrayで配列を生成しているのですが、タプルの中に3つの値をカンマ区切りで入力しています。そして、オプション引数のdtypeで、タプルの中のデータのフィールドとデータ型を1つずつ指定しています。

つまり、タプルの中の最初の要素は、’name’フィールドで文字列型データが入る、2番目の要素は’height’フィールドでfloat型データが入る、3番目の要素は’age’フィールドでint型データが入るようになっています。

構造化配列では、様々な操作を行うことができます。

まず、以下のコードで、この構造化配列を変数arrに代入します。

In [2]:
arr = np.array( [('山田', 178.5, 28), ('佐藤', 183.2, 24)], \
         dtype=([('name', 'U2'), ('height', float), ('age', int)]))

各データフィールドでスライスすると、指定のデータフィールドの値を参照することができます。

In [3]:
#  nameデータを確認
arr['name']
Out[3]:
array(['山田', '佐藤'], dtype='<U2')
In [4]:
#  heightデータを確認
arr['height']
Out[4]:
array([178.5, 183.2])
In [5]:
#  ageデータを確認
arr['age']
Out[5]:
array([28, 24])

こうしてデータフィールドで値のdtypeを指定しているので、例えば、numpy.sortでソートする時に、指定のデータフィールドを基準にソートするということが可能になります。

In [6]:
#  データフィールドを指定してソート
np.sort(arr, order='age')
Out[6]:
array([('佐藤', 183.2, 24), ('山田', 178.5, 28)],
      dtype=[('name', '<U2'), ('height', '<f8'), ('age', '<i8')])

3. まとめ

以上がNumPy配列のdtype属性です。

最後にポイントをまとめておきましょう。

  • dtype属性はNumPy配列(ndarray)の要素の型を保持しているインスタンス変数。
  • 原則として1つの配列には1つのdtype。
  • 配列のdtypeを参照するには「nderray.dtype」と書く。
  • 配列を生成する時にdtypeを指定することができる。
  • ndarray.astypeで既存の配列のdtypeを変更することができる。
  • 構造化配列といって複数のdtypeが混在する配列を生成することもできる。

ぜひ、参考にして頂ければと思います。

また、NumPyのndarrayの属性としてよく使うものは他に、次の2つがあります。

これらも併せて確認しておくと良いでしょう。



よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

目次
閉じる