環境
- pandas v1.5.1
- Python v3.10.2
概要
pandas.Sereis
で、値の型が揃っていないときの動きにハマりました。
後学のため、値の型が揃っていないときの動きをまとめます。
値の型が揃っていないときの挙動
dtype
がstring
のpandas.Series
に、文字列以外を代入
dtype
がstring
のpandas.Series
に対して数値またはbool値を代入しようとすると、ValueError
が発生します。
In [167]: s1 = pandas.Series(["a", "b"], dtype="string")
In [168]: s1
Out[168]:
0 a
1 b
dtype: string
In [169]: s1[0] = 1
---------------------------------------------------------------------------
ValueError: Cannot set non-string value '1' into a StringArray.
In [170]: s1[0] = True
---------------------------------------------------------------------------
ValueError: Cannot set non-string value 'True' into a StringArray.
数値と文字列のlistからpandas.Series(dtype="string")
を生成
数値と文字列のlistからpandas.Series
を生成する際、dtype="string"
を指定すると、数値は文字列に変換されます。
In [198]: s2 = pandas.Series([1, "b"], dtype="string")
In [199]: s2
Out[199]:
0 1
1 b
dtype: string
In [200]: type(s2[0])
Out[200]: str
dtype
がint64
のpandas.Series
に、文字列を代入
dtype
がint64
のpandas.Series
に対して文字列を代入すると、dtype
はobject
に変わります。エラーは発生しません。
In [202]: s3 = pandas.Series([1, 2])
In [203]: s3
Out[203]:
0 1
1 2
dtype: int64
In [204]: s3[0] = "a"
In [205]: s3
Out[205]:
0 a
1 2
dtype: object
dtype
がInt64
のpandas.Series
に、文字列を代入
dtype
がInt64
のpandas.Series
に対して文字列、bool値、小数を代入すると、TypeError
が発生します。
小数を代入してもエラーになるところが、nullableな型の特徴です。
In [211]: s4 = pandas.Series([1, 2], dtype="Int64")
In [212]: s4
Out[212]:
0 1
1 2
dtype: Int64
In [213]: s4[0] = "a"
---------------------------------------------------------------------------
TypeError: Invalid value 'a' for dtype Int64
In [214]: s4[0] = True
---------------------------------------------------------------------------
TypeError: Invalid value 'True' for dtype Int64
In [279]: s4[0] = 1.2
---------------------------------------------------------------------------
TypeError: Invalid value '1.2' for dtype Int64
数値と文字列のlistからpandas.Series(dtype="int64")
を生成
数値と文字列のlistからpandas.Series
を生成する際、dtype="int64"を指定すると、数値に変換できるならエラーは発生しません。ただし警告メッセージが表示されます。
In [260]: s5 = pandas.Series([1, "b"], dtype="int64")
---------------------------------------------------------------------------
ValueError: invalid literal for int() with base 10: 'b'
n [272]: s5 = pandas.Series([1, "2"], dtype="int64")
/home/vagrant/.pyenv/versions/3.10.2/lib/python3.10/site-packages/numpy/core/numeric.py:2463: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
return bool(asarray(a1 == a2).all())
<ipython-input-272-ddb554c61a9c>:1: FutureWarning: Values are too large to be losslessly cast to int64. In a future version this will raise OverflowError. To retain the old behavior, use pd.Series(values).astype(int64)
s5 = pandas.Series([1, "2"], dtype="int64")
[274]: s5
Out[274]:
0 1
1 2
dtype: int64
まとめ
各挙動を確認した結果、以下であることが分かりました。
-
Int64
,string
などnullableな型に対して異なる値を代入しようとしたら、エラーが発生しました。ただし発生するエラーはTypeError
とValueError
で、それぞれ異なりました。 -
int64
などnullableでない型に対して、異なる値を代入すると、より広い範囲を表す型に変わります。 -
pandas.Series
生成時には、dtype
引数で指定した型に変換を試みます。変換できない場合はエラーが発生します。
補足
pandas.Series
生成時にdtype="string"
を指定しない場合
pandas.Series
に文字列のlistを渡した場合、dtype
を指定しなければdtype
はobject
になります。
object
は最も汎用的な型なので、この場合は異なる値を代入してもエラーは発生しません。
[206]: s5 = pandas.Series(["a", "b"])
In [207]: s5
Out[207]:
0 a
1 b
dtype: object
In [208]: s5[0] = 1
In [209]: s5
Out[209]:
0 1
1 b
dtype: object
In [210]: type(s5[0])
Out[210]: int