如何将含NaN的Pandas整数列存储为PostgreSQL整数类型列
这个问题我碰到过好几次,核心原因确实是Pandas原生的整数类型(比如int64)无法存储np.NaN,外连接操作后会自动把列类型升级为float64,导致存入PostgreSQL后变成double precision类型。要把这类列存成PostgreSQL支持null的整数类型(比如integer或bigint),可以用下面两种靠谱的方法:
方法一:使用Pandas的Nullable Integer类型(推荐)
从Pandas 0.24版本开始,官方引入了支持NaN的Nullable Integer类型(注意是大写的Int64,区分原生小写的int64),能完美适配这个场景:
- 先将目标列转换为
Int64类型:
import pandas as pd import numpy as np # 假设你的DataFrame名为df,目标列为year df['year'] = df['year'].astype('Int64')
转换后,列的类型会变成Int64,原来的np.NaN会被标记为Pandas的pd.NA,完全不影响后续存入数据库。
- 使用
to_sql时明确指定SQL类型:
通过SQLAlchemy的类型映射,直接告诉PostgreSQL这是整数列:
from sqlalchemy import create_engine, Integer # 初始化数据库连接 engine = create_engine('postgresql://用户名:密码@主机地址/数据库名') # 写入数据库,指定year列的SQL类型为Integer df.to_sql( '目标表名', engine, if_exists='replace', # 根据需求选择append/replace等模式 dtype={'year': Integer()} )
这样存入PostgreSQL后,year列的类型就是integer,原来的NaN会被正确转换为SQL的null值。
方法二:兼容旧版Pandas的替代方案
如果你的Pandas版本低于0.24,没有Nullable Integer类型,可以通过把NaN替换为None,再配合指定SQL类型来实现:
- 将列中的NaN替换为
None,同时保留有效整数:
df['year'] = df['year'].apply(lambda x: int(x) if pd.notnull(x) else None)
此时列的类型可能还是float64,但有效值已经是整数,NaN被替换为Python的None。
- 同样在
to_sql时指定SQL类型:
from sqlalchemy import create_engine, Integer engine = create_engine('postgresql://用户名:密码@主机地址/数据库名') df.to_sql( '目标表名', engine, if_exists='replace', dtype={'year': Integer()} )
SQLAlchemy会自动把None映射为PostgreSQL的null,最终列类型就是integer。
补充说明
PostgreSQL的整数类型(integer、bigint等)本身是支持存储null值的,问题的关键在于Pandas和SQLAlchemy之间的类型映射。只要让Pandas传递正确的可空整数信息,或者明确指定SQL类型,就能实现你想要的效果。
内容的提问来源于stack exchange,提问作者Rutger Hofste

