どこにでもいる30代SEの学習ブログ

主にプログラミング関連の学習内容。読んだ本の感想や株式投資についても書いてます。

pandasのDataFrameをconcatすると型が変わってしまう場合の対処法

f:id:predora005:20200921204242j:plain
<pandasのDataFrameをconcatすると型が変わってしまう場合の対処法>*1

※ 2020/03/14にQrunchで書いた記事を移行しました。

pandasのDataFrameを連結する際はconcatを使用します。 このとき、DataFrameにNaNが含まれていると型が変わってしまう場合があります。

起きた事象

dtypeがintの列を結合するとき、結合元のいずれかにNaNが含まれていると、結合後にdtypeがfloatに変わってしまいました。

int_df1 = pd.DataFrame(data=[0, 1, 2, 3, 4], columns=['Int'])
int_df2 = pd.DataFrame(data=[np.nan, 6, 7, 8, 9], columns=['Int'])
int_df3 = pd.concat([int_df1, int_df2])

print(int_df3['Int'].dtype)
# float64

結合元のdtypeを確認すると、NaNを含む方はfloatになっていました。

print('int_df1:', int_df1['Int'].dtype)
print('int_df2:', int_df2['Int'].dtype)

NaNはfloat型

np.nanはfloat型なので、int型の中にnp.nanが含まれているとfloat型と認識されてしまいます。 文字列などのobject型の場合は、NaNが含まれていてもobject型のままです。

obj_df1 = pd.DataFrame(data=['0', '1', '2', '3', '4'], columns=['Object'])
obj_df2 = pd.DataFrame(data=[np.nan, '6', '7', '8', '9'], columns=['Object'])
obj_df3 = pd.concat([obj_df1, obj_df2], ignore_index=True)

print(obj_df3['Object'].dtype)
# object

対処法1

DataFrameを作成する際にdtypeを明示的にInt64と指定します。 すると、concatによる結合後も'dtypeはInt64'のままになっています。

int_df1 = pd.DataFrame(data=[0, 1, 2, 3, 4], columns=['Int'], dtype='Int64')
int_df2 = pd.DataFrame(data=[np.nan, 6, 7, 8, 9], columns=['Int'], dtype='Int64')
int_df3 = pd.concat([int_df1, int_df2], ignore_index=True)

print(int_df3['Int'].dtype)
# Int64

対処法2

結合後にNaNを他の値に変更してから、dtypeをInt64に変更する方法もあります。 この場合、対処法1とは異なりNaNが保持されず別の値に変わることになります。

int_df1 = pd.DataFrame(data=[0, 1, 2, 3, 4], columns=['Int'])
int_df2 = pd.DataFrame(data=[np.nan, 6, 7, 8, 9], columns=['Int'])
int_df3 = pd.concat([int_df1, int_df2], ignore_index=True)

# NaNを0で埋める
int_df3.fillna({'Int':0 }, inplace=True)

# 'Int'列の型を変更する
int_df3 = int_df3.astype( {'Int': 'Int64'} )

print(int_df3['Int'].dtype)
# Int64

終わりに

世の中に存在する実データは欠損(NaN)を含む場合が多いので、対処法を知っておいて損はないと思います。 上に記載した内容の詳しい説明は、pandasのUserGuideに載っています。 Nullable integer data type — pandas 1.0.2 documentation

*1:Gerd AltmannによるPixabayからの画像