2016-03-22 14 views
2

Python 2.7で次の例を考えてみましょう。 2つの1次元numpy配列を返す任意の関数f()があります。一般に、f()は異なるサイズの配列を返すことがあり、サイズは入力に依存する可能性があることに注意してください。ジェネレータから2つの連結配列を作成する

f()mapを呼び出し、結果を2つの別々の新しい配列に連結したいとします。

import numpy as np 

def f(x): 
    return np.arange(x),np.ones(x,dtype=int) 

inputs = np.arange(1,10) 
result = map(f,inputs) 
x = np.concatenate([i[0] for i in result]) 
y = np.concatenate([i[1] for i in result]) 

これは、意図した結果を示します。しかし、結果が多くのメモリを消費することがあるので、mapの代わりにを呼び出すことによってジェネレータを使用することが望ましい場合があります。

from itertools import imap 
result = imap(f,inputs) 
x = np.concatenate([i[0] for i in result]) 
y = np.concatenate([i[1] for i in result]) 

ジェネレータは、我々はyを計算する時点で空であるため、これはエラーになります。

ジェネレータを一度しか使用せず、これらの2つの連結配列を作成する方法はありますか?私はforループを持たないソリューションを探しています。なぜなら、配列を繰り返し連結/追加するのはむしろ非効率的だからです。

ありがとうございます。

+0

あなたは '私は[0]' 'と私は[1]'異なる形状を持つことができることを意味していますか? –

+0

@ SergeiLebedev一般的には、はい。私の例では、彼らは同じ形をしています。 – Forzaa

+0

'result'にジェネレータを使用するメリットはありません。あなたは 'np.concatenate'呼び出しの' result'と同じサイズの2つのリストを作ります。したがって、2つのリストを持つことができれば、for-loopで 'result'を繰り返し実行し、同時にリストを更新することができます。 –

答えて

3

ジェネレータを一度しか使用せず、これらの2つの連結配列を作成する方法はありますか?

はい、発電機はteeでクローニングすることができる。

import itertools 
a, b = itertools.tee(result) 

x = np.concatenate([i[0] for i in a]) 
y = np.concatenate([i[1] for i in b]) 

しかし、teeを使用すると、あなたのケースでのメモリ使用量には役立ちません。 tee内部発電機をキャッシュするため

  • N、
  • 2 Nをnp.concatenateコール、連結アレイの
  • 2 N内のリストの内包のために上記溶液を実行するために5 Nのメモリを必要とするであろう。

明らかに、我々はteeをドロップすることによって、より良い行うことができます:これは中間のリストをドロップしxyを事前に割り当てる手段を更に行く4 N.を残して、1以上Nを削ら

x_acc = [] 
y_acc = [] 
for x_i, y_i in result: 
    x_acc.append(x_i) 
    y_acc.append(y_i) 

x = np.concatenate(x_acc) 
y = np.concatenate(y_acc) 

。あなたが必要とする配列、唯一の上限の正確なサイズを知らないことに、注意してください:

x = np.empty(capacity) 
y = np.empty(capacity) 
right = 0 
for x_i, y_i in result: 
    left = right 
    right += len(x_i) # == len(y_i) 
    x[left:right] = x_i 
    y[left:right] = y_i 

x = x[:right].copy() 
y = y[:right].copy() 

は、実際には、あなたも上限を必要としません。ただ、xyは、新しいアイテムを収納するのに十分な大きさであることを確認してください。

for x_i, y_i in result: 
    # ... 
    if right >= len(x): 
     # It would be slightly trickier for >1D, but the idea 
     # remains the same: alter the 0-the dimension to fit 
     # the new item. 
     new_capacity = max(right, len(x)) * 1.5 
     x = x.resize(new_capacity) 
     y = y.resize(new_capacity) 
関連する問題