問題
我有一個 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 然后將其轉換為指定的型別?
uj5u.com熱心網友回復:
是的,不幸的是,pandas 本身并不支持其新的擴展資料型別(如可為空的整數陣列)。在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)。
您已經可以使用 nightly 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>
uj5u.com熱心網友回復:
很有趣,也很奇怪。我想出的是一個保持NaN價值觀的轉變
def diff(x,y):
if math.isnan(float(x)) or math.isnan(float(y)):
return np.nan
else:
z = np.int64(y)- np.int64(x)
return z
df['diff'] = df.apply(lambda x: diff(x['epoch_1'],x['epoch_2']), axis=1)
uj5u.com熱心網友回復:
有趣的是df = pd.read_csv('./file.csv', dtype='Int64')在這種情況下不起作用。這是一個實驗性功能,似乎在這里中斷。似乎有很多關于pd.NAand的作業正在進行np.nan(例如這里),所以它很可能是一個錯誤。
請注意,t = pd.array([1665045912937689151, np.nan], dtype='Int64')它也會失敗,因為它以[1665045912937689088, <NA>]. 問題似乎是np.nan和pd.NAas之間的區別s = pd.array([1665045912937689151, pd.NA], dtype='Int64')產生了正確的[1665045912937689151, <NA>]. 可能您將不得不等到np.nan切換到pd.NAin pd.read_csv。
uj5u.com熱心網友回復:
默認情況下,當存在空值或 NaN 值時,pandas 會將整數轉換為浮點數,如果您有大整數,則會導致精度損失。為了克服這個問題,在 read_csv() 中使用 na_filter=False。
解決方案:
import pandas as pd
import numpy as np
df = pd.read_csv('sample.csv', index_col=0, na_filter=False)
print(df)
輸出:
epoch_1 epoch_2
0 1665045912937687151 1665045912937689151
1
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/518165.html
