首页 > 解决方案 > 如何减少这段代码的内存使用并提高其速度?

问题描述

我正在运行一个循环遍历pandas数据帧的所有行的for循环,然后它计算从一个点到数据帧中所有其他点的欧几里得距离,然后它通过下一点,并做同样的事情事情,等等。

问题是我需要存储距离的值计数以稍后绘制直方图,我将其存储在另一个熊猫数据框中。问题是随着第二个数据帧变大,我有时会耗尽内存。更不用说随着数据帧大小的增长,重复同样的循环会变得更慢,因为它会更重,更难在内存中处理。

这是一些重现原始问题的玩具数据:

import pandas as pd

xx = []
yy = []
tt = []

for i in progressbar(range(1,655556)):
    xx.append(i)
    yy.append(i)
    tt.append(i)

df = pd.DataFrame()
df['xx'] = xx
df['yy'] = yy
df['tt'] = tt
df['xx'] = df['xx'].apply(lambda x : float(x))
df['yy'] = df['yy'].apply(lambda x : float(x))
df['tt'] = df['tt'].apply(lambda x : float(x))
df

这是我使用的原始代码:

counts = pd.DataFrame()

for index, row in df.iterrows():

    dist = pd.Series(np.sqrt((row.xx - df.xx)**2 + (row.yy - df.yy)**2 + (row.tt - df.tt)**2))
    counter = pd.Series(dist.value_counts( sort = True)).reset_index().rename(columns = {'index': 'values', 0:'counts'})   
    counts = counts.append(counter)

原始 df 的形状为 ,(695556, 3)因此预期结果应该是一个形状的数据框,(695556**3, 2)其中包含来自所有 3 个向量的所有距离值及其计数。问题是这不可能适合我的 16gb 内存。

所以我改为尝试这个:

for index, row in df.iterrows():
    counts = pd.DataFrame()
    dist = pd.Series(np.sqrt((row.xx - df.xx)**2 + (row.yy - combination.yy)**2 + (row.tt - df.tt)**2))
    counter = pd.Series(dist.value_counts( sort = True)).reset_index().rename(columns = {'index': 'values', 0:'counts'})   
    counts = counts.append(counter)
    counts.to_csv('counts/count_' + str(index) + '.csv')
    del counts

在这个版本中,我不只是将计数数据帧存储到内存中,而是为每个循环编写一个 csv。这个想法是在完成后将它们放在一起。此代码比第一个代码运行得更快,因为每个循环的时间不会随着数据帧大小的增长而增加。虽然,它仍然很慢,因为它每次都必须写一个 csv。并不是说当我必须将所有这些 csv 读入单个数据帧时它会更慢。

谁能告诉我如何优化此代码以实现这些相同的结果,但以更快和更节省内存的方式?我也对其他实现持开放态度,例如 spark、dask 或任何实现相同结果的方式:包含所有距离的值的数据帧,但在时间和内存方面可能或多或少方便。

非常感谢您提前

标签: pythonpython-3.xpandasdataframememory

解决方案


推荐阅读