场景例程:
with db.cursor() as c1:
sql='''select 原料1原料筒,原料2原料筒,原料3原料筒,原料1比例,原料2比例,原料3比例
from 配方表 where 配方号=%s;'''
c1.execute(sql,pf_no)
if c1.rowcount>0:
data=pd.DataFrame(c1.fetchall())
t_exe=data.iloc[0,:3]
bl_exe=data.iloc[0,3:]
这里原料筒在数据库的数据类型是int,原料比例的数据类型是float,原本期望得到一个整型Series(t_exe)和一个浮点型Series(bl_exe),然而在实际应用中报错,调试中发现t_exe中的数据类型全部变成了浮点型。
data=pd.DataFrame(c1.fetchall())
data.iloc[0,:3]
Out[20]:
0 3.0
1 1.0
2 2.0
Name: 0, dtype: float64
而采用t_exe=data.iloc[:1,:3]时,数据类型没变:
data.iloc[:1,:3]
Out[22]:
0 1 2
0 3 1 2
原因:
t_exe=data.iloc[0,:3]
当执行t_exe=data.iloc[0,:3]
时,Pandas提取出DataFrame的第一行的前三列并创建了一个Series对象。在Pandas中,Series默认倾向于使用较为通用的数据类型来存储数据,以适应可能存在的不同数据类型。对于数值型数据,如果没有明确指定或数据中存在非整数值(如浮点数),Pandas可能会自动将整个Series的数据类型提升为float64
,以避免信息丢失。
t_exe=data.iloc[:1,:3]
而当执行t_exe=data.iloc[:1,:3]
时,得到的是一个包含单行(第一行)但仍然是DataFrame格式的结果。DataFrame在处理数据时,对于每一列,它会尝试保持原始数据类型,只要该类型在DataFrame的列中是同质的。因此,如果原始数据库查询结果中前三列确实是整型,且没有浮点数混入,Pandas在构建这个小的DataFrame时,会保留整型。
解决办法
如果希望在提取Series时也保持原始的整型数据,可以显式地设置数据类型。例如:
t_exe=data.iloc[0,:3].apply(int)
或
t_exe=data.iloc[0,:3].astype(int)
也可以在得到小的Dataframe后再做一次切片
data.iloc[:1,:3].iloc[0]
Out[25]:
0 3
1 1
2 2
Name: 0, dtype: int64
这里还有一个小的知识点:在大多数情况下,将Pandas的Series对象用于预期接收列表或其他一维数据集合的函数或方法时,不会直接报错,因为Series设计为与这些场景兼容,所以很多时候需要列表的地方可以直接用Series类型,即直接切片出的单行或单列。但!!!用data.iloc[:1,:3]切出来的单行单列直接当列表用会报错,因为它的数据格式仍然是DataFrame,这是pandas为了保持数据一致性所进行的处理。