问题
我有一个包含大整数值的 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
正如您所看到的,第三列的值不正确,正确的值应该是 2000。
如果没有 nan 值,则计算结果是正确的。
我尝试过的
我尝试在加载数据时将数据类型指定为 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 然后将其转换到指定的数据类型?
最佳答案
是的,不幸的是 pandas 本身并不支持其新的扩展数据类型(如可为 null 的整数数组)。要完成的工作在 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 轮子对其进行测试。
mamba create -n test_pandas -c conda-forge python pandas pip
mamba activate test_pandas
pip install --pre --upgrade --extra-index https://pypi.anaconda.org/scipy-wheels-nightly/simple pandas
In [5]: pd.__version__
Out[5]: '1.6.0.dev0+350.g2f7dce4e6e'
In [6]: pd.read_csv("sample.csv", use_nullable_dtypes=True, index_col=0).assign(diff=lambda df: df.epoch_2 - df.epoch_1)
Out[6]:
epoch_1 epoch_2 diff
0 1665045912937687151 1665045912937689151 2000
1 <NA> <NA> <NA>
关于python - Pandas read_csv() 损失数字精度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74094447/