pandasで文字列と数値を相互変換、書式変更

Posted: | Tags: Python, 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()メソッドで型変換(キャスト)することで数値と文字列を相互に変換可能。データ型dtypeastype()についての詳細は以下の記事を参照。

以下の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.51ではなく0に丸められる。

print(df['round'].map('{:.0f}'.format))
# 0    0
# 1    0
# 2    1
# Name: round, dtype: object

四捨五入で丸めたい場合や、文字列ではなく数値を取得したい場合(format()は文字列を返す)は以下の記事を参照。

関連カテゴリー

関連記事