NumPyのデータ型dtype一覧とastypeによる変換(キャスト)
NumPy配列ndarrayはデータ型dtypeを保持しており、np.array()でndarrayオブジェクトを生成する際に指定したり、astype()メソッドで変換したりできる。
基本的には一つのndarrayオブジェクトに対して一つのdtypeが設定されていて、すべての要素が同じデータ型となる。
一つのndarrayで複数のデータ型を扱うためのStructured Data(構造化データ)という仕組みも用意されているが、ここでは触れない。複数の型を含むデータ(数値の列と文字列の列がある場合など)を処理するにはpandasが便利。
pandasのデータ型dtypeとastype()については以下の記事を参照。
本記事のサンプルコードの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_のように末尾に_が必要なので注意。
intやfloat, strのようなPythonの型を指定することもできる。この場合、等価なdtypeとして扱われる。Python3、64ビット環境での例は以下の通り。uintはPythonの型にはないが便宜上まとめて挙げておく。
| Pythonの型 | 等価なdtypeの例 |
|---|---|
int |
int64 |
float |
float64 |
str |
unicode |
(uint) |
uint64 |
引数で指定する場合はintやfloatでも文字列'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
先頭の<, >は、それぞれリトルエンディアン、ビッグエンディアンを表す。
末尾の数字は文字数を表し、この例のようにコンストラクタでdtypeにstrなどを指定した場合、要素の中で最大の文字数となる。
各要素に対してこの文字数分のメモリしか確保されていないので、それ以上の文字数の文字列は保持できず切り捨てられる。あらかじめ十分な文字数の型を指定しておく必要がある。
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配列ndarrayのastype()メソッドでデータ型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の型変換は行われない。
例えば、整数intのndarrayに浮動小数点数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