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