如何将DataFrame中的指定值替换为NA,同时保留近似原始数据类型并转换为对应可空扩展类型
解决方案:自动将原生类型转为可空扩展类型替换NA
这个问题确实很常见——当我们想给基于numpy原生类型的DataFrame添加缺失值时,总是会不小心把列类型变成object,好在pandas有几个优雅的自动解决方案,完全不用手动维护繁琐的类型映射表:
方法1:用mask()一键替换并自动转类型
直接使用DataFrame.mask()方法,把等于-1的值替换为pd.NA,pandas会智能识别原列的numpy类型,自动将其升级为对应的pandas可空扩展类型:
import numpy as np import pandas as pd # 初始化你的原始数据 ar = np.array([(1, -1), (-1, 2)], dtype=[('a', 'i2'), ('b', 'i4')]) df = pd.DataFrame(ar) # 替换-1为NA,自动转换类型 df_with_na = df.mask(df == -1, pd.NA) # 查看结果 print(df_with_na) # a b # 0 1 <NA> # 1 <NA> 2 print(df_with_na.dtypes) # a Int16 # b Int32 # dtype: object
这个方法完全不需要你操心类型匹配:原int16会转成Int16,int32转成Int32,连浮点、datetime类型都能自动适配——比如float32会变成Float32,原生datetime64本身支持缺失值,会直接保留类型并兼容pd.NA。
方法2:如果已经用了replace(),用convert_dtypes()修正
要是你已经执行了replace(-1, pd.NA)导致类型变成object,也不用重新来,用convert_dtypes()方法就能自动把列转回最合适的可空扩展类型:
df_with_na = df.replace(-1, pd.NA).convert_dtypes() print(df_with_na.dtypes) # a Int16 # b Int32 # dtype: object
这个方法会自动检测列中的数据,精准匹配原numpy类型的可空版本,同样不需要手动指定任何类型。
为什么replace()会把类型变成object?
简单说,numpy的原生整数/浮点类型是不支持缺失值的,当你用replace()把数值换成pd.NA时,pandas没办法在原生类型里容纳缺失值,只能退而求其次用object类型来混合存储数值和NA。而mask()方法会提前检测这种需求,自动帮你把列升级到pandas的可空扩展类型——这些类型原生支持缺失值,同时还能保留原类型的精度。
扩展测试:其他数据类型也适用
这个逻辑对其他数据类型同样有效,比如浮点和datetime:
# 浮点类型测试 ar_float = np.array([(1.5, -1.0), (-1.0, 2.5)], dtype=[('x', 'f4'), ('y', 'f8')]) df_float = pd.DataFrame(ar_float) df_float_na = df_float.mask(df_float == -1.0, pd.NA) print(df_float_na.dtypes) # x Float32 # y Float64 # dtype: object # datetime类型测试 ar_dt = np.array([(np.datetime64('2020-01-01'), np.datetime64('1970-01-01')), (np.datetime64('1970-01-01'), np.datetime64('2020-01-02'))], dtype=[('start', 'datetime64[ns]'), ('end', 'datetime64[ns]')]) df_dt = pd.DataFrame(ar_dt) df_dt_na = df_dt.mask(df_dt == np.datetime64('1970-01-01'), pd.NA) print(df_dt_na.dtypes) # start datetime64[ns] # end datetime64[ns] # dtype: object
内容的提问来源于stack exchange,提问作者Antti Haapala
相关产品推荐
相关产品推荐

