【问题标题】:How can I better manage my use of memory in Pandas?如何更好地管理我在 Pandas 中的内存使用?
【发布时间】:2014-05-29 07:03:30
【问题描述】:

我正在使用 Pandas 来存储、加载和操作财务数据。一个典型的数据文件是一个 6000x4000 的 DataFrame(6000 个股票 x 4000 个交易日期),如果说一半的股票在给定日期的价值为 N/A,则 CSV 格式的大小为 200MB。我一直在使用具有 16GB 内存的工作站,这足以将这种大小的整个 CSV 加载到内存中,执行各种计算,然后存储结果。在典型的一天中,我最终会在高峰使用期间使用大约 10GB 的 RAM。我觉得我可以更有效地做事。我想把这个数字降低到 2GB 左右,这样我就可以使用具有 4GB RAM 的普通笔记本电脑运行我的几个型号的每日更新。这合理吗?无论我的硬件如何,我是否都使用了太多内存?

我了解上述问题的答案取决于我正在做的事情的细节。这是我可能运行的函数类型的示例:

def momentum_strategy():
    # prices.csv is a matrix containing stock prices for 6000 stocks
    # and 4000 trading dates
    prices = pd.read_csv("prices.csv")
    # Daily stock returns
    returns = prices/prices.shift(1) -1 
    # Annualized return volatility
    volatility = pd.rolling_std(returns, 21, 21) * 252**0.5
    # 6-month stock returns
    trail6monthreturns = prices/prices.shift(21*6) - 1
    # Rank of 6 month stock returns
    retrank = trail6monthreturns.rank(axis=1, ascending=False)
    # Portfolio of the top 100 stocks as measured by 6 month return
    positions = retrank.apply(lambda x: np.where(x<= 100, 1, np.nan))
    # Daily returns for top 100 stocks
    uptrendreturns = positions * returns
    # Daily return for 100 stock portfolio
    portfolioreturns = uptrendreturns.mean(1)
    return positions, portfolioreturns

我的一个想法是使用 HDF5 存储格式而不是 CSV,因为通过最近的测试以及对 pandas 文档和 stackoverlfow 的阅读,我发现输入/输出速度更快,并且在此类操作期间占用的内存更少。对此有什么想法吗?例如,我将每日开盘价、最高价、最低价、收盘价、交易量、流通股数、市盈率、盈利增长和另外 30 种不同的指标存储在单独的 CSV 中(如上例中,通常为 6000 只股票 x每个 4000 个交易日期)。如果建议切换到 HDF5,我应该将这些相同的 DataFrame 存储在 30 多个单独的 H5 文件中吗?

在上面的函数中,如果我想在函数完成后访问一些中间结果,但不占用内存,将结果存储在包含 HDF5 的“temp”文件夹中是否有意义文件?例如:

def momentum_strategy_hdf5():
    # prices.csv is a matrix containing stock prices for 6000 stocks
    # and 4000 trading dates
    prices = pd.read_csv("prices.csv")
    s = pd.HDFStore("temp.h5")
    # Daily stock returns
    s['returns'] = prices/prices.shift(1) -1 
    # Annualized return volatility
    s['volatility'] = pd.rolling_std(s['returns'], 21, 21) * 252**0.5
    # 6-month stock returns
    s['trail6monthreturns'] = prices/prices.shift(21*6)
    # Rank of 6 month stock returns
    s['retrank'] = s['trail6monthreturns'].rank(axis=1, ascending=False)
    # Portfolio of the top 100 stocks as measured by 6 month return
    s['positions'] = s['retrank'].apply(lambda x: np.where(x<= 100, 1, np.nan))
    # Daily returns for top 100 stocks
    s['uptrendreturns'] = s['positions'] * s['returns']
    # Daily return for 100 stock portfolio
    s['portfolioreturns'] = s['uptrendreturns'].mean(1)
    return s['positions'], s['portfolioreturns']

编辑:我刚刚测试了上面两个函数,第一个用了15秒,第二个用了42秒。所以写的第二个要慢得多,但希望有更好的方法吗?

【问题讨论】:

  • 如果你的数据框大部分是空的,你有没有看过使用sparse structures
  • 谢谢,我刚刚用它做了一些测试。您确定 to_sparse() 会对 DataFrame 产生内存影响吗?我刚刚尝试在 Series 和 DataFrames 上使用它。我能够在 Series 但不是 DataFrames 上使用 to_sparse() 来节省内存。虽然,当我为 DataFrame 以二进制形式写入磁盘时,我确实看到空间减少了。

标签: python pandas hdf5


【解决方案1】:

这是此类数据的典型工作流程:

  • 1) 读取 csv 数据,转换为 DataFrame,强制数据类型,使用HDFStore 写出(取决于您的需要可以是“固定”或“表格”格式)。这样做是一个单独的过程,然后退出该过程。当数据集很大时,我以逻辑格式(例如日期范围)读取它,然后输出一个“表格”格式的 HDF5 文件。然后可以追加到这个。

  • 2) 查询(同样可以是日期或其他一些条件)。执行计算,然后写出 NEW HDF5 文件。这可以并行完成(多个进程)。确保您在每个进程中编写单独的文件。

  • 3) 将先前的数据文件合并为单个 HDF5 文件。这是一个单进程事件。

  • 4) 根据需要重复 2 和 3。

关键是执行离散的步骤,在中间写出中间数据,并在中间退出进程。这保持了可管理的内存数据大小,并使内存计算快速。此外,这允许对只读 HDF5 文件的 CPU 密集型操作进行多次处理。

重要的是在单独的系统进程中执行此操作以允许系统回收内存。

HTH

【讨论】:

  • 非常感谢杰夫!需要明确的是,当您说使用单独的进程时,您的意思是使用来自多处理的进程,如下所示:stackoverflow.com/a/2046630/3389318
  • 另外,我读到使用 HDF5 处理少于 20k 行的数据可能比使用 pickle 慢。由于我的数据只有 4k 行,我应该改用 pickle 吗?
  • 您在问题中指出您的数据要大得多,所以 YMMV。对于所有数据,我更喜欢 HDF5。
  • 我的数据(与问题相同)是 4000 行 x 6000 列。在 pandas 文档中,它只提到了行数(20k)作为是否使用 HDF5 的指导。由于您推荐 HDF5 用于所有数据,我将尝试两者。再次感谢!
【解决方案2】:

虽然我没有太多使用 HDF5 文件的经验,但我会推荐三个 Python 库,它们可能会让你朝着更好的方向前进

H5py 是一个 Python 库,专门用于对二进制格式的文件进行编码和解码。我并不是说它比 Pandas HDFstore 更好(我发现 Pandas 在处理大量 2.2M x 24 的数据方面非常出色),但它可能会奏效。

PyTables 已在内存管理对话中多次提及。我没有使用这个库的经验,但我在处理memory/HDf5 problems 的讨论中看到了它。

mmap 是一个用于内存映射的库(将数据从磁盘移动到内存中进行操作而不使用二进制格式的过程)。如果您猜到我没有使用此库的经验,那么您将是赢家。

同样,我不能从这里的经验谈太多,但我认为这三种方法可能会让你在处理大型数据集时更好地利用 Python 的内存。

【讨论】:

    猜你喜欢
    • 2016-07-20
    • 1970-01-01
    • 1970-01-01
    • 2020-09-04
    • 1970-01-01
    • 1970-01-01
    • 2015-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多