読者です 読者をやめる 読者になる 読者になる

StatsBeginner: 初学者の統計学習ノート

初学者が統計学、機械学習、R、Pythonの勉強の過程をメモっていくノート。

Pythonメモ: Pandasのデータフレームに空のデータフレームを合体させたらint型の列がfloat型になってた

 こんな事象に陥る人が他にいるのか分からないのですが、ググって解決しなかった問題が解決したので、せっかくだからメモしておきます。


 Pandasのデータフレームに、整数型で値が入っている列があるとします。

>>> import pandas as pd
>>> import numpy
>>> 
>>> df1 = pd.DataFrame({
...     'ID':[123456789012345678, 123456789012345673, 12345678901234567],
...     'Name':['Ichiro','Jiro','Saburo']
...     },
...     columns = ['ID', 'Name']
... )
>>> 
>>> type(df1['ID'][0])  # 列ごと取り出すとPandasのSeriesですと言われるので
<class 'numpy.int64'>


 このデータフレームに、列の構成は同じで行が空になっているデータフレームをappendで下からくっつけたら、整数型の列がfloat型に変わりました。

>>> df2 = pd.DataFrame({
...     'ID':[],
...     'Name':[]
...     },
...     columns = ['ID', 'Name']
... )
>>> 
>>> df12 = df1.append(df2)
>>> 
>>> type(df12['ID'][0])
<class 'numpy.float64'>
>>> 
>>> print([v for v in df12['ID']])
[1.2345678901234568e+17, 1.2345678901234568e+17, 12345678901234568.0]
>>> 


 しかも桁数が大きいので、指数表示になっていますね。
 Nameはもちろん、文字列型になっています。

>>> type(df12['Name'][0])
<class 'str'>


 空のデータフレームをくっつけるみたいな変なことが起きないように処理を組んでおけばいいと思うのですが、私が書いてたTwitterのbot(仕事関係の情報をつぶやくアカウントを半分botにしています)内のデータ集計の部分でpandasを使っていて、こういう事象が発生し得る状態になってしまっていました。 
 しかも、いったんfloat型になったものがその後の処理で結果的にint型に変換されるようになっていたので、なかなか気づきませんでした。なんで気づいたかというと、これがまたヤバいのですが、桁数が大きいので、指数表示になったときに「...568」で止まって以降の数字が切り上げ(?)されてしまっているように、元の数字に戻らないわけです。
 一応試しにやってみると、

>>> df12[['ID']] = df12[['ID']].astype(numpy.int64) # 整数型に変換する
>>> 
>>> print([v for v in df12['ID']])
[123456789012345680, 123456789012345680, 12345678901234568]


 数字が変わってしまっておりますね。このせいで、私のbot内でも、ユーザIDが指数表示を経て別の数字に変わってしまっているものが一部あり、「そのIDのユーザは見つかりません」というエラーが出ていました。そこから辿っていって、Pandasに空のデータフレームを扱わせてfloat型を経由していることに気づいたわけです。
 
 
 そもそもユーザIDを整数型で持つ必要はなく、文字列型にすればいいわけですが、TwitterのAPIから帰ってくるIDが単なる数字の並びになっていて、int型として認識されていたので、そのままにしてました。
 素人なのでよく知りませんが、IDを整数型にしてるケースってけっこうあるんですかね?

 
 TwitterIDが33bitになったため、値をINT型に入れているとエラーに。 | iconDecotter-Log
 世界規模のWebサービスを作るときにDBのユーザーIDをINT型にしてはいけない理由 | 着ぐるみ追い剥ぎペンギン


 こういう記事をからすると、文字列型にしてるのが当然ってわけでもないんだろうか。メリット・デメリット等、私はよく分かりませんが、文字列のほうが間違いが少なそうなので、あとでbotの修正をしようと思います。
 ちなみに、IDを文字列型として扱いたい場合、Tweepyのレスポンスの中にある「id」という項目ではなく「id_str」という項目を取得すればよいです。