python - Pandas read_csv() 损失数字精度

标签 python pandas dataframe csv

问题

我有一个包含大整数值的 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/

相关文章:

python:根据修改日期+迭代器重命名文件

python - 将包含十六进制和 ASCII 的字符串解码为十进制

python - 使用另一个多索引系列屏蔽数据框

python - 想要知道有多少对象位于两个不同子集的重叠部分

r - 对具有由该行中的另一个值指定的动态列范围的行求和

python: _winreg 问题

python - '从 X 导入 a' 与 'import X; X.a'

pandas - '<' not supported between instances of ' 日期时间.日期' 和 'str'

python - Pandas 数据帧 : Rolling Set Union Aggregation over multiple Groups

python - 日期列和整数列之间的 Seaborn 热图