pandas to_numeric设置downcast='integer'未返回整数类型问题
问题重现
现有如下示例DataFrame:
>>> d = pd.DataFrame({'si': ['1', '2', 'NA'], 's': ['a', 'b', 'c']}) >>> d.dtypes si object s object dtype: object
最初尝试用astype搭配支持NA的Int64整数类型转换,触发TypeError报错:
>>> d.si.astype('Int64') --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-144-ed289e0c95aa> in <module> ----> 1 d.si.astype('Int64') ...
随后尝试使用to_numeric方法,设置downcast='integer'后结果仍为float64类型:
In [112]: d.loc[:, 'ii'] = pd.to_numeric(d.si, errors='coerce', downcast='integer') In [113]: d.dtypes Out[113]: si object s object ii float64 dtype: object In [114]: d Out[114]: si s ii 0 1 a 1.0 1 2 b 2.0 2 NA c NA
预期ii列应为支持缺失值的整数列,实际得到浮点列。参考官方文档对downcast参数的说明:
downcast : {'integer', 'signed', 'unsigned', 'float'}, default None
If not None, and if the data has been successfully cast to a
numerical dtype (or if the data was numeric to begin with),
downcast that resulting data to the smallest numerical dtype
possible according to the following rules:- 'integer' or 'signed': smallest signed int dtype (min.: np.int8) - 'unsigned': smallest unsigned int dtype (min.: np.uint8) - 'float': smallest float dtype (min.: np.float32)
原因说明
pd.to_numeric的downcast参数只针对传统numpy原生数值类型做优化,不支持pandas自定义的可空整数类型(即大写开头的Int64/Int32等)。
当传入的列存在被errors='coerce'转为np.nan的缺失值时,numpy原生整数类型无法存储np.nan,因此to_numeric会先把整列转为float64类型兼容缺失值,后续downcast逻辑检测到存在缺失值,无法降级到numpy整数类型,就会保留float64的结果。
直接用astype('Int64')报错的原因很直接:列里的缺失值是字符串'NA',不是pandas可识别的空值类型,astype无法自动完成字符串到pd.NA的转换,直接抛出类型错误。
正确实现方法
方法1:两步转换(兼容所有pandas 0.25+版本)
先用to_numeric把字符串转为数值,非法值转为np.nan,再显式转成可空Int64类型:
d['ii'] = pd.to_numeric(d.si, errors='coerce').astype('Int64')
转换后结果符合预期:
>>> d.dtypes si object s object ii Int64 dtype: object >>> d si s ii 0 1 a 1 1 2 b 2 2 NA c <NA>
方法2:自动类型转换(pandas 1.0+版本可用)
直接用convert_dtypes方法,它会自动识别列中的数字、字符串缺失值,自动转换为最合适的可空类型:
d['ii'] = d.si.convert_dtypes()
运行结果和方法1完全一致,代码更简洁。
内容的提问来源于stack exchange,提问作者user3313834

