自定义平均值实现比默认平均值慢。如何优化?

2024-03-28 10:48:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我想找出熊猫的平均数。所以我使用了熊猫默认提供的以下平均值函数。Link to its doc

df.mean()

但该函数的问题是,如果所有值的总和大于数据类型的限制,则会发生溢出。在我的例子中,我有float16的数据,记录数超过2000万条。很明显,所有记录的总数都会溢出float16。一种方法是将数据类型更改为float64,但这将使用太多的额外内存,因为每个值都在~1900-2100范围内。所以我想用here给出的方法迭代实现mean。下面是我对pandas数据帧的实现

def mean_without_overflow(df):
    avgs = []
    for column in df:
        avg, t = 0, 1
        for data in df[column]:
            if not math.isnan(data):
                avg += (data-avg) / t;
                t += 1
        avgs.append(avg)
    return avgs

对于每一列,我迭代所有行。所以总的迭代次数将是# of columns * # of records。但是,这不会溢出,并给出整个数据帧的正确平均值,但比pandas提供的默认平均值函数慢得多。你知道吗

所以我在这里错过了什么?我如何优化它?或者熊猫有没有现成的函数可以用来迭代求平均值?你知道吗

编辑: 在计算平均值时,溢出似乎是一个常见的问题。我想知道为什么pandas中的默认mean()没有使用这样一种迭代方法来实现,这种方法可以防止在范围较小的数据类型中发生溢出。你知道吗


Tags: 数据方法函数pandasdffordata记录
3条回答

如果我错了,请纠正我,但我相信:

sum(l) / len(l) = sum(l[:n]) / len(l) + sum(l[n:2*n]) / len(l) + ...

这意味着您可以按大小n批量np.sum,这样n * 2100 < max_float16

我自己找到了解决办法。逻辑是首先将所有值标准化,将其除以序列长度(#个记录),然后使用默认值df.mean(),然后将标准化的平均值乘以#个记录:这是一个从1分37秒到3.13秒的改进。但是我仍然不明白为什么熊猫实现没有使用这样的优化。你知道吗

def mean_without_overflow_fast(col):
    col /= len(col)
    return col.mean() * len(col)

按如下方式使用此功能:

print (df.apply(mean_without_overflow_fast))

在pandas中循环很慢,所以可以使用apply。你知道吗

def mean_without_overflow(column):
    avg, t = 0, 1
    for data in column:
        if not math.isnan(data): 
            avg += (data-avg) / t
            t += 1 
    return avg

然后我们可以计算出df的整个平均值。你知道吗

mean_df = np.mean(df.apply(mean_without_overflow))

以上脚本与

mean_df = np.mean(df.apply(np.mean))

相关问题 更多 >