pandasで文字列と数値を相互変換、書式変更
pandas.DataFrame
, pandas.Series
の文字列と数値を相互に変換したり、文字列の書式を変更したりする方法について説明する。
データ自体を変換するのではなく、print()
での出力などの表示をカスタマイズしたい場合はpandasの設定を変更する。以下の記事を参照。
サンプルコードのpandasのバージョンは以下の通り。
import pandas as pd
print(pd.__version__)
# 0.23.0
以下の内容について説明する。
- 型変換(キャスト):
astype()
- 数値を文字列に変換
- 文字列を数値に変換
- 列の上書き、新たな列として追加
- 2進数、8進数、16進数の数値、文字列の変換
- 整数値を文字列に変換:
bin()
,oct()
,hex()
,format()
- 文字列を整数値に変換:
int()
で基数指定 - 基数を変換
- 整数値を文字列に変換:
- 文字列をゼロ埋め、アラインメント
- ゼロ埋め
- アラインメント(右寄せ、中央寄せ、左寄せ)
- 任意の書式の文字列に変換:
format()
- ゼロ埋め、アラインメント
- 2進数、8進数、16進数
- 小数点以下桁数、有効数字
- 指数表記
- パーセント表示
- 丸めについての注意
Pythonにおける文字列から数値への変換や2進数、8進数、16進数の数値・文字列の相互変換については以下の記事を参照。
型変換(キャスト): astype()
astype()
メソッドで型変換(キャスト)することで数値と文字列を相互に変換可能。データ型dtype
やastype()
についての詳細は以下の記事を参照。
以下のpandas.DataFrame
を例とする。
df = pd.DataFrame({'i': [0, 10, 200], 'f': [0, 0.9, 0.09],
's_i': ['0', '10', '200'], 's_f': ['0', '0.9', '0.09']})
print(df)
# i f s_i s_f
# 0 0 0.00 0 0
# 1 10 0.90 10 0.9
# 2 200 0.09 200 0.09
print(df.dtypes)
# i int64
# f float64
# s_i object
# s_f object
# dtype: object
数値を文字列に変換
数値int
, float
を文字列str
に変換する。
print(df['i'].astype(str))
# 0 0
# 1 10
# 2 200
# Name: i, dtype: object
print(df['f'].astype(str))
# 0 0.0
# 1 0.9
# 2 0.09
# Name: f, dtype: object
文字列における小数点以下の桁数などは自動的に決まる。自分で選択したい場合は後述のformat()
メソッドを使う。
pandas.DataFrame
全体を一括で変換することもできる。ただし、全ての列が指定した型に変換可能である必要がある。
print(df.astype(str))
# i f s_i s_f
# 0 0 0.0 0 0
# 1 10 0.9 10 0.9
# 2 200 0.09 200 0.09
print(df.astype(str).dtypes)
# i object
# f object
# s_i object
# s_f object
# dtype: object
整数int
と浮動小数点float
の変換も可能。
print(df['i'].astype(float))
# 0 0.0
# 1 10.0
# 2 200.0
# Name: i, dtype: float64
print(df['f'].astype(int))
# 0 0
# 1 0
# 2 0
# Name: f, dtype: int64
例のように、float
からint
への変換は小数点以下切り捨てとなる。四捨五入や偶数への丸めで丸めたい場合は以下の記事を参照。
文字列を数値に変換
文字列str
を数値int
, float
に変換する。
print(df['s_i'].astype(int))
# 0 0
# 1 10
# 2 200
# Name: s_i, dtype: int64
print(df['s_i'].astype(float))
# 0 0.0
# 1 10.0
# 2 200.0
# Name: s_i, dtype: float64
print(df['s_f'].astype(float))
# 0 0.00
# 1 0.90
# 2 0.09
# Name: s_f, dtype: float64
小数の文字列を整数int
に直接変換するとエラーValueError
になる。float
に変換してからint
に変換すればOK。
# print(df['s_f'].astype(int))
# ValueError: invalid literal for int() with base 10: '0.1'
print(df['s_f'].astype(float).astype(int))
# 0 0
# 1 0
# 2 0
# Name: s_f, dtype: int64
カンマで桁区切りされた数字の文字列も直接変換するとエラーValueError
になる。文字列メソッドstr.replace()
でカンマを削除(空文字列''
に置換)してからint
またはfloat
に型変換する。
s_sep = pd.Series(['1,000,000', '1,000', '1'])
print(s_sep)
# 0 1,000,000
# 1 1,000
# 2 1
# dtype: object
# print(s_sep.astype(int))
# ValueError: invalid literal for int() with base 10: '1,000,000'
print(s_sep.str.replace(',', '').astype(int))
# 0 1000000
# 1 1000
# 2 1
# dtype: int64
print(s_sep.str.replace(',', '').astype(float))
# 0 1000000.0
# 1 1000.0
# 2 1.0
# dtype: float64
列の上書き、新たな列として追加
変換した値で既存の列を上書きしたり、新たな列として追加することもできる。以降の例でも同様。
df['i'] = df['i'].astype(str)
print(df)
# i f s_i s_f
# 0 0 0.00 0 0
# 1 10 0.90 10 0.9
# 2 200 0.09 200 0.09
df['f_s'] = df['f'].astype(str)
print(df)
# i f s_i s_f f_s
# 0 0 0.00 0 0 0.0
# 1 10 0.90 10 0.9 0.9
# 2 200 0.09 200 0.09 0.09
print(df.dtypes)
# i object
# f float64
# s_i object
# s_f object
# f_s object
# dtype: object
列の追加については以下の記事も参照。
2進数、8進数、16進数の数値、文字列の変換
2進数、8進数、16進数で表された整数値、文字列を相互に変換する。
Pythonにおける2進数、8進数、16進数の扱いについては以下の記事を参照。
整数値を文字列に変換: bin(), oct(), hex(), format()
以下のpandas.Series
を例とする。コード中では16進数0xff
などのような形式で整数値を表せるが、print()
などの出力では10進数で表示される。
s_int = pd.Series([0xff, 0o77, 0b11])
print(s_int)
# 0 255
# 1 63
# 2 3
# dtype: int64
整数値を2進数、8進数、16進数の文字列に変換するには、それぞれbin()
, oct()
, hex()
関数を各要素に適用する。
pandas.Series
, pandas.DataFrame
の列の要素に対してはmap()
メソッド、pandas.DataFrame
のすべての要素に対してはapplymap()
メソッドを使う。
print(s_int.map(bin))
# 0 0b11111111
# 1 0b111111
# 2 0b11
# dtype: object
print(s_int.map(oct))
# 0 0o377
# 1 0o77
# 2 0o3
# dtype: object
print(s_int.map(hex))
# 0 0xff
# 1 0x3f
# 2 0x3
# dtype: object
format()
を使う方法もある。format()
を使うとプレフィックス(0b
, 0o
, 0x
)やゼロ埋めなどを選択可能。詳細は後述。
print(s_int.map('{:b}'.format))
# 0 11111111
# 1 111111
# 2 11
# dtype: object
print(s_int.map('{:#b}'.format))
# 0 0b11111111
# 1 0b111111
# 2 0b11
# dtype: object
print(s_int.map('{:#010b}'.format))
# 0 0b11111111
# 1 0b00111111
# 2 0b00000011
# dtype: object
文字列を整数値に変換: int()で基数指定
以下のpandas.DataFrame
を例とする。
df_str = pd.DataFrame({'bin': ['0b01', '0b10', '0b11'],
'oct': ['0o07', '0o70', '0o77'],
'hex': ['0x0f', '0xf0', '0xff'],
'dec': ['1', '10', '11']})
print(df_str)
# bin oct hex dec
# 0 0b01 0o07 0x0f 1
# 1 0b10 0o70 0xf0 10
# 2 0b11 0o77 0xff 11
print(df_str.dtypes)
# bin object
# oct object
# hex object
# dec object
# dtype: object
0b
, 0o
, 0x
のような基数を表すプレフィックスがついた文字列はastype()
では変換できない。
# print(df_str['bin'].astype(int))
# ValueError: invalid literal for int() with base 10: '0b01'
無名関数(ラムダ式)を使って、int()
の第二引数にそれぞれの基数を指定して適用する。
print(df_str['bin'].map(lambda x: int(x, 2)))
# 0 1
# 1 2
# 2 3
# Name: bin, dtype: int64
print(df_str['oct'].map(lambda x: int(x, 8)))
# 0 7
# 1 56
# 2 63
# Name: oct, dtype: int64
print(df_str['hex'].map(lambda x: int(x, 16)))
# 0 15
# 1 240
# 2 255
# Name: hex, dtype: int64
プレフィックスがついている場合はint()
の第二引数を0
とするとプレフィックスをもとに自動的に基数が設定される。
print(df_str.applymap(lambda x: int(x, 0)))
# bin oct hex dec
# 0 1 7 15 1
# 1 2 56 240 10
# 2 3 63 255 11
プレフィックスがついていない文字列もint()
の第二引数に基数を指定して変換できる。
print(df_str['dec'].map(lambda x: int(x, 2)))
# 0 1
# 1 2
# 2 3
# Name: dec, dtype: int64
先頭に0
がついている文字列の場合、astype()
では変換可能だが、第二引数を0
としたint()
だとエラーValueError
になるので注意。
s_str_dec = pd.Series(['01', '10', '11'])
print(s_str_dec)
# 0 01
# 1 10
# 2 11
# dtype: object
print(s_str_dec.astype(int))
# 0 1
# 1 10
# 2 11
# dtype: int64
# print(s_str_dec.map(lambda x: int(x, 0)))
# ValueError: invalid literal for int() with base 0: '01'
基数を変換
これまでの方法を繰り返すことで基数の変換が可能。
例えば、8進数の文字列から16進数の文字列への変換は以下の通り。
print(df_str['oct'].map(lambda x: int(x, 8)).map(hex))
# 0 0x7
# 1 0x38
# 2 0x3f
# Name: oct, dtype: object
文字列をゼロ埋め、アラインメント
strアクセサによる文字列メソッドを適用することにより、文字列をゼロ埋めしたりアラインメント(右寄せ、中央寄せ、左寄せ)したりできる。
以下のpandas.Series
を例とする。
s_str = pd.Series(['0', '10', 'xxx'])
print(s_str)
# 0 0
# 1 10
# 2 xxx
# dtype: object
strアクセサによる文字列メソッドではなくformat()
を使う方法もある。後述。
ゼロ埋め
str.zfill()
でゼロ埋め。引数に指定した文字数になるように左側が0
で埋められる。
print(s_str.str.zfill(8))
# 0 00000000
# 1 00000010
# 2 00000xxx
# dtype: object
ゼロ埋めについての詳細は以下の記事も参照。
アラインメント(右寄せ、中央寄せ、左寄せ)
str.rjust()
, str.center()
, str.ljust()
でそれぞれ右寄せ、中央寄せ、左寄せ。
第二引数を省略すると空白(スペース)、文字を指定するとその文字で埋められる。
print(s_str.str.rjust(8))
# 0 0
# 1 10
# 2 xxx
# dtype: object
print(s_str.str.rjust(8, '_'))
# 0 _______0
# 1 ______10
# 2 _____xxx
# dtype: object
print(s_str.str.center(8))
# 0 0
# 1 10
# 2 xxx
# dtype: object
print(s_str.str.center(8, '_'))
# 0 ___0____
# 1 ___10___
# 2 __xxx___
# dtype: object
print(s_str.str.ljust(8))
# 0 0
# 1 10
# 2 xxx
# dtype: object
print(s_str.str.ljust(8, '_'))
# 0 0_______
# 1 10______
# 2 xxx_____
# dtype: object
数値の列に対してはstrアクセサによる文字列メソッドは適用できない。astype()
で文字列に型変換してから適用する。
s_num = pd.Series([0, 10, 100])
# print(s_num.str.rjust(8, '_'))
# AttributeError: Can only use .str accessor with string values, which use np.object_ dtype in pandas
print(s_num.astype(str).str.rjust(8, '_'))
# 0 _______0
# 1 ______10
# 2 _____100
# dtype: object
アラインメント(右寄せ、中央寄せ、左寄せ)についての詳細は以下の記事も参照。
任意の書式の文字列に変換: format()
文字列メソッドformat()
を各要素に適用することで任意の書式の文字列に変換できる。
以下のpandas.DataFrame
を例とする。
df = pd.DataFrame({'i': [0, 10, 100],
'f': [0.1234, 1.234, 12.34],
'round': [0.4, 0.5, 0.6]})
print(df)
# i f round
# 0 0 0.1234 0.4
# 1 10 1.2340 0.5
# 2 100 12.3400 0.6
print(df.dtypes)
# i int64
# f float64
# round float64
# dtype: object
format()
における書式指定文字列の詳細などは以下の記事を参照。
ゼロ埋め、アラインメント
print(df['i'].map('{:08}'.format))
# 0 00000000
# 1 00000010
# 2 00000100
# Name: i, dtype: object
print(df['i'].map('{:_<8}'.format))
# 0 0_______
# 1 10______
# 2 100_____
# Name: i, dtype: object
2進数、8進数、16進数
print(df['i'].map('{:x}'.format))
# 0 0
# 1 a
# 2 64
# Name: i, dtype: object
print(df['i'].map('{:#010b}'.format))
# 0 0b00000000
# 1 0b00001010
# 2 0b01100100
# Name: i, dtype: object
小数点以下桁数、有効数字
print(df['f'].map('{:.2f}'.format))
# 0 0.12
# 1 1.23
# 2 12.34
# Name: f, dtype: object
print(df['f'].map('{:.2g}'.format))
# 0 0.12
# 1 1.2
# 2 12
# Name: f, dtype: object
指数表記
print(df['f'].map('{:.2e}'.format))
# 0 1.23e-01
# 1 1.23e+00
# 2 1.23e+01
# Name: f, dtype: object
パーセント表示
print(df['f'].map('{:.2%}'.format))
# 0 12.34%
# 1 123.40%
# 2 1234.00%
# Name: f, dtype: object
丸めについての注意
桁数を指定する場合は数値が丸められるが、四捨五入ではなく偶数への丸めなので注意。例えば0.5
は1
ではなく0
に丸められる。
print(df['round'].map('{:.0f}'.format))
# 0 0
# 1 0
# 2 1
# Name: round, dtype: object
四捨五入で丸めたい場合や、文字列ではなく数値を取得したい場合(format()
は文字列を返す)は以下の記事を参照。