Python 如何在使用django ORM加载数据之前强制列数据类型

Python 如何在使用django ORM加载数据之前强制列数据类型,python,django,pandas,dataframe,django-orm,Python,Django,Pandas,Dataframe,Django Orm,我们使用pandas(v0.25.3)从通过Django ORM(Django v2.2.6)访问的postgres数据库中的大型数据集运行分析和数据操作 我们遇到的情况是,我们导入到DataFrame的表包含一个外键ID列,该列存储为models.BigIntegerField。此外键字段通常是一个大数字,但在未设置外键的行中也可以为空 当我们将Django查询集中的记录列表导入新的pandas数据帧时,pandas将ID列的dtype设置为np.float64,因为数据包含一些空值。但是,对

我们使用pandas(v0.25.3)从通过Django ORM(Django v2.2.6)访问的postgres数据库中的大型数据集运行分析和数据操作

我们遇到的情况是,我们导入到DataFrame的表包含一个外键ID列,该列存储为models.BigIntegerField。此外键字段通常是一个大数字,但在未设置外键的行中也可以为空

当我们将Django查询集中的记录列表导入新的pandas数据帧时,pandas将ID列的dtype设置为np.float64,因为数据包含一些空值。但是,对于ID不为null的行,从BigInteger到np.float64的转换会导致最低有效位发生更改,因此,如果我们随后尝试将列dtype重新转换为np.int64(使用DataFrame.astype()),我们最终会得到一个不同的值

下面是我们看到的问题的简化示例:

import numpy as np
import pandas as pd
data = [{'id': 144123525091332019}, {'id': None}]
df = pd.DataFrame(data)
df
Out[6]: 
             id
0  1.441235e+17
1           NaN
df.fillna(0, inplace=True)
df.astype({'id': np.int64})
Out[8]: 
                   id
0  144123525091332032
1                   0
请注意,从大整数到np.float64再到np.int64的转换结果是,第一行的id列中的值发生了更改。上面示例中使用的id值直接取自系统中的实际事件

在将数据导入pandas时,建议使用什么方法来避免从int到float的类型转换,从而阻止id值在我们身上的更改


谢谢

问题在于id列中没有。Numpy对于整数没有NaN

因此,在int64和float64之间转换时,会出现转换错误。这说明了这一点

 a = np.int64(144123525091332019)
 print(a)
 b = np.float64(a)
 print(b)
 c = np.int64(b)
 print(c)

144123525091332019
1.4412352509133203e+17
144123525091332032
因此,我们需要避免转换。现在np.NaN是float64类型,而np.NaN根本不是int类型。但在pandas中,这一问题已经解决,需要使用扩展dtype Int64(大写),而不是默认的dtype Int64(小写)

但是,None和转换存在问题

import numpy as np
import pandas as pd
data = [{'id': 144123525091332019}, {'id': 0}]
df = pd.DataFrame(data,dtype='Int64') # here we are saying that use the int with NA
print(df.dtypes)
df
给予

但是

给出了错误的答案

id    Int64
dtype: object
    id
0   144123525091332032
1   <NA>
id Int64
数据类型:对象
身份证件
0   144123525091332032
1.

当数字通过str->float64->Int64转换时,首先解决问题。基本上,如果您能够以不同的方式处理None,那么情况会更好。

在我们继续寻找更好的解决方案的同时,我们采用了蛮力解决方案,即在QuerySet中循环,并在构建数据帧之前将所有None值更改为0。这将导致pandas将Int64类型指定给列,并避免强制转换浮动

for tgt in target_performance_set:
    if tgt['gv_target_id'] is None:
        tgt['gv_target_id'] = 0

这很难看,但目前还有效。

我同意核心问题在于无元素。如果我能在DataFrame构造函数之前以某种方式(有效地)将None值转换为0,那么问题可能就解决了。我只是不知道如何最好地使用Django ORM。实际上,您可以先将它们全部设置为-1,然后稍后在pandas中将负数更改为Int64中的负数。。。基本上,强迫负数模拟Nanth。关键问题是在构建数据帧之前,如何最好地使值为-1(或0)。目前,我们正在Django QuerySet上使用蛮力方法和For循环。我希望有更好/更干净的方法。
id    Int64
dtype: object
    id
0   144123525091332032
1   <NA>
for tgt in target_performance_set:
    if tgt['gv_target_id'] is None:
        tgt['gv_target_id'] = 0