使用pd.read_sql从Redshift拉取数据为何所有列dtype均为object
问题原因
- psycopg2默认未适配Redshift专属数据类型的Python映射。Redshift的
VARCHAR(max)、固定长度CHAR、自定义枚举类字段,或是空值占比极高的数值/日期字段,都会被psycopg2默认返回为字符串或None对象,pandas读取这类无明确类型标识的数据时,会统一归类为object类型。 - 你当前传入
pd.read_sql的是原生psycopg2连接,pandas对原生数据库连接的类型推断能力较弱,没有对应的Redshift类型映射规则,遇到非明确的基础类型就会直接降级为object。 - 如果查询的表中存在全空列,或是数值/日期字段中混有字符串格式的空值标记(比如
N/A、字符串类型的NULL),也会触发pandas的类型降级逻辑,整列转为object类型。
修复方案
方案1:使用SQLAlchemy Redshift驱动(推荐)
安装sqlalchemy-redshift依赖后,构造SQLAlchemy引擎作为连接传入,pandas会自动匹配Redshift数据类型做转换,代码示例:
from sqlalchemy import create_engine # 按实际信息替换连接参数即可 engine = create_engine('redshift+psycopg2://{用户名}:{密码}@{集群地址}:5439/{数据库名}') data = pd.read_sql("""select * from some.tables""", con=engine)
方案2:原生psycopg2连接手动注册类型转换器
如果要保留现有原生连接的用法,可手动注册数据类型转换器,让psycopg2返回对应类型的Python对象,示例代码:
import psycopg2 import psycopg2.extensions # 注册DECIMAL类型转float的规则 DEC2FLOAT = psycopg2.extensions.new_type( psycopg2.extensions.DECIMAL.values, 'DEC2FLOAT', lambda value, curs: float(value) if value is not None else None ) psycopg2.extensions.register_type(DEC2FLOAT) # 日期、时间戳类型psycopg2默认已带转换规则,如有自定义格式可参考上述逻辑自行注册
方案3:read_sql调用时手动指定字段类型
如果表结构固定、字段数量少,可直接通过dtype参数指定每一列的目标类型:
import numpy as np data = pd.read_sql( """select * from some.tables""", con=credentials, dtype={ "Column1": np.int32, "Column2": np.float64, # 其余字段按实际需求配置即可 } )
内容的提问来源于stack exchange,提问作者x1PatientZero1x
相关产品推荐
相关产品推荐

