python生成数组内存爆,关于python:是否存在与内存使用类似的任何对象(如生成器),但在必要时可以返回numpy数组?...

我有一些时间数据,它们从T0开始并以dt的步长转到T1。此数据以dt的小增量递增,当前存储为numpy数组,因此占用大量空间。一种更有效的存储方式是存储T0,T1和dt,例如使用发电机。但是,生成器不能使用许多功能,例如numpy函数,算术和绘图。我想要一个类似于生成器的东西,即仅存储3个必要的值,然后在必要时生成一个numpy数组以用于某些功能。

是否已经存在像这样工作的对象?即将必要的数据(3个值)存储在生成器中,然后在用于函数或算术运算时将其自身返回/表示为numpy数组?然后,仅在函数范围内使用内存,而在超出范围时才释放内存。

使用解决方案进行编辑:我创建了自己想要的实现。复制生成器非常棘手,请参见此处,因此我改为存储start,stop和step并根据需要创建和返回生成器或numpy数组。

的代码如下:

import numpy as _np

class frange():

"""

Return an object can be used to generate a generator or an array

of floats from start (inclusive) to stop (exclusive) by step.

This object stores the start, stop, step and length of

the data. Uses less memory than storing a large array.

Example

-------

An example of how to use this class to generate some data is

as follows for some time data between 0 and 2 in steps of

1e-3 (0.001)::

$ time = frange(0, 2, 1e-3)

$ printlen(time) # prints length of frange, just like an array or list

$ generator = time.get_generator() # gets a generator instance

$ for i in generator: # iterates through printing each element

$     print(i)

$ array = time.get_array() # gets an array instance

$ newarray = 5 * array # multiplies array by 5

"""

def __init__(self, start, stop, step):

"""

Intialises frange class instance. Sets start, top, step and

len properties.

Parameters

----------

start : float

starting point

stop : float

stopping point

step : float

stepping interval

"""

self._slice = slice(start, stop, step)

self.len = self.get_array().size

return None

def get_generator(self):

"""

Returns a generator for the frange object instance.

Returns

-------

gen : generator

A generator that yields successive samples from start (inclusive)

to stop (exclusive) in step steps.

"""

s = self._slice

gen = drange(s.start, s.stop, s.step) # intialises the generator

return gen

def get_array(self):

"""

Returns an numpy array containing the values from start (inclusive)

to stop (exclusive) in step steps.

Returns

-------

array : ndarray

Array of values from start (inclusive)

to stop (exclusive) in step steps.

"""

s = self._slice

array = _np.arange(s.start, s.stop, s.step)

return array

def __len__(self):

return self.len

def drange(start, stop, step):

"""

A generator that yields successive samples from start (inclusive)

to stop (exclusive) in step intervals.

Parameters

----------

start : float

starting point

stop : float

stopping point

step : float

stepping interval

Yields

------

x : float

next sample

"""

x = start

if step > 0:

while x + step <= stop: # produces same behaviour as numpy.arange

yield x

x += step

elif step < 0:

while x + step >= stop: # produces same behaviour as numpy.arange

yield x

x += step

else:

raise ZeroDivisionError("Step must be non-zero")

这个答案可能会解决您的问题。

如果您使用的是python 3,那么您已经通过使用range来获取了。 但是,多数民众赞成仅用于整数。 如果要对浮点数执行类似的操作,它将变得更加复杂。

确实,我想要一些类似于范围的功能,但对于浮点数,并且可以在numpy函数中使用。

您应该创建一个最小的可复制示例,并将该代码引入问题中。 这样一来,在将来某个时候链接消失的情况下,问题就可以独立解决。

Python已经有一个存储start, stop, step属性的类,一个slice

In [523]: s = slice(0, 1, .1)

np.lib.index_tricks具有可以扩展切片的类。在这种情况下,它使用arange:

In [524]: np.r_[s]

Out[524]: array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9])

In [525]: np.arange(s.start, s.stop, s.step)

Out[525]: array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9])

In [526]: np.arange(0, 1, .1)

Out[526]: array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9])

slice仅存储其属性;任何计算都由使用它的代码完成。如果step的值为虚数,则np.r_使用此技巧来调用np.linspace。

In [527]: np.r_[slice(0,1,11j)]

Out[527]: array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9,  1. ])

我看不到另一个答案中讨论的生成器如何对动态运行arange或linspace的改进。

如果您正在开发自己的索引类,则值得研究index_tricks.py文件。

我不知道切片,它们绝对是可能的解决方案。尽管它们有缺点,但它们不是可迭代的。

就其本身而言,slice是不可迭代的。它不存储这三个值。通常,python解释器会将x[1:3:2]转换为x.__getitem__(slice(1,3,2))。换句话说,它是存储1:2:3表达式元素的一种方式。

与使用原始切片相比,稍有改进是创建一个可以用__array__强制转换为数组的类:

class range_array(object):

def __init__(*args):

self._slice = slice(*args)

def __array__(self):

s = self._slice

return np.arange(s.start, s.stop, s.step)

这意味着这样的代码将起作用:

a = range_array(T0, T1, dt)

res = np.dot(a, a)

您可以更进一步,并在numpy 1.13中实现__array_ufunc__:

class range_array(np.lib.mixins.NDArrayOperatorsMixin):

def __init__(start, stop, step):

sl = slice(*args)

self._start = sl.start

self._stop = sl.stop

self._step = sl.step

def __array__(self):

return np.arange(self._start, self._stop, self._step)

def __array_ufunc__(self, ufunc, method, args, kwargs):

# special case np.add(range, 1) to just add to stop and start, etc

我无法让您的__array __(self)方法正常工作。当我执行它时,我得到以下信息:

In [9]: class range_array(object): ...: def __init__(self, *args): ...: self._slice = slice(*args) ...: ...: def __array__(self): ...: s = self._slice ...: return np.arange(s.start, s.stop, s.step) ...: In [10]: a = range_array(0, 10, 0.1) ...: res = np.dot(a, a) ...:

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) in () 1 a = range_array(0, 10, 0.1) ----> 2 res = np.dot(a, a) 3

每个生成器都可以转换为具有列表理解的列表或numpy数组,如下所示:

def mygenerator(T0, T1, dt):

while T0

T0 += dt

yield T0

def gen2numpy(gen):

return np.array([item for item in gen])

我使用了一个非常幼稚的生成器,该生成器对T0, T1, dt进行了很多假设,但这是因为您没有提供有助于这些假设的代码...不管怎样,请看看我如何将生成器转换为numpy数组

如果您正在寻找一个可以同时实现两者的对象,请定义一个类并将这些函数用作其方法

但是要小心-迭代生成器,甚至是部分迭代,然后生成列表只会给出部分列表或错误。如果必须在创建列表之前进行迭代,我建议创建2个相同的(但独立的)生成器,一个用于迭代,另一个用于以后需要完整列表的情况...

我计划创建一个完全实现此目的的类,但是我想检查是否没有内置的类以更健壮和有效的方式提供此功能。我以为是这种情况不存在?

并不是我所知道的,但是就像您看到的那样,将生成器转换为列表是一种单线方式,并且尽可能高效,但是我也为我的回答添加了警告...

嗯,我看到了这个问题,也许一种解决方案是拥有用户无法访问的迭代器的受保护的私有副本,并且每次访问该类时,都返回一个供用户使用的新迭代器。

那行得通!

我在这里创建了一个最小的实现。复制生成器非常棘手,请参见此处,因此我改为存储start,stop和step并根据需要创建和返回生成器或numpy数组。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值