2017-01-20 9 views
0

を分割するために、私は、i番目のエントリは、番号iのパーティションIDを示すnumpyの配列を有するパイソンnumpyの:インジケータが

にN-1まで番号0のパーティションを表現しようとしています。例えば、numpyのアレイ

indicator = array([1, 1, 3, 0, 2, 3, 0, 0])

はIDを持つパーティションに属し番号3,6、および7 0番号0と1 1. 4を分割するために属することを示す。2. 2のパーティションに属します5はパーティション3に属しています。これをというインジケータの表記としましょう。

パーティションを表す別の方法は、i番目のリストがID iのパーティションであるリストのリストです。上記の配列の場合、これは

explicit = [[3, 6, 7], [0, 1], [4], [2, 5]]

にマップのが明示表現これを呼びましょう。

私の質問はインジケータ表現を明示的表現に変換する最も効率的な方法は何ですか?単純な方法は、インジケータ配列を反復し、要素を明示的な配列のそれぞれのスロットに割り当てることですが、numpy配列を反復することは非効率的です。 これを行うためのより自然なnumpy構造がありますか?私はそれらを比較することはできませんので、私はあなたの反復ベースのアプローチを見ていないここで

+2

いいえ、私は最初の明示的な表現がnumpyで自然であるとは思わないので、配列が不均一になります。例えば、これを回避することができます。オブジェクトの配列を持つことで、あなたの明示的な表現のためのリストがより自然な選択かもしれません。しかし、これは変更されていないが、それは "自然な"数え切れない構造ではない。 –

+0

1つのホットエンコーディングを使用するスパース行列はどうですか? – UberStuper

+0

投稿されたソリューションのいずれかはあなたのために機能しましたか? – Divakar

答えて

1

ここでのアプローチですソートされたインデックスを使用し、次にグループにそれらを分割 -

def indicator_to_part(indicator): 
    sidx = indicator.argsort() # indicator.argsort(kind='mergesort') keeps order 
    sorted_arr = indicator[sidx] 
    split_idx = np.nonzero(sorted_arr[1:] != sorted_arr[:-1])[0] 
    return np.split(sidx, split_idx+1) 

ランタイム試験 - 出力は、ARのリストであろうこと

In [326]: indicator = np.random.randint(0,100,(10000)) 

In [327]: %timeit from_ind_to_expl(indicator) #@yogabonito's soln 
100 loops, best of 3: 5.59 ms per loop 

In [328]: %timeit indicator_to_part(indicator) 
1000 loops, best of 3: 801 µs per loop 

In [330]: indicator = np.random.randint(0,1000,(100000)) 

In [331]: %timeit from_ind_to_expl(indicator) #@yogabonito's soln 
1 loops, best of 3: 494 ms per loop 

In [332]: %timeit indicator_to_part(indicator) 
100 loops, best of 3: 11.1 ms per loop 

注レイ。リストを出力として取得する必要がある場合、簡単な方法はmap(list,indicator_to_part(indicator))を使用することです。繰り返しますが、実行可能な代替案には、これ以上のステップは含まれません。

def indicator_to_part_list(indicator): 
    sidx = indicator.argsort() # indicator.argsort(kind='mergesort') keeps order 
    sorted_arr = indicator[sidx] 
    split_idx = np.nonzero(sorted_arr[1:] != sorted_arr[:-1])[0] 

    sidx_list = sidx.tolist() 
    start = np.append(0,split_idx+1) 
    stop = np.append(split_idx+1,indicator.size+1) 
    return [sidx_list[start[i]:stop[i]] for i in range(start.size)] 
1

のみ(forループ、リスト内包、itertoolsなど)をnumpyの使用していないexplicitindicatorを翻訳するためのソリューションです 多分それはあなたのニーズ:)

import numpy as np 
indicator = np.array([1, 1, 3, 0, 2, 3, 0, 0]) 
explicit = [[3, 6, 7], [0, 1], [4], [2, 5]] 

def from_ind_to_expl(indicator): 
    groups, group_sizes = np.unique(indicator, return_counts=True) 
    group_sizes = np.cumsum(group_sizes) 
    ordered = np.where(indicator==groups[:, np.newaxis]) 
    return np.hsplit(ordered[1], group_sizes[:-1]) 

from_ind_to_expl(indicator)のために十分な速さだ場合は、

[array([3, 6, 7]), array([0, 1]), array([4]), array([2, 5])] 

を与える私に言うことができます

また、@ Divakarと私のソリューションの時を比較しました。私のマシンでは、@ DivaCarのソリューションは私のものより2〜3倍高速です。だから、@Divakarは間違いなく私からupvoteを取得します:)

@ Divakarの記事の最後の比較では唯一のループがありますので、私の解決策のための平均化はありません - これは少し不公平である:P;)

+1

それにもかかわらず、良い試みだった! :) – Divakar

+0

ありがとう! upvoteのためにありがとう:) – yogabonito

関連する問題