pandasのinfer_objects()は文字列を数値に変換しない

pandasのinfer_objects()は、数字の入った文字列('123')を数値(123)に変換しない、という話。

StackOverflowのURL: https://stackoverflow.com/questions/35003138/python-pandas-inferring-column-datatypes/48269724 のコメント

infer_objects()は、DataFrameのメソッドとSeriesのメソッドと両方がある。 pandas.DataFrame.infer_objectsの関数APIpandas.DataFrame.infer_objects — pandas 0.25.3 documentation
pandas.Series.infer_objectsの関数APIpandas.Series.infer_objects — pandas 0.25.3 documentation
(今後メジャーアップデートが来るから、バージョン指定したURLにしておくよ)

pandasの型システムであるdtypeが分かってないんだよね、という人は、以前dtypeについての公式ドキュメントを翻訳したので是非ご覧ください。

linus-mk.hatenablog.com

動作環境

python 3.7.6
pandas 0.25.3

StackOverflowの例

上記のStackOverflowのコメントによれば、pd.DataFrame(['1', '2', '3']) にinfer_objects()を適用しても、数値になってくれないらしい。本当だろうか。

df1 = pd.DataFrame(['1', '2', '3'])
df1.dtypes
0    object
dtype: object

このデータに対してinfer_objects()を適用する。

df1.infer_objects().dtypes
0    object
dtype: object

本当だ。確かにdtypesはobjectのままだ。

infer_objectsは型を「推測」するだけで「変換」はしない

関数名には、convertという単語は入っていない。
関数名の中にあるinferという単語の和訳は「推測する、推論する」であり、「変換する」ではない。
なるほど、ちゃんと考えてこの関数名にしたんだな、と思える。

公式ドキュメント([https://pandas.pydata.org/pandas-docs/version/0.25.3/reference/api/pandas.Series.infer_objects.html:title])の使用例は、確かに型を推測しているのであり、変換してはいない。

# 公式ドキュメントに載っている例

df2 = pd.DataFrame({"A": ["a", 1, 2, 3]})
df2 = df2.iloc[1:]
df2
A
1 1
2 2
3 3
df2.dtypes
A    object
dtype: object
df2.infer_objects().dtypes
A    int64
dtype: object

この例だと、最初に作ったDataFrameにaという文字列が入っていたので、dtypeがobjectに設定された。
数値部分だけを取り出したときも、dtypeは自動的に変換されないので、objectのままだ。 そこでinfer_objects()を適用すると、今あるデータが入る最適な型であるint64が選択された。めでたしめでたし。

なるほど。infer_objects() のやってることが分かったぞ。 じゃあ、全く同じことをやってみよう。ただし、文字列aではなく、浮動小数点数を使ってみよう。

# では文字列の代わりに浮動小数点数ではどうだろうか?

df3 = pd.DataFrame({"A": [9.876, 1, 2, 3]})
df3 = df3.iloc[1:]
df3
A
1 1.0
2 2.0
3 3.0
df3.dtypes
A    float64
dtype: object
df3.infer_objects().dtypes
A    float64
dtype: object

えっ。どういうことなの。今あるデータは整数だけなんだから、それが入る適切な型であるint64が出力されるんじゃないの?
infer_objects() 何もわからない。

じゃあ文字列を数字に変換する方法は?

to_numeric()を使いましょう。

pandasで型を推測するときの規則は? よく分からない……

APIリファレンスには以下のように書いてある。

The inference rules are the same as during normal Series/DataFrame construction.
拙訳:推測の規則は、通常のSeries/DataFrameの作成をするときと同じである。

「通常のSeries/DataFrameの作成をするとき」のdtype推論の規則は、どのようなものだろうか? この疑問の具体的な答えは、pandasドキュメントの中には見つからなかった。
例えば、DataFrameのコンストラクタについてのページ[https://pandas.pydata.org/pandas-docs/version/0.25.3/reference/api/pandas.DataFrame.html:title]では、 「引数dtypeがNoneだったら推測します(infer)」と書いてあるだけだ。具体的にどう推測するかは一切書かれていない。

「通常のSeries/DataFrameの作成をするとき」には、64bitの整数型で収まる場合にはint64型になる。

df_temp = pd.DataFrame({"A": [1, 2, 3]})
df_temp.dtypes
A    int64
dtype: object

例えば、上記と同じデータに対して、データ型int8を指定してDataFrameを作ってみよう。 このDataFrameに対してinfer_objects()を実施すると、 「通常のSeries/DataFrameの作成をするとき」と同じ推測を実行するのだから、上記の結果と同じint64になると期待される。

df4 = pd.DataFrame({"A": [1, 2, 3]}, dtype='int8')
df4.dtypes
A    int8
dtype: object
# 上のdf_tempと同じ型になるのだろうか?
df4.infer_objects().dtypes
A    int8
dtype: object

えっ。どういうことなの。今あるデータに対して、型の推測をいま一度実施して、特にint64が出力されるんじゃないの?
infer_objects() 何もわからない。

今日の結論

infer_objects() 何もわからない。