Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/355.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python ndarray.resize:为refcheck参数传递正确的值_Python_Numpy - Fatal编程技术网

Python ndarray.resize:为refcheck参数传递正确的值

Python ndarray.resize:为refcheck参数传递正确的值,python,numpy,Python,Numpy,和其他许多人一样,我的情况是,我有一个类收集大量数据,并提供一个方法以numpy数组的形式返回数据。(即使在返回数组后,其他数据也可以继续流入)。因为创建数组是一项昂贵的操作,所以我只想在必要时创建它,并尽可能高效地创建它(具体地说,在可能的情况下在适当的位置追加数据) 为此,我读了一些关于ndarray.resize()方法和refcheck参数的书。我理解,只有在“确定没有与另一个Python对象共享此数组的内存”时,refcheck才应设置为False 问题是我不确定。有时我有,有时我没有

和其他许多人一样,我的情况是,我有一个类收集大量数据,并提供一个方法以numpy数组的形式返回数据。(即使在返回数组后,其他数据也可以继续流入)。因为创建数组是一项昂贵的操作,所以我只想在必要时创建它,并尽可能高效地创建它(具体地说,在可能的情况下在适当的位置追加数据)

为此,我读了一些关于ndarray.resize()方法和refcheck参数的书。我理解,只有在“确定没有与另一个Python对象共享此数组的内存”时,refcheck才应设置为False

问题是我不确定。有时我有,有时我没有。如果refcehck失败(我可以捕获它,然后创建一个新副本),我很乐意它会引发错误,但我希望它只有在存在“真实”的外部引用时才会失败,而忽略我知道是安全的引用

下面是一个简化的示例:

import numpy as np

def array_append(arr, values, refcheck = True):
    added_len = len(values)
    if added_len == 0:
        return arr
    old_len = len(arr)
    new_len = old_len + added_len
    arr.resize(new_len, refcheck = refcheck)
    arr[old_len:] = values
    return arr

class DataCollector(object):

    def __init__(self):
        self._new_data = []
        self._arr = np.array([])

    def add_data(self, data):
        self._new_data.append(data)

    def get_data_as_array(self):
        self._flush()
        return self._arr

    def _flush(self):
        if not self._new_data:
            return
#        self._arr = self._append1()
#        self._arr = self._append2()
        self._arr = self._append3()
        self._new_data = []

    def _append1(self):
        # always raises an error, because there are at least 2 refs:
        # self._arr and local variable 'arr' in array_append()
        return array_append(self._arr, self._new_data, refcheck = True)

    def _append2(self):
        # Does not raise an error, but unsafe in case there are other
        # references to self._arr
        return array_append(self._arr, self._new_data, refcheck = False)

    def _append3(self):
        # "inline" version: works if there are no other references
        # to self._arr, but raises an error if there are.
        added_len = len(self._new_data)
        old_len = len(self._arr)
        self._arr.resize(old_len + added_len, refcheck = True)
        self._arr[old_len:] = self._new_data
        return self._arr

dc = DataCollector()
dc.add_data(0)
dc.add_data(1)
print dc.get_data_as_array()
dc.add_data(2)
print dc.get_data_as_array()
x = dc.get_data_as_array()  # create an external reference
print x.shape
for i in xrange(5000):
    dc.add_data(999)
print dc.get_data_as_array()
print x.shape
问题:

  • 有没有更好(更快)的方法来完成我想做的事情(以增量方式创建numpy数组)
  • 有没有办法告诉resize()方法:“执行refcheck,但忽略我知道是安全的一个(或n个)引用”?(这将解决_append1()总是失败的问题)

  • 我将使用
    array.array()
    进行数据收集:

    import array
    a = array.array("d")
    for i in xrange(100):
        a.append(i*2)
    
    每次要对收集的数据进行计算时,请通过
    numpy.frombuffer
    将其转换为
    numpy.ndarray

    b = np.frombuffer(a, dtype=float)
    print np.mean(b)
    

    b
    将与
    a
    共享数据内存,因此转换非常快。

    调整
    大小的方法有两个主要问题。首先,当用户调用
    get\u data\u as\u array
    时,返回对self的引用。现在,resize将根据您的实现执行以下两个操作之一。它要么修改你给你的用户的数组,即用户将采用
    a.shape
    ,形状将发生不可预测的变化。否则会损坏该数组,使其指向坏内存。您可以通过始终使用
    get\u data\u as\u array
    return
    self.\u arr.copy()
    来解决该问题,但这就引出了第二个问题<代码>调整大小
    实际上效率不高。我认为,通常情况下,resize必须分配新内存,并在每次调用它时进行一次拷贝,以增加阵列。另外,现在您需要在每次希望将阵列返回给用户时复制阵列

    另一种方法是设计自己的,类似于:

    class DynamicArray(object):
    
        _data = np.empty(1)
        data = _data[:0]
        len = 0
        scale_factor = 2
    
        def append(self, values):
            old_data = len(self.data)
            total_data = len(values) + old_data
            total_storage = len(self._data)
            if total_storage < total_data:
                while total_storage < total_data:
                    total_storage = np.ceil(total_storage * self.scale_factor)
                self._data = np.empty(total_storage)
                self._data[:old_data] = self.data
    
            self._data[old_data:total_data] = values
            self.data = self._data[:total_data]
    
    class-DynamicArray(对象):
    _数据=np.空(1)
    数据=_数据[:0]
    len=0
    比例系数=2
    def append(自身、值):
    旧数据=len(self.data)
    总数据=长度(值)+旧数据
    总存储量=长度(自身数据)
    如果总存储<总数据:
    总存储<总数据:
    总存储量=np.ceil(总存储量*自身比例系数)
    self.\u data=np.empty(总存储量)
    self.\u数据[:旧的\u数据]=self.data
    自身数据[旧数据:总数据]=值
    self.data=self.\u数据[:总数据]
    
    这应该非常快,因为您只需要将阵列日志(N)增加一倍,并且最多使用2*N-1存储,其中N是阵列的最大大小。除了增加数组之外,您只需查看
    \u数据
    ,这不涉及任何复制,应该是固定时间


    希望这是有用的。

    这很酷,解决了数字类型的问题。然而,在我的现实问题中,我收集带有数字、字符串和对象的记录(并从中创建一个重新排列)。另外,@HYRY您能在您的示例中解释一下这种数据共享是如何工作的吗?当再次调用a.append()时需要重新分配共享数据时会发生什么情况?
    a.append()
    可能会重新分配内存,因此您不能使用以前创建的
    ndarray
    ,每次需要对数据进行计算时,您都通过
    np.frombuffer(a)创建
    ndarray
    。如果我仍然持有对
    np.frombuffer(a)
    的旧结果的引用?它还能用吗?我的意思是,它是否会被破坏,或者只是防止旧内存被垃圾收集(由于ref计数)?在这种情况下,这不是解决我问题的有效方法。我不能给调用者一个后来变得不可用的引用…这个解决方案的缺点是它平均多使用50%的内存,这在我的例子中意味着几GB。但当然,在大小和速度之间有一个折衷,在我看来,速度可能更重要。我很快就会试一试。