NumPyのデータ型dtype一覧とastypeによる変換(キャスト)

Modified: | Tags: Python, NumPy

NumPy配列ndarrayはデータ型dtypeを保持しており、np.array()ndarrayオブジェクトを生成する際に指定したり、astype()メソッドで変換したりできる。

基本的には一つのndarrayオブジェクトに対して一つのdtypeが設定されていて、すべての要素が同じデータ型となる。

一つのndarrayで複数のデータ型を扱うためのStructured Data(構造化データ)という仕組みも用意されているが、ここでは触れない。複数の型を含むデータ(数値の列と文字列の列がある場合など)を処理するにはpandasが便利。

pandasのデータ型dtypeastype()については以下の記事を参照。

本記事のサンプルコードのNumPyのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。

import numpy as np

print(np.__version__)
# 1.26.1

NumPyの主要なデータ型dtype一覧

NumPyの主要なデータ型dtypeは以下の通り。整数、浮動小数点数のそれぞれの型が取り得る値の範囲については後述。

データ型dtype 型コード 説明
int8 i1 符号あり8ビット整数型
int16 i2 符号あり16ビット整数型
int32 i4 符号あり32ビット整数型
int64 i8 符号あり64ビット整数型
uint8 u1 符号なし8ビット整数型
uint16 u2 符号なし16ビット整数型
uint32 u4 符号なし32ビット整数型
uint64 u8 符号なし64ビット整数型
float16 f2 半精度浮動小数点型(符号部1ビット、指数部5ビット、仮数部10ビット)
float32 f4 単精度浮動小数点型(符号部1ビット、指数部8ビット、仮数部23ビット)
float64 f8 倍精度浮動小数点型(符号部1ビット、指数部11ビット、仮数部52ビット)
float128 f16 四倍精度浮動小数点型(符号部1ビット、指数部15ビット、仮数部112ビット)
complex64 c8 複素数(実部・虚部がそれぞれfloat32
complex128 c16 複素数(実部・虚部がそれぞれfloat64
complex256 c32 複素数(実部・虚部がそれぞれfloat128
bool ? ブール型(True or False
unicode U Unicode文字列
object O Pythonオブジェクト型

データ型名の末尾の数字はビット(bit)で表し、型コード末尾の数字はバイト(Byte)で表す。同じ型でも値が違うので注意。

また、bool型の型コード?は不明という意味ではなく文字通り?が割り当てられている。

関数やメソッドの引数でデータ型dtypeを指定するとき、例えばint64型は以下の3通りで指定可能。

  • 型オブジェクト: np.int64
  • 型名の文字列: 'int64'
  • 型コードの文字列: 'i8'
a = np.array([1, 2, 3], dtype=np.int64)
print(a.dtype)
# int64

a = np.array([1, 2, 3], dtype='int64')
print(a.dtype)
# int64

a = np.array([1, 2, 3], dtype='i8')
print(a.dtype)
# int64

なお、bool, unicode, objectを型オブジェクトとして指定する場合はnp.bool_, np.unicode_, np.object_のように末尾に_が必要なので注意。

intfloat, strのようなPythonの型を指定することもできる。この場合、等価なdtypeとして扱われる。Python3、64ビット環境での例は以下の通り。uintはPythonの型にはないが便宜上まとめて挙げておく。

Pythonの型 等価なdtypeの例
int int64
float float64
str unicode
(uint) uint64

引数で指定する場合はintfloatでも文字列'int', 'float'でもよい。Pythonの型にはないuintは文字列'uint'のみ可。

a = np.array([1, 2, 3], dtype=int)
print(a.dtype)
# int64

a = np.array([1, 2, 3], dtype='int')
print(a.dtype)
# int64

数値型の取り得る範囲(最小値・最大値)の確認

整数int, uintや浮動小数点数floatの各データ型の取り得る値の範囲はnp.iinfo(), np.finfo()で確認できる。

np.iinfo()

整数int, uintに対してはnp.iinfo()を使う。

引数にデータ型を指定するとnumpy.iinfo型が返される。print()で概要を出力したり、max属性やmin属性などで最大値や最小値などを数値として取得できる。

以下の例ではnp.int64を指定しているが、'int64''i8'などの文字列も指定可能。

ii = np.iinfo(np.int64)
print(type(ii))
# <class 'numpy.iinfo'>

print(ii)
# Machine parameters for int64
# ---------------------------------------------------------------
# min = -9223372036854775808
# max = 9223372036854775807
# ---------------------------------------------------------------
# 

print(ii.max)
# 9223372036854775807

print(type(ii.max))
# <class 'int'>

print(ii.min)
# -9223372036854775808

print(ii.bits)
# 64

値そのものを引数に指定することもできる。

i = 100
print(type(i))
# <class 'int'>

print(np.iinfo(i))
# Machine parameters for int64
# ---------------------------------------------------------------
# min = -9223372036854775808
# max = 9223372036854775807
# ---------------------------------------------------------------
# 

ui = np.uint8(100)
print(type(ui))
# <class 'numpy.uint8'>

print(np.iinfo(ui))
# Machine parameters for uint8
# ---------------------------------------------------------------
# min = 0
# max = 255
# ---------------------------------------------------------------
# 

NumPy配列ndarrayは指定不可。dtype属性でデータ型を取得するか、要素を取得して指定する。

a = np.array([1, 2, 3], dtype=np.int8)
print(type(a))
# <class 'numpy.ndarray'>

# print(np.iinfo(a))
# ValueError: Invalid integer data type 'O'.

print(np.iinfo(a.dtype))
# Machine parameters for int8
# ---------------------------------------------------------------
# min = -128
# max = 127
# ---------------------------------------------------------------
# 

print(np.iinfo(a[0]))
# Machine parameters for int8
# ---------------------------------------------------------------
# min = -128
# max = 127
# ---------------------------------------------------------------
# 

np.finfo()

浮動小数点数floatにはnp.finfo()を使う。

使い方はnp.iinfo()と同じ。引数には型オブジェクト(np.float64)や文字列('float64', 'f8')、値(0.1)を指定可能。

print()で概要を出力したり、各属性の値を数値として取得したりできる。

fi = np.finfo(np.float64)
print(type(fi))
# <class 'numpy.finfo'>

print(fi)
# Machine parameters for float64
# ---------------------------------------------------------------
# precision =  15   resolution = 1.0000000000000001e-15
# machep =    -52   eps =        2.2204460492503131e-16
# negep =     -53   epsneg =     1.1102230246251565e-16
# minexp =  -1022   tiny =       2.2250738585072014e-308
# maxexp =   1024   max =        1.7976931348623157e+308
# nexp =       11   min =        -max
# smallest_normal = 2.2250738585072014e-308   smallest_subnormal = 4.9406564584124654e-324
# ---------------------------------------------------------------
# 

print(fi.max)
# 1.7976931348623157e+308

print(type(fi.max))
# <class 'numpy.float64'>

print(fi.min)
# -1.7976931348623157e+308

print(fi.eps)
# 2.220446049250313e-16

print(fi.bits)
# 64

print(fi.iexp)
# 11

print(fi.nmant)
# 52

上の例のように、np.iinfo()よりも多くの情報、例えば、epsでイプシロン、iexp, nmantで指数部および仮数部のビット数などが取得できる。詳細は上記の公式ドキュメントを参照。

文字列の文字数についての注意

要素を文字列として保持する場合、dtype<U3のようになる。

a_str = np.array([1, 22, 333], dtype=str)
print(a_str)
# ['1' '22' '333']

print(a_str.dtype)
# <U3

先頭の<, >は、それぞれリトルエンディアン、ビッグエンディアンを表す。

末尾の数字は文字数を表し、この例のようにコンストラクタでdtypestrなどを指定した場合、要素の中で最大の文字数となる。

各要素に対してこの文字数分のメモリしか確保されていないので、それ以上の文字数の文字列は保持できず切り捨てられる。あらかじめ十分な文字数の型を指定しておく必要がある。

a_str[0] = 'abcde'
print(a_str)
# ['abc' '22' '333']

a_str10 = np.array([1, 22, 333], dtype='U10')
print(a_str10.dtype)
# <U10

a_str10[0] = 'abcde'
print(a_str10)
# ['abcde' '22' '333']

object型: Pythonオブジェクトへのポインターを格納

object型は特殊なデータ型で、Pythonオブジェクトへのポインターを格納する。

各要素のデータの実体はそれぞれメモリ領域を確保するので、一つの配列ndarray内に異なる型のデータ(へのポインタ)をもつことができる。

a_object = np.array([1, 0.1, 'abc'], dtype=object)
print(a_object)
# [1 0.1 'abc']

print(a_object.dtype)
# object

print(type(a_object[0]))
print(type(a_object[1]))
print(type(a_object[2]))
# <class 'int'>
# <class 'float'>
# <class 'str'>

文字数の多い文字列への変更も可能。

a_object[2] = 'abcXYZ'
print(a_object)
# [1 0.1 'abcXYZ']

このような異なる型を持つ配列はPython組み込みのリストlist型でも表現できる。

listとNumPy配列ndarrayは演算子に対する振る舞いが異なり、ndarrayの場合は各要素に対する演算が簡単にできるが、あえてNumPyでこのようなデータを作成して処理する場面は少ないかもしれない。

l = [1, 0.1, 'abcXYZ']

print(type(l))
# <class 'list'>

print(type(l[0]))
print(type(l[1]))
print(type(l[2]))
# <class 'int'>
# <class 'float'>
# <class 'str'>

print(a_object * 2)
# [2 0.2 'abcXYZabcXYZ']

print(l * 2)
# [1, 0.1, 'abcXYZ', 1, 0.1, 'abcXYZ']

astype()によるデータ型dtypeの変換(キャスト)

astype()の基本的な使い方

NumPy配列ndarrayastype()メソッドでデータ型dtypeを変換(キャスト)できる。

dtypeが変更された新たなndarrayが生成され、元のndarrayは変化しない。

a = np.array([1, 2, 3])
print(a)
print(a.dtype)
# [1 2 3]
# int64

a_float = a.astype(np.float32)
print(a_float)
print(a_float.dtype)
# [1. 2. 3.]
# float32

print(a)
print(a.dtype)
# [1 2 3]
# int64

上述のように、dtypeは型名・型コードの文字列やPythonの型でも指定可能。

a_int = a.astype('int32')
print(a_int)
print(a_int.dtype)
# [1 2 3]
# int32

a_uint = a.astype('u8')
print(a_uint)
print(a_uint.dtype)
# [1 2 3]
# uint64

a_float = a.astype(float)
print(a_float)
print(a_float.dtype)
# [1. 2. 3.]
# float64

floatからintへの型変換は小数点以下切り捨て

浮動小数点数floatから整数intへの型変換は小数点以下切り捨て(0への丸め)となる。

a = np.array([-2, -1.5, -1, -0.5, 0.5, 1, 1.5, 2])

print(a.astype(int))
# [-2 -1 -1  0  0  1  1  2]

NumPyにおける四捨五入や小数点以下の切り捨て・切り上げについては以下の記事を参照。

暗黙の型変換

astype()による明示的な型変換だけでなく、演算によって暗黙の型変換が行われる場合がある。

例えば、/演算子による除算は、整数int同士でも浮動小数点数floatを返す。

a_int = np.array([1, 2, 3])
a_float = np.array([1.0, 2.0, 3.0])

print((a_int / a_int).dtype)
# float64

print((a_int / a_float).dtype)
# float64

+, -, *, //, **では、整数int同士の場合はint、浮動小数点数floatが含まれる場合はfloatとなる。

print((a_int + a_int).dtype)
# int64

print((a_int + a_float).dtype)
# float64

print((a_int - a_int).dtype)
# int64

print((a_int - a_float).dtype)
# float64

print((a_int * a_int).dtype)
# int64

print((a_int * a_float).dtype)
# float64

print((a_int // a_int).dtype)
# int64

print((a_int // a_float).dtype)
# float64

print((a_int**a_int).dtype)
# int64

print((a_int**a_float).dtype)
# float64

整数int同士や浮動小数点数float同士でも、ビット数が異なる場合はビット数の大きい方の型に合わせて変換される。

a_int16 = np.array([1, 2, 3], np.int16)
a_int32 = np.array([1, 2, 3], np.int32)

print((a_int16 + a_int32).dtype)
# int32

a_float16 = np.array([1, 2, 3], np.float16)
a_float32 = np.array([1, 2, 3], np.float32)

print((a_float16 + a_float32).dtype)
# float32

ただし、場合によっては、元のndarrayのどちらとも異なる型になることがある。ビット数が重要な処理ではastype()で明示的に所望の型に変換しておいたほうが安心だろう。

print((a_int16 + a_float16).dtype)
# float32

print((a_int32 + a_float32).dtype)
# float64

なお、要素への値の代入ではndarrayの型変換は行われない。

例えば、整数intndarrayに浮動小数点数floatの値を代入しても、ndarrayのデータ型はintのまま。代入した値は小数点以下切り捨て(0への丸め)となる。

a_int[0] = 10.9
a_int[1] = -20.9
print(a_int)
# [ 10 -20   3]

print(a_int.dtype)
# int64

関連カテゴリー

関連記事