即使最大的(9.761140e+02)和最小的(0.000000e+00)元素适用于flat32,将Pandas Dataframe (按列)从flat64向下转换也会导致精度下降。数据集非常大,5500万行乘以12列。这是没有向下预测的特定列的平均值(1.343987e+00),之后是1.224472e+00。与使用np.astype()得到的结果相同。
np.astype()
ru9i0ody1#
这是一个非常有趣的问题。我测试了几个 Dataframe ,从100万条记录到5500万条记录,大小与您的相同,保持min、max的值与您拥有的值相似。
min
max
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万条记录之后,精度的损失突然增加,本质上似乎是对数的。我还没弄明白为什么会是这样。
z4bn682m2#
简而言之,答案是肯定的,你将永远失去精确度。您几乎无法避免这种情况,因为无论Float64的52位中有一半编码为零或其他数字(在位级上它们不是零),向下转换总是会发生,请参见https://en.wikipedia.org/wiki/Double-precision_floating-point_formatMean()函数的问题在于它可能没有像您预期的那样处理精度。来自@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()
并以图形方式比较:
2条答案
按热度按时间ru9i0ody1#
这是一个非常有趣的问题。我测试了几个 Dataframe ,从100万条记录到5500万条记录,大小与您的相同,保持
min
、max
的值与您拥有的值相似。故事情节是这样的。
根据剧情,似乎在3500万条记录之后,精度的损失突然增加,本质上似乎是对数的。我还没弄明白为什么会是这样。
z4bn682m2#
简而言之,答案是肯定的,你将永远失去精确度。
您几乎无法避免这种情况,因为无论Float64的52位中有一半编码为零或其他数字(在位级上它们不是零),向下转换总是会发生,请参见https://en.wikipedia.org/wiki/Double-precision_floating-point_format
Mean()函数的问题在于它可能没有像您预期的那样处理精度。来自@tidakdiinginkan的答案确实很好地说明了这一点,因为加起来3500万到3900万行超过了最后一位数的精度,并开始偏离更大的程度。
将提供更好方法的代码是使用Decimal:
并以图形方式比较: