You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas read_csv读取含NaN大整数时精度丢失,求更优解决方案

大整数CSV加载与精度问题处理

问题描述

我有一个包含大整数值的CSV文件,需对这些值执行算术运算,部分字段可能包含NaN值。使用Pandas的read_csv方法加载数据时,若不存在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值,计算结果正确。

已尝试的方案

尝试在加载数据时指定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>

结果仍出现精度丢失,计算错误。

不愿采用的临时方案

可以将数据加载为字符串类型,移除含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

但需要保留含NaN的条目,因此需重新添加这些行,该方法涉及大量类型转换,在数据量较大时会成为性能瓶颈,且不够简洁,故寻求更优方案。

更新尝试

另一种可行方法:

[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>

该方法比删除再添加行更优,但仍需在运算前进行类型转换,希望能避免此操作。

同时产生疑问:为何在read_csv中指定dtype为Int64会丢失精度,而加载为字符串后转换为Int64却能正常工作?是否read_csv内部先将数据加载为float64再转换为指定类型?


解决方案与疑问解答

最优加载方式

直接使用read_csv的converters参数,指定列转换为Int64类型,跳过中间浮点转换步骤:

df = pd.read_csv(
    'sample.csv',
    index_col=0,
    converters={
        'epoch_1': pd.Int64Dtype().construct_array_type()._from_sequence,
        'epoch_2': pd.Int64Dtype().construct_array_type()._from_sequence
    }
)

# 计算差值
df['diff'] = df['epoch_2'] - df['epoch_1']

这样加载后的数据能完整保留大整数精度,计算结果正确,且无需后续类型转换。

精度丢失原因解析

你的猜测完全正确:当在read_csv中直接指定dtype=pd.Int64Dtype()时,Pandas内部会先将CSV中的数值解析为float64(因为存在空值,默认解析逻辑会优先用浮点类型兼容NaN),再转换为Int64。而float64只能精确表示到2^53(约9e15),你的数值是1.6e18,远超这个范围,因此转换时会丢失精度。

而先加载为字符串再转换为Int64,是直接从字符串解析为整数,跳过了浮点转换的步骤,因此能完整保留大整数的精度。

替代方案:使用dtype_backend='numpy_nullable'(Pandas 2.0+)

如果你的Pandas版本在2.0及以上,可以使用dtype_backend参数,让read_csv直接用nullable整数类型解析,避免浮点转换:

df = pd.read_csv(
    'sample.csv',
    index_col=0,
    dtype={'epoch_1': 'Int64', 'epoch_2': 'Int64'},
    dtype_backend='numpy_nullable'
)

df['diff'] = df['epoch_2'] - df['epoch_1']

这个参数会改变Pandas的类型解析逻辑,直接用对应的nullable类型读取数据,不会经过浮点类型中转,因此精度不会丢失。


内容的提问来源于stack exchange,提问作者K S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 06:10:58