【问题标题】:Memory error utilizing numpy arrays Python使用numpy数组Python的内存错误
【发布时间】:2021-01-18 02:26:00
【问题描述】:

我原来的 list_ 函数有超过 200 万行代码,当我运行计算 .有没有办法可以绕过它。下方的 list_ 是实际 numpy 数组的一部分。

熊猫数据:

import pandas as pd
import math
import numpy as np
bigdata = 'input.csv'
data =pd.read_csv(Daily_url, low_memory=False)
#reverses all the table data values
data1 = data.iloc[::-1].reset_index(drop=True)
list_= np.array(data1['Close']

代码:

number = 5
list_= np.array([457.334015,424.440002,394.795990,408.903992,398.821014,402.152008,435.790985,423.204987,411.574005,
404.424988,399.519989,377.181000,375.467010,386.944000,383.614990,375.071991,359.511993,328.865997,
320.510010,330.079010,336.187012,352.940002,365.026001,361.562012,362.299011,378.549011,390.414001,
400.869995,394.773010,382.556000])

def rolling_window(a, window):
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

std = np.std(rolling_window(list_, number), axis=1)

错误信息:MemoryError: Unable to allocate 198. GiB for an array with shape (2659448, 10000) and data type float64

错误信息的全长:

MemoryError                               Traceback (most recent call last)
<ipython-input-7-df0ab5649b16> in <module>
      5     return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
      6 
----> 7 std1 = np.std(rolling_window(PC_list, number), axis=1)

<__array_function__ internals> in std(*args, **kwargs)

C:\Python3.7\lib\site-packages\numpy\core\fromnumeric.py in std(a, axis, dtype, out, ddof, keepdims)
   3495 
   3496     return _methods._std(a, axis=axis, dtype=dtype, out=out, ddof=ddof,
-> 3497                          **kwargs)
   3498 
   3499 

C:\Python3.7\lib\site-packages\numpy\core\_methods.py in _std(a, axis, dtype, out, ddof, keepdims)
    232 def _std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False):
    233     ret = _var(a, axis=axis, dtype=dtype, out=out, ddof=ddof,
--> 234                keepdims=keepdims)
    235 
    236     if isinstance(ret, mu.ndarray):

C:\Python3.7\lib\site-packages\numpy\core\_methods.py in _var(a, axis, dtype, out, ddof, keepdims)
    200     # Note that x may not be inexact and that we need it to be an array,
    201     # not a scalar.
--> 202     x = asanyarray(arr - arrmean)
    203 
    204     if issubclass(arr.dtype.type, (nt.floating, nt.integer)):

MemoryError: Unable to allocate 198. GiB for an array with shape (2659448, 10000) and data type float64

【问题讨论】:

  • 其实大处理,可以考虑最小化到n个部分,或者放到文件中逐行枚举。
  • @TấnNguyên list_ 值位于 csv 文件中,我使用 pandas 获取值,然后将 pandas 列转换为 numpy 数组。
  • 这有几种方法,用pandas获取值的时候,有没有优化加载?例如,您可以加载您使用的列,并逐行处理。您可以在这里查看更多详细信息:pandas.pydata.org/pandas-docs/stable/user_guide/scale.html
  • @TấnNguyên 我已经做了这些我会为你更新细节
  • Pandas 已经通过df.rolling(n) 支持滚动窗口的各种数据聚合。 Here 是它的文档!

标签: python function numpy out-of-memory numpy-ndarray


【解决方案1】:

请帮我们参考您之前的相关问题(至少 2 个)。我碰巧记得看到过类似的东西,所以请查看您之前的问题。

此外,在询问错误时,请显示完整的回溯(如果可能)。我们(和)应该确定问题发生的位置,并缩小可能的原因和修复范围。

对于只有 (35,) 形状的样本 list_(为什么 numpy 数组的名字这么糟糕?),rolling_window 数组并没有那么大。另外它是view

In [90]: x =rolling_window(list_, number)
In [91]: x.shape
Out[91]: (26, 5)

但是,对该数组的操作可能会产生副本,从而增加内存使用量。

在 [96] 中:np.std(x, axis=1) 出[96]: 数组([22.67653383, 10.3940773, 14.60076482, 13.82801944, 13.68038469, 12.54834004, ... 8.07511323]) 在 [97] 中:_.shape 出 [97]: (26,)

np.std 会:

std = sqrt(mean(abs(x - x.mean())**2))

x.mean(axis=1) 是每行一个值,但是

In [102]: x.mean(axis=1).shape
Out[102]: (26,)
In [103]: (x-x.mean(axis=1, keepdims=True)).shape
Out[103]: (26, 5)
In [106]: (abs(x-x.mean(axis=1, keepdims=True))**2).shape
Out[106]: (26, 5)

产生一个和x一样大的数组,并且是一个完整的副本;不是跨步的虚拟副本。

错误信息的形状有意义吗? (2659448, 10000) 你的 window 尺寸是 10000 吗?以及其他值的预期窗口数?

198. GiB 是一个合理的数字,考虑到该维度:

In [94]: 2659448*10000*8/1e9
Out[94]: 212.75584

我不会用足够大的数组来测试你的代码以产生内存错误。

as_strided 是一种生成移动窗口的好方法,而且速度很快 - 但它很容易消耗内存。

【讨论】:

  • 只是想知道,既然这需要一个窗口,那么 OP 不能更好地使用np.memmap 来减少 RAM 使用吗?
  • @CodeNoob, memmap 可用于用户创建的数组,但问题在于 np.std 在计算过程中创建的数组。
  • @hpaulj 我已经更新了问题的详细信息,包括 pandas 库以及我如何获取数据。我还发布了完整的错误消息。我看到没有太多方法可以通过具有记忆功能的索引 numpy 数组。是否有任何其他库可以让我通过如此大的列表值并执行数学方程?
  • 你可以在块上计算这个std。我不知道有多少。 100 个块可以将内存需求减少到每个 2gB。如果我最初没记错的话,您正在遍历所有 2659448 个窗口,一次一个。在大小为 26595 的窗口上迭代 100 次可能是一个合理的折衷方案。
  • @hpaulj 好的,我会尝试将它分成块有没有办法可以像列表一样索引 numpy list[:n]
【解决方案2】:

一般来说,处理“cannot allocate 198GiB of memory”有两种方式:

  • 分块或逐行处理数据。

    您的算法似乎适用于此;与其一次读取所有数据,不如重写rolling_window 函数,使其加载初始窗口(文件的第一行n),然后重复删除一行并从文件中读取一行。这样一来,您的内存将永远不会超过 n 行,而且一切正常。

    如果是本地文件,可以在整个计算过程中保持打开状态,这是最简单的。如果是远程对象,您可能会发现连接超时;如果是这样,您可能需要将数据复制到本地文件,或使用相关的 seek/offset 参数为每​​个附加行(或每个附加块,您在本地缓冲)重新打开文件。

  • 或者,购买(租用)一台内存超过 200 GiB 的机器; AWS 提供现成的内存超过 1 TiB 的机器(可能是 GCP 和 Azure;或直接购买)。

    如果您有理由确定您的需求不会进一步增长并且您只需要完成这一项工作,那么这尤其适合。它可以让您避免重写代码来处理这个问题,但从长远来看,这不是一个可持续的解决方案。

【讨论】:

  • 好的,谢谢你,它会尝试解决这个问题。
  • 我一直试图将它理解成块,但似乎没有用有没有办法我可以这样组织它。
  • pandas.read_csv 函数有iteratorchunksize 选项。或许可以在带有 iterator=True, chunksize=3 或类似名称的小文件上对它们进行试验,以了解其工作原理?
  • 关于基于块计算标准差,请看runstats library
  • 抱歉打扰了,但我已经尝试过块大小等,但它并没有真正帮助,而是我尝试实现多处理并将 for 循环分成块。我对此提出了问题issue。如果您能快速浏览一下,将不胜感激。
猜你喜欢
  • 2011-05-18
  • 2017-11-05
  • 1970-01-01
  • 2012-07-31
  • 1970-01-01
  • 2011-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多