pandasのデータ型dtype一覧とastypeによる変換(キャスト)
pandas.Series
は一つのデータ型dtype
、pandas.DataFrame
は列ごとにそれぞれデータ型dtype
を保持している。
dtype
は、コンストラクタで新たにオブジェクトを生成する際やCSVファイルなどから読み込む際に指定できる。また、astype()
メソッドで型変換(キャスト)することも可能。
データ型dtype
によって列を抽出する方法は以下の記事を参照。
NumPyのデータ型dtype
とastype()
については以下の記事を参照。
本記事のサンプルコードのpandasは2.0.3
。バージョンによっては挙動が異なる場合があるので注意。NumPyもインポートしておく。
import pandas as pd
import numpy as np
print(pd.__version__)
# 2.0.3
pandasの主要なデータ型dtype一覧
pandasの主要なデータ型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 ) |
object |
O |
Pythonオブジェクト型 |
データ型名の末尾の数字はビット(bit)で表し、型コード末尾の数字はバイト(Byte)で表す。同じ型でも値が違うので注意。
bool
型の型コード?
は不明という意味ではなく文字通り?
が割り当てられている。
日時を表すdatetime64
型については以下の記事を参照。
関数やメソッドの引数でデータ型dtype
を指定するとき、例えばfloat64
型は以下の3通りで指定可能。
- 型オブジェクト:
np.float64
- 型名の文字列:
'float64'
- 型コードの文字列:
'f8'
s = pd.Series([0, 1, 2], dtype=np.float64)
print(s.dtype)
# float64
s = pd.Series([0, 1, 2], dtype='float64')
print(s.dtype)
# float64
s = pd.Series([0, 1, 2], dtype='f8')
print(s.dtype)
# float64
int
やfloat
, str
のようなPythonの型を指定することもできる。この場合、等価なdtype
に自動的に変換される。Python3、64ビット環境での例は以下の通り。uint
はPythonの型にはないが便宜上まとめて挙げておく。
Pythonの型 | 等価なdtype の例 |
---|---|
int |
int64 |
float |
float64 |
str |
object (各要素がstr 型) |
(uint ) |
uint64 |
引数で指定する場合はint
やfloat
でも文字列'int'
, 'float'
でもよい。Pythonの型にはないuint
は文字列'uint'
のみ可。
s = pd.Series([0, 1, 2], dtype='float')
print(s.dtype)
# float64
s = pd.Series([0, 1, 2], dtype=float)
print(s.dtype)
# float64
s = pd.Series([0, 1, 2], dtype='uint')
print(s.dtype)
# uint64
整数、浮動小数点数においてそれぞれの型が取り得る値の範囲(最小値・最大値)はnp.iinfo()
, np.finfo()
で確認できる。詳細は以下の記事を参照。
なお、上のデータ型一覧は基本的にNumPyに準じたものだが、pandasが独自に拡張したデータ型もある。
object型と文字列
ここでは文字列str
型とobject
型について説明する。
なお、pandasバージョン1.0.0
から文字列のためのデータ型としてStringDtype
が導入された。今後はこちらが主流になる可能性があるが、ここでは触れない。詳細は公式ドキュメントを参照。
特殊なデータ型であるobject
object
型は特殊なデータ型で、Pythonオブジェクトへのポインターを格納する。各要素のデータはそれぞれ別の型を持つ場合がある。
pandasでは文字列を含むSeries
やDataFrame
の列はobject
型となるが、各要素はそれぞれの型を持っており、すべての要素が文字列str
型とは限らない。
以下に例を示す。ここではmap()
メソッドで各要素に組み込み関数type()
を適用して型を確認している。np.nan
は欠損値を表す。
- 関連記事: pandasで要素・行・列に関数を適用するmap, apply, applymap
- 関連記事: Pythonで型を取得・判定するtype関数, isinstance関数
- 関連記事: pandasにおける欠損値(nan, None, pd.NA)
s_object = pd.Series([0, 'abcde', np.nan])
print(s_object)
# 0 0
# 1 abcde
# 2 NaN
# dtype: object
print(s_object.map(type))
# 0 <class 'int'>
# 1 <class 'str'>
# 2 <class 'float'>
# dtype: object
astype()
による型変換(詳細は後述)でstr
を指定すると、NaN
を含むすべての要素がstr
型に変換される。この場合も、dtype
はobject
のまま。
s_str_astype = s_object.astype(str)
print(s_str_astype)
# 0 0
# 1 abcde
# 2 nan
# dtype: object
print(s_str_astype.map(type))
# 0 <class 'str'>
# 1 <class 'str'>
# 2 <class 'str'>
# dtype: object
コンストラクタでdtype
にstr
を指定した場合、NaN
はfloat
のまま。なお、これはバージョン2.0.3
での挙動であり、0.22.0
ではNaN
もstr
に変換されていた。
s_str_constructor = pd.Series([0, 'abcde', np.nan], dtype=str)
print(s_str_constructor)
# 0 0
# 1 abcde
# 2 NaN
# dtype: object
print(s_str_constructor.map(type))
# 0 <class 'str'>
# 1 <class 'str'>
# 2 <class 'float'>
# dtype: object
注意: 文字列メソッド
dtype
が同じobject
型でも、要素の型によってstrアクセサによる文字列メソッドの結果が異なるので注意。
例えば文字列の文字数を返すstr.len()
を適用すると、数値型の要素はNaN
を返す。
s_object = pd.Series([0, 'abcde', np.nan])
print(s_object)
# 0 0
# 1 abcde
# 2 NaN
# dtype: object
print(s_object.str.len())
# 0 NaN
# 1 5.0
# 2 NaN
# dtype: float64
文字列メソッドの結果にNaN
が含まれている場合は列のデータ型がobject
でも各要素がstr
型ではない可能性がある。文字列メソッドの前にastype(str)
を適用すればよい。
s_str_astype = s_object.astype(str)
print(s_str_astype)
# 0 0
# 1 abcde
# 2 nan
# dtype: object
print(s_str_astype.str.len())
# 0 1
# 1 5
# 2 3
# dtype: int64
文字列メソッドの利用については以下の記事も参照。
- 関連記事: pandasの文字列メソッドで置換や空白削除などの処理を行う
- 関連記事: pandasで特定の文字列を含む行を抽出(完全一致、部分一致)
- 関連記事: pandasの文字列を区切り文字や正規表現で複数の列に分割
注意: 欠損値NaN
欠損値NaN
はisnull()
で判定したり、dropna()
で削除したりできる。
s_object = pd.Series([0, 'abcde', np.nan])
print(s_object)
# 0 0
# 1 abcde
# 2 NaN
# dtype: object
print(s_object.map(type))
# 0 <class 'int'>
# 1 <class 'str'>
# 2 <class 'float'>
# dtype: object
print(s_object.isnull())
# 0 False
# 1 False
# 2 True
# dtype: bool
print(s_object.dropna())
# 0 0
# 1 abcde
# dtype: object
文字列str
にキャストすると欠損値は文字列'nan'
となり、欠損値を処理するメソッドの対象とならないので注意。
s_str_astype = s_object.astype(str)
print(s_str_astype)
# 0 0
# 1 abcde
# 2 nan
# dtype: object
print(s_str_astype.map(type))
# 0 <class 'str'>
# 1 <class 'str'>
# 2 <class 'str'>
# dtype: object
print(s_str_astype.isnull())
# 0 False
# 1 False
# 2 False
# dtype: bool
print(s_str_astype.dropna())
# 0 0
# 1 abcde
# 2 nan
# dtype: object
キャストする前に欠損値の処理を行うか、replace()
で文字列'nan'
を欠損値に置き換えればよい。
s_str_astype_nan = s_str_astype.replace('nan', np.nan)
print(s_str_astype_nan)
# 0 0
# 1 abcde
# 2 NaN
# dtype: object
print(s_str_astype_nan.map(type))
# 0 <class 'str'>
# 1 <class 'str'>
# 2 <class 'float'>
# dtype: object
print(s_str_astype_nan.isnull())
# 0 False
# 1 False
# 2 True
# dtype: bool
astype()によるデータ型dtypeの変換(キャスト)
pandas.DataFrame
, pandas.Series
のメソッドastype()
を使うとデータ型dtype
を変更できる。
- pandas.DataFrame.astype — pandas 2.0.3 documentation
- pandas.Series.astype — pandas 2.0.3 documentation
astype()
はデータ型dtype
が変更された新たなpandas.DataFrame
, pandas.Series
を返し、元のオブジェクトは変更されない。
pandas.Seriesのデータ型dtypeを変更
pandas.Series
のメソッドastype()
の引数にデータ型dtype
を指定すると、そのdtype
に変更された新たなpandas.Series
が返される。
s = pd.Series([1, 2, 3])
print(s)
# 0 1
# 1 2
# 2 3
# dtype: int64
s_f = s.astype('float64')
print(s_f)
# 0 1.0
# 1 2.0
# 2 3.0
# dtype: float64
上述のようにdtype
は様々な形で指定できる。
s_f = s.astype('float')
print(s_f.dtype)
# float64
s_f = s.astype(float)
print(s_f.dtype)
# float64
s_f = s.astype('f8')
print(s_f.dtype)
# float64
pandas.DataFrame全体のデータ型dtypeを一括で変更
pandas.DataFrame
は列ごとにデータ型dtype
を保持している。
それぞれのdtype
はdtypes
属性で取得・確認できる。
df = pd.DataFrame({'a': [11, 21, 31], 'b': [12, 22, 32], 'c': [13, 23, 33]})
print(df)
# a b c
# 0 11 12 13
# 1 21 22 23
# 2 31 32 33
print(df.dtypes)
# a int64
# b int64
# c int64
# dtype: object
pandas.DataFrame
のメソッドastype()
の引数にデータ型dtype
を指定すると、すべての列のdtype
が変更された新たなpandas.DataFrame
が返される。
df_f = df.astype('float64')
print(df_f)
# a b c
# 0 11.0 12.0 13.0
# 1 21.0 22.0 23.0
# 2 31.0 32.0 33.0
print(df_f.dtypes)
# a float64
# b float64
# c float64
# dtype: object
pandas.DataFrameの任意の列のデータ型dtypeを個別に変更
astype()
の引数に{列名: データ型}
の辞書を指定すると、任意の列のデータ型dtype
を個別に変更できる。
一列だけでも複数列でも指定可能。
df = pd.DataFrame({'a': [11, 21, 31], 'b': [12, 22, 32], 'c': [13, 23, 33]})
print(df)
# a b c
# 0 11 12 13
# 1 21 22 23
# 2 31 32 33
print(df.dtypes)
# a int64
# b int64
# c int64
# dtype: object
df_fcol = df.astype({'a': float})
print(df_fcol)
# a b c
# 0 11.0 12 13
# 1 21.0 22 23
# 2 31.0 32 33
print(df_fcol.dtypes)
# a float64
# b int64
# c int64
# dtype: object
df_fcol2 = df.astype({'a': 'float32', 'c': 'int8'})
print(df_fcol2)
# a b c
# 0 11.0 12 13
# 1 21.0 22 23
# 2 31.0 32 33
print(df_fcol2.dtypes)
# a float32
# b int64
# c int8
# dtype: object
CSVファイル読み込み時のデータ型dtype指定
pandasでは関数read_csv()
でCSVファイルを読み込むことができる。引数dtype
で任意の型を指定できる。
以下のCSVファイルを例とする。
,a,b,c,d
ONE,1,"001",100,x
TWO,2,"020",,y
THREE,3,"300",300,z
引数dtype
を省略すると、列ごとにデータ型が自動的に選ばれる。
df = pd.read_csv('data/src/sample_header_index_dtype.csv', index_col=0)
print(df)
# a b c d
# ONE 1 1 100.0 x
# TWO 2 20 NaN y
# THREE 3 300 300.0 z
print(df.dtypes)
# a int64
# b int64
# c float64
# d object
# dtype: object
すべての列に同じデータ型dtypeを指定
引数dtype
に任意のデータ型を指定すると、index_col
で指定した列も含めてすべての列がその型に変換される。
指定したデータ型に変換できない列が存在する場合はエラー。
# pd.read_csv('data/src/sample_header_index_dtype.csv',
# index_col=0, dtype=float)
# ValueError: could not convert string to float: 'ONE'
dtype=str
の場合、欠損値NaN
はstr
型に変換されない。
df_str = pd.read_csv('data/src/sample_header_index_dtype.csv',
index_col=0, dtype=str)
print(df_str)
# a b c d
# ONE 1 001 100 x
# TWO 2 020 NaN y
# THREE 3 300 300 z
print(df_str.dtypes)
# a object
# b object
# c object
# d object
# dtype: object
print(df_str.applymap(type))
# a b c d
# ONE <class 'str'> <class 'str'> <class 'str'> <class 'str'>
# TWO <class 'str'> <class 'str'> <class 'float'> <class 'str'>
# THREE <class 'str'> <class 'str'> <class 'str'> <class 'str'>
dtype
を指定せずに読み込んだ後にastype()
でstr
にキャストした場合は欠損値も文字列'nan'
に変換される。
df = pd.read_csv('data/src/sample_header_index_dtype.csv', index_col=0)
print(df.astype(str))
# a b c d
# ONE 1 1 100.0 x
# TWO 2 20 nan y
# THREE 3 300 300.0 z
print(df.astype(str).applymap(type))
# a b c d
# ONE <class 'str'> <class 'str'> <class 'str'> <class 'str'>
# TWO <class 'str'> <class 'str'> <class 'str'> <class 'str'>
# THREE <class 'str'> <class 'str'> <class 'str'> <class 'str'>
列ごとにデータ型dtypeを指定
astype()
と同様に、read_csv()
のdtype
でも辞書形式で列ごとの指定が可能。指定した列以外は自動で選ばれた型となる。
df_col = pd.read_csv('data/src/sample_header_index_dtype.csv',
index_col=0, dtype={'a': float, 'b': str})
print(df_col)
# a b c d
# ONE 1.0 001 100.0 x
# TWO 2.0 020 NaN y
# THREE 3.0 300 300.0 z
print(df_col.dtypes)
# a float64
# b object
# c float64
# d object
# dtype: object
列番号でも指定できる。インデックス列を指定している場合、インデックス列も含めた列番号で指定する必要があるので注意。
df_col = pd.read_csv('data/src/sample_header_index_dtype.csv',
index_col=0, dtype={1: float, 2: str})
print(df_col)
# a b c d
# ONE 1.0 001 100.0 x
# TWO 2.0 020 NaN y
# THREE 3.0 300 300.0 z
print(df_col.dtypes)
# a float64
# b object
# c float64
# d object
# dtype: object
暗黙の型変換
astype()
による明示的な型変換だけでなく、演算などによって暗黙の型変換が行われる場合がある。
整数int
の列と浮動小数点数float
の列を持つpandas.DataFrame
を例とする。
df_mix = pd.DataFrame({'col_int': [0, 1, 2], 'col_float': [0.0, 0.1, 0.2]}, index=['A', 'B', 'C'])
print(df_mix)
# col_int col_float
# A 0 0.0
# B 1 0.1
# C 2 0.2
print(df_mix.dtypes)
# col_int int64
# col_float float64
# dtype: object
演算による暗黙の型変換
例えば、int
の列とfloat
の列との+
演算子による加算の結果はfloat
となる。
print(df_mix['col_int'] + df_mix['col_float'])
# A 0.0
# B 1.1
# C 2.2
# dtype: float64
スカラー値との演算でも同様に暗黙の型変換が行われる。/
演算子による除算の結果はfloat
。
print(df_mix / 1)
# col_int col_float
# A 0.0 0.0
# B 1.0 0.1
# C 2.0 0.2
print((df_mix / 1).dtypes)
# col_int float64
# col_float float64
# dtype: object
+
, -
, *
, //
, **
では、整数int
同士の場合はint
、浮動小数点数float
が含まれる場合はfloat
となる。NumPy配列ndarray
の暗黙の型変換に準ずる。
print(df_mix * 1)
# col_int col_float
# A 0 0.0
# B 1 0.1
# C 2 0.2
print((df_mix * 1).dtypes)
# col_int int64
# col_float float64
# dtype: object
print(df_mix * 1.0)
# col_int col_float
# A 0.0 0.0
# B 1.0 0.1
# C 2.0 0.2
print((df_mix * 1.0).dtypes)
# col_int float64
# col_float float64
# dtype: object
行の取得や転置による暗黙の型変換
loc
やiloc
で1行をpandas.Series
として取得したり、T
やtranspose()
で転置を行ったりする際にも型変換が行われる場合がある。例では整数int
の要素が浮動小数点数float
に変換される。
print(df_mix.loc['A'])
# col_int 0.0
# col_float 0.0
# Name: A, dtype: float64
print(df_mix.T)
# A B C
# col_int 0.0 1.0 2.0
# col_float 0.0 0.1 0.2
print(df_mix.T.dtypes)
# A float64
# B float64
# C float64
# dtype: object
これは、行取得や転置などによって複数の型の要素が混在する列やpandas.Series
が生じてしまうのが原因。pandas.Series
およびpandas.DataFrame
の各列は単一のデータ型dtype
でなければならないので、型変換が発生する。
詳細は以下の記事を参照。
要素への代入による暗黙の型変換
要素に値を代入する際にも型変換が行われる場合がある。
例えば、int
の列にfloat
の要素を代入すると、その列がfloat
に変換される。また、float
の列にint
の要素を代入するとその要素がfloat
に変換される。
df_mix.at['A', 'col_int'] = 10.1
df_mix.at['A', 'col_float'] = 10
print(df_mix)
# col_int col_float
# A 10.1 10.0
# B 1.0 0.1
# C 2.0 0.2
print(df_mix.dtypes)
# col_int float64
# col_float float64
# dtype: object
数値列に文字列の要素を代入すると、列はobject
になり要素ごとに異なる型となる。
df_mix.at['A', 'col_float'] = 'abc'
print(df_mix)
# col_int col_float
# A 10.1 abc
# B 1.0 0.1
# C 2.0 0.2
print(df_mix.dtypes)
# col_int float64
# col_float object
# dtype: object
print(df_mix.applymap(type))
# col_int col_float
# A <class 'float'> <class 'str'>
# B <class 'float'> <class 'float'>
# C <class 'float'> <class 'float'>
なお、上のサンプルコードはバージョン2.0.3
での結果。バージョン0.22.0
では異なる型の要素を代入しても列の型変換は行われず、代入された要素の型が変わっていた。バージョンによって振る舞いが異なる場合があるので要注意。