1. ホーム
  2. python

[解決済み] numpyの数値配列の最速の成長方法

2023-04-02 06:48:27

質問

要求事項

  • データから配列を任意に大きくしたい。
  • サイズが推測できる(だいたい100~200)が、毎回配列が収まるという保証はない
  • 最終的なサイズに成長したら、私はそれに対して数値計算を実行する必要があるので、最終的には2次元numpy配列になることを望みます。
  • スピードは重要です。例として、300個のファイルのうち1個について、update()メソッドが4500万回呼ばれ(150sくらいかかる)、finalize()メソッドが500k回呼ばれ(合計106sかかる)・・・合計250sくらいかかる。

以下は私のコードです。

def __init__(self):
    self.data = []

def update(self, row):
    self.data.append(row)

def finalize(self):
    dx = np.array(self.data)

その他、以下のようなコードも試しましたが......これはワザと遅くしています。

def class A:
    def __init__(self):
        self.data = np.array([])

    def update(self, row):
        np.append(self.data, row)

    def finalize(self):
        dx = np.reshape(self.data, size=(self.data.shape[0]/5, 5))

これがどのように呼び出されるかの模式図は以下の通りです。

for i in range(500000):
    ax = A()
    for j in range(200):
         ax.update([1,2,3,4,5])
    ax.finalize()
    # some processing on ax

どのように解決するのですか?

タイミングを見て、いろいろと試してみました。

import numpy as np

  1. 遅いと言っている方法です。(32.094秒)

    class A:
    
        def __init__(self):
            self.data = np.array([])
    
        def update(self, row):
            self.data = np.append(self.data, row)
    
        def finalize(self):
            return np.reshape(self.data, newshape=(self.data.shape[0]/5, 5))
    
    
  2. 通常のOL Pythonのリストです。(0.308秒)

    class B:
    
        def __init__(self):
            self.data = []
    
        def update(self, row):
            for r in row:
                self.data.append(r)
    
        def finalize(self):
            return np.reshape(self.data, newshape=(len(self.data)/5, 5))
    
    
  3. numpyでarraylistの実装を試みる。(0.362秒)

    class C:
    
        def __init__(self):
            self.data = np.zeros((100,))
            self.capacity = 100
            self.size = 0
    
        def update(self, row):
            for r in row:
                self.add(r)
    
        def add(self, x):
            if self.size == self.capacity:
                self.capacity *= 4
                newdata = np.zeros((self.capacity,))
                newdata[:self.size] = self.data
                self.data = newdata
    
            self.data[self.size] = x
            self.size += 1
    
        def finalize(self):
            data = self.data[:self.size]
            return np.reshape(data, newshape=(len(data)/5, 5))
    
    

そして、このように時間を計りました。

x = C()
for i in xrange(100000):
    x.update([i])

というわけで、普通の古いPythonのリストがかなり良いようです ;)