- 问题**
我有一个包含大整数值的csv文件,我想对它执行一些算术运算,这些字段可能包含nan值,现在当我使用pandas to_csv方法将这些值加载到df中时,当没有nan值时,这些值被加载为'int',精度似乎是正确的,但当存在nan值时,这些值被转换为'float',我看到精度损失。
示例csv文件-〉
,epoch_1,epoch_2
0,1665045912937687151,1665045912937689151
1,,
加载后-〉
[1] df = pd.read_csv('sample.csv', index_col=0)
[2] df
epoch_1 epoch_2
0 1.665046e+18 1.665046e+18
1 NaN NaN
[3] df['diff'] = df['epoch_2'] - df['epoch_1']
[4] df
epoch_1 epoch_2 diff
0 1.665046e+18 1.665046e+18 2048.0
1 NaN NaN NaN
如您所见,第3列的值不正确,正确的值应为2000。
如果没有nan值,则计算结果正确。
"我所尝试的"
我在加载数据时尝试将dtype指定为Int64
[1] df = pd.read_csv('sample.csv', index_col=0, dtype={'epoch_1': pd.Int64Dtype(), 'epoch_2': pd.Int64Dtype()})
[2] df
epoch_1 epoch_2
0 1665045912937687296 1665045912937689088
1 <NA> <NA>
[3] df['diff'] = df['epoch_2'] - df['epoch_1']
[4] df
epoch_1 epoch_2 diff
0 1665045912937687296 1665045912937689088 1792
1 <NA> <NA> <NA>
正如您所看到的,这也会导致精度损失,从而导致不正确的结果。
- 我不想使用的解决方法**
我可以做的是将数据加载为str,删除NaN列,然后将这些字段转换为"int64"并计算结果,这将给出正确的结果:
[1] df = pd.read_csv('sample.csv', index_col=0, dtype={'epoch_1': str, 'epoch_2': str})
[2] df
epoch_1 epoch_2
0 1665045912937687151 1665045912937689151
1 NaN NaN
[3] df = df[~df['epoch_1'].isna()]
[4] df['diff'] = df['epoch_2'].astype(int) - df['epoch_1'].astype(int)
[5] df
epoch_1 epoch_2 diff
0 1665045912937687151 1665045912937689151 2000
但是我需要在最后的df中保留nan值的条目,所以我必须把这些条目加回去,这个方法在两次转换之间花费了大量的计算,当df的大小和要计算的字段数量增加时,它将成为一个瓶颈,它也不是很优雅,所以我正在寻找一个更好的方法来实现这一点。
- 更新**
另一件似乎起作用的事情是:-
[1] df = pd.read_csv('sample.csv', index_col=0, dtype=str)
[2] df
epoch_1 epoch_2
0 1665045912937687151 1665045912937689151
1 NaN NaN
[3] df['diff'] = df['epoch_2'].astype('Int64') - df['epoch_1'].astype('Int64')
[4] df
epoch_1 epoch_2 diff
0 1665045912937687151 1665045912937689151 2000
1 NaN NaN <NA>
这似乎比删除na值然后再添加它们要好,尽管这也需要在操作之前进行类型转换,如果可能的话,我希望避免这种情况。
这也引起了另一个疑问,为什么在read_csv中指定列的dtype为Int64时会丢失精度,但在加载为str然后转换为Int64时可以正常工作,read_csv是否在内部加载数据为float64然后将其转换为指定的dtype?
4条答案
按热度按时间agyaoht71#
是的,不幸的是Pandas还没有原生地支持它的新扩展dtypes(比如可以为空的整数数组)。要做的工作在https://github.com/pandas-dev/pandas/issues/29752中跟踪。
pd.read_csv
的相关更新刚刚登陆main
,即参考https://github.com/pandas-dev/pandas/pull/48776,并计划在下一个Pandas版本1.6.0
中发布。定于12月发布的新版本最近被重命名为2.0.0
)。你已经可以用夜间的scipy轮子测试它了。
3b6akqbq2#
很有趣,也很奇怪,我得到的是一个保留
NaN
值的反转krugob8w3#
有趣的是
df = pd.read_csv('./file.csv', dtype='Int64')
在这种情况下不起作用。这是一个实验特性,似乎在这里中断了。似乎有很多关于pd.NA
和np.nan
的工作正在进行中(例如here),所以很可能是一个bug。请注意,
t = pd.array([1665045912937689151, np.nan], dtype='Int64')
也失败了,因为它最终得到了[1665045912937689088, <NA>]
。问题似乎在于np.nan
和pd.NA
之间的差异,因为s = pd.array([1665045912937689151, pd.NA], dtype='Int64')
生成了正确的[1665045912937689151, <NA>]
。可能您必须等到np.nan
在pd.read_csv
中切换到pd.NA
。wko9yo5t4#
默认情况下,当存在空值或NaN值时,Pandas会将整数转换为浮点型,如果您有大整数,这会导致精度损失。要克服此问题,请在read_csv()中使用na_filter = False。
解决方案:
输出: