numpy Pandas数字(…)(_N),Downcast=‘Float’)失去精度

zz2j4svz  于 2022-11-10  发布在  其他
关注(0)|答案(2)|浏览(138)

即使最大的(9.761140e+02)和最小的(0.000000e+00)元素适用于flat32,将Pandas Dataframe (按列)从flat64向下转换也会导致精度下降。
数据集非常大,5500万行乘以12列。这是没有向下预测的特定列的平均值(1.343987e+00),之后是1.224472e+00。
与使用np.astype()得到的结果相同。

ru9i0ody

ru9i0ody1#

这是一个非常有趣的问题。我测试了几个 Dataframe ,从100万条记录到5500万条记录,大小与您的相同,保持minmax的值与您拥有的值相似。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

x, y = [], []
for idx, num in enumerate(range(1, 57, 2)):
    print(f"{idx+1}) Testing with {num} million records...")
    rows = num*(10**6)
    cols = ['col']

    df = pd.DataFrame(np.random.uniform(0, 9.761140e+02, size=(rows, len(cols))), columns=cols)
    df['col1'] = pd.to_numeric(df['col'], downcast='float')
    df['diff'] = df['col'] - df['col1']

    diff = df['col'].mean() - df['col1'].mean()

    x.append(num)
    y.append(diff)

plt.plot(x, y, 'ro')
plt.xlabel('number of rows (millions)')
plt.ylabel('precision value lost')
plt.show()

故事情节是这样的。

根据剧情,似乎在3500万条记录之后,精度的损失突然增加,本质上似乎是对数的。我还没弄明白为什么会是这样。

z4bn682m

z4bn682m2#

简而言之,答案是肯定的,你将永远失去精确度。
您几乎无法避免这种情况,因为无论Float64的52位中有一半编码为零或其他数字(在位级上它们不是零),向下转换总是会发生,请参见https://en.wikipedia.org/wiki/Double-precision_floating-point_format
Mean()函数的问题在于它可能没有像您预期的那样处理精度。来自@tidakdiinginkan的答案确实很好地说明了这一点,因为加起来3500万到3900万行超过了最后一位数的精度,并开始偏离更大的程度。
将提供更好方法的代码是使用Decimal:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import decimal

x, y1, y2 = [], [], []
for idx, num in enumerate(range(1, 57, 2)):
    print(f"{idx+1}) Testing with {num} million records...")
    rows = num*(10**6)
    cols = ['col']

    df = pd.DataFrame(np.random.uniform(0, 9.761140e+02, size=(rows, len(cols))), columns=cols)
    df['col1'] = pd.to_numeric(df['col'], downcast='float')
    df['diff'] = df['col'] - df['col1']

    mean = df['col'].mean()
    mean32 = df['col1'].mean()
    diff = abs(mean - mean32)
    decmean = decimal.Decimal(df['col'].sum())/rows
    decmean32 = decimal.Decimal(float(df['col1'].sum()))/rows
    decdiff = abs(decmean - decmean32)

    #print("Mean:{}, Mean32:{}, MeanDec:{}, MeanDec32:{}".format(mean, mean32, decmean, decmean32))    
    x.append(num)
    y1.append(diff)
    y2.append(decdiff)

plt.plot(x, y1, 'ro', label='df.mean()')
plt.plot(x, y2, 'bo', label='Decimal(Sum(df))/num')
plt.yscale('log')
plt.title('Differences after to_numeric() float conversion with downcast')
plt.xlabel('number of rows (millions)')
plt.ylabel('precision value lost')
plt.legend()
plt.show()

并以图形方式比较:

相关问题