135

Pythonで効率的な循環バッファーを作成したい(バッファー内の整数値の平均を取ることを目的としています)。

これは、リストを使用して値を収集する効率的な方法ですか?

def add_to_buffer( self, num ):
    self.mylist.pop( 0 )
    self.mylist.append( num )

何がより効率的でしょうか (そしてその理由)?

4

14 に答える 14

251

私は引数で使用collections.dequeしますmaxlen

>>> import collections
>>> d = collections.deque(maxlen=10)
>>> d
deque([], maxlen=10)
>>> for i in xrange(20):
...     d.append(i)
... 
>>> d
deque([10, 11, 12, 13, 14, 15, 16, 17, 18, 19], maxlen=10)

ドキュメントには、あなたが望むものに似たレシピがあります。dequeそれが最も効率的であるという私の主張は、一流のコードを作成する習慣がある信じられないほど熟練した乗組員によって C で実装されているという事実に完全に基づいています。

于 2010-11-11T04:29:13.860 に答える
14

リストの先頭からポップすると、リスト全体がコピーされるため、非効率的です

代わりに、固定サイズのリスト/配列と、アイテムを追加/削除するときにバッファを移動するインデックスを使用する必要があります

于 2010-11-11T04:28:06.653 に答える
12

MoonCactus の答えに基づいて、ここにcircularlistクラスがあります。彼のバージョンとの違いは、ここで c[0]は常に、最後に追加された要素、最後c[-1]に追加された要素、c[-2]最後から 2 番目の要素が提供されることです。これは、アプリケーションにとってより自然です。

c = circularlist(4)
c.append(1); print(c, c[0], c[-1])    #[1] (1/4 items)              1  1
c.append(2); print(c, c[0], c[-1])    #[1, 2] (2/4 items)           1  2
c.append(3); print(c, c[0], c[-1])    #[1, 2, 3] (3/4 items)        1  3
c.append(8); print(c, c[0], c[-1])    #[1, 2, 3, 8] (4/4 items)     1  8
c.append(10); print(c, c[0], c[-1])   #[2, 3, 8, 10] (4/4 items)    2  10
c.append(11); print(c, c[0], c[-1])   #[3, 8, 10, 11] (4/4 items)   3  11
d = circularlist(4, [1, 2, 3, 4, 5])  #[2, 3, 4, 5]

クラス:

class circularlist(object):
    def __init__(self, size, data = []):
        """Initialization"""
        self.index = 0
        self.size = size
        self._data = list(data)[-size:]

    def append(self, value):
        """Append an element"""
        if len(self._data) == self.size:
            self._data[self.index] = value
        else:
            self._data.append(value)
        self.index = (self.index + 1) % self.size

    def __getitem__(self, key):
        """Get element by index, relative to the current index"""
        if len(self._data) == self.size:
            return(self._data[(key + self.index) % self.size])
        else:
            return(self._data[key])

    def __repr__(self):
        """Return string representation"""
        return (self._data[self.index:] + self._data[:self.index]).__repr__() + ' (' + str(len(self._data))+'/{} items)'.format(self.size)
于 2016-11-24T11:01:53.737 に答える
7

Python の deque は遅いです。代わりに numpy.roll を使用することもでき ます。形状 (n,) または (n,1) の numpy 配列で数値をどのように回転させますか?

このベンチマークでは、deque は 448ms です。Numpy.roll は 29ms http://scimusing.wordpress.com/2013/10/25/ring-buffers-in-pythonnumpy/

于 2014-11-26T11:46:39.897 に答える
3

このかなり古いPython レシピも参照できます。

NumPy配列を使用した私自身のバージョンは次のとおりです。

#!/usr/bin/env python

import numpy as np

class RingBuffer(object):
    def __init__(self, size_max, default_value=0.0, dtype=float):
        """initialization"""
        self.size_max = size_max

        self._data = np.empty(size_max, dtype=dtype)
        self._data.fill(default_value)

        self.size = 0

    def append(self, value):
        """append an element"""
        self._data = np.roll(self._data, 1)
        self._data[0] = value 

        self.size += 1

        if self.size == self.size_max:
            self.__class__  = RingBufferFull

    def get_all(self):
        """return a list of elements from the oldest to the newest"""
        return(self._data)

    def get_partial(self):
        return(self.get_all()[0:self.size])

    def __getitem__(self, key):
        """get element"""
        return(self._data[key])

    def __repr__(self):
        """return string representation"""
        s = self._data.__repr__()
        s = s + '\t' + str(self.size)
        s = s + '\t' + self.get_all()[::-1].__repr__()
        s = s + '\t' + self.get_partial()[::-1].__repr__()
        return(s)

class RingBufferFull(RingBuffer):
    def append(self, value):
        """append an element when buffer is full"""
        self._data = np.roll(self._data, 1)
        self._data[0] = value
于 2013-10-03T10:47:29.710 に答える
2

シリアルプログラミングを行う前に、この問題が発生しました。ちょうど 1 年ほど前の時点でも、効率的な実装を見つけることができなかったので、C 拡張機能として 1 つ作成することになり、MIT ライセンスの下で pypiでも利用できます。これは非常に基本的なもので、8 ビットの符号付き char のバッファーのみを処理しますが、長さが柔軟であるため、char 以外のものが必要な場合は、Struct またはその上に何かを使用できます。最近はいくつかのオプションがあることがグーグル検索でわかりましたので、それらも見たいと思うかもしれません.

于 2016-12-07T20:30:20.650 に答える