2017-07-10 14 views
4

collections.Counterは非常に遅いので、私はPython 2.7でマップされた値を合計するより速い方法を追求しています。シンプルなコンセプトのように思えますが、組み込みのCounterメソッドではうんざりです。カウンタのようなナンシーアレイの追加

基本的に、私はこのような配列を取ることができるようにする必要があります:

array([[ 0., 2.], 
     [ 2., 2.], 
     [ 3., 1.]]) 

array([[ 0., 3.], 
     [ 1., 1.], 
     [ 2., 5.]]) 

そして、彼らはこのように見えるので、それらを「追加」:

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

良いがない場合私はこれに似た何かをすることを可能にする他のアイデアを公開しています.Numpy以外のモジュールも公開しています。

ありがとうございます!

編集:いくつかのスピードテストには対応していますか? インテルは64ビットマシンを獲得しました。次の値はすべて秒単位です。 20000ループ。

collections.Counter結果: 2.131000、2.125000、2.125000

Divakarのunion1d +マスキング結果: 1.641000、1.633000、1.625000

Divakarのunion1d +インデックスの結果: 0.625000、0.625000、0.641000

ヒストグラムの結果: 1.844000、1.938000、1.858000

パンダ結果: 16.659000、16.686000、16.885000

結論:パンダを有効にするためにunion1d +インデックスの勝利は、配列のサイズが小さすぎると、ヒストグラムのアプローチは、そのシンプルさで私の心を吹いたが、私はよそれを作成するにはあまりにも多くのオーバーヘッドがかかります私が受け取ったすべての反応はとても良いものでした。 This is what I used to get the numbers.もう一度ありがとう!

編集:そして、同じ正確なこと(65.671000秒)にもかかわらず、Counter1.update(Counter2.elements())を使用することはひどいことに言及する必要があります。

後で編集しました:私はこれについてたくさん考えていましたが、Numpyでの各列に最初の列がないように記入する方が効果的かもしれません。インデックスを使用するだけで済むので、複数の配列を追加するだけでなく、他の関数も簡単に作成できます。さらに、NumpyよりもPandasのほうが理にかなっています。なぜなら、0で塗りつぶす必要はなく、大きなデータセットではより効果的です(しかし、NumpyはGAEのようなより多くのプラットフォームで互換性があるという利点がありますまったく)。最後に、私がチェックした答えは、私が尋ねた正確な質問に対する最善の答えでした。私が示した方法で2つの配列を追加しました。しかし、私は必要なのは視点の変更だと思います。

+0

なぜ結果に4行ありますか? –

+1

結果の行は、配列のすべての最初のインデックスの和集合にあるユニークな最初のインデックスの数に等しいためです。上の配列では、上の配列だけが「2」を持ち、中央の配列のみが「3」を有するので、下の配列は2と3の両方を有する。 – Zoojay

+0

最初の列の最大値は何ですか? –

答えて

2

は、ここに1つのnp.union1dとアプローチとmaskingだ -

def app1(a,b): 
    c0 = np.union1d(a[:,0],b[:,0]) 

    out = np.zeros((len(c0),2)) 
    out[:,0] = c0 

    mask1 = np.in1d(c0,a[:,0]) 
    out[mask1,1] = a[:,1] 

    mask2 = np.in1d(c0,b[:,0]) 
    out[mask2,1] += b[:,1] 
    return out 

サンプル実行 - すべてのインデックスがある場合については

def app2(a,b): 
    n = np.maximum(a[:,0].max(), b[:,0].max())+1 
    c0 = np.union1d(a[:,0],b[:,0]) 
    out0 = np.zeros((int(n), 2)) 
    out0[a[:,0].astype(int),1] = a[:,1] 

    out0[b[:,0].astype(int),1] += b[:,1] 

    out = out0[c0.astype(int)] 
    out[:,0] = c0 
    return out 

-

In [174]: a 
Out[174]: 
array([[ 0., 2.], 
     [ 12., 2.], 
     [ 23., 1.]]) 

In [175]: b 
Out[175]: 
array([[ 0., 3.], 
     [ 1., 1.], 
     [ 12., 5.]]) 

In [176]: app1(a,b) 
Out[176]: 
array([[ 0., 5.], 
     [ 1., 1.], 
     [ 12., 7.], 
     [ 23., 1.]]) 
ここ

だ別のnp.union1dとし、indexing覆う最初の列aの値とb -

def app2_specific(a,b): 
    c0 = np.union1d(a[:,0],b[:,0]) 
    n = c0[-1]+1 
    out0 = np.zeros((int(n), 2)) 
    out0[a[:,0].astype(int),1] = a[:,1]   
    out0[b[:,0].astype(int),1] += b[:,1] 
    out0[:,0] = c0 
    return out0 

サンプル実行 -

In [234]: a 
Out[234]: 
array([[ 0., 2.], 
     [ 2., 2.], 
     [ 3., 1.]]) 

In [235]: b 
Out[235]: 
array([[ 0., 3.], 
     [ 1., 1.], 
     [ 2., 5.]]) 

In [236]: app2_specific(a,b) 
Out[236]: 
array([[ 0., 5.], 
     [ 1., 1.], 
     [ 2., 7.], 
     [ 3., 1.]]) 
+0

'collections.Counter'アプローチとのタイミング比較が気に入っています... –

+0

@ juanpa.arrivillaga OPがそのバージョンを投稿した場合にも、そのことをしたいと思います。 – Divakar

0

パンダはあなたが

import pandas as pd 
pda = pd.DataFrame(a).set_index(0) 
pdb = pd.DataFrame(b).set_index(0) 
result = pd.concat([pda, pdb], axis=1).fillna(0).sum(axis=1) 

編集を意図し、正確に何をしていくつかの機能を持っている:あなたは、実際にデータが必要な場合numpy形式で戻ってください。

array_res = result.reset_index(name=1).values 
1

フィールド数がわかっている場合は、np.bincountを使用してください。

c = np.vstack([a, b]) 
counts = np.bincount(c[:, 0], weights = c[:, 1], minlength = numFields) 
out = np.vstack([np.arange(numFields), counts]).T 

これは、すべてのデータを一度に取得している場合に機能します。あなたの配列とvstackのリストを作成します。データチャンクを順次取得する場合は、同じことを行うにはnp.add.atを使用できます。

out = np.zeros(2, numFields) 
out[:, 0] = np.arange(numFields) 
np.add.at(out[:, 1], a[:, 0], a[:, 1]) 
np.add.at(out[:, 1], b[:, 0], b[:, 1]) 
+0

私の最後のものは危険なほど近くのものでした。以前のバージョンにロールバックすると思います。その「範囲」は素晴らしいアイデアでした! – Divakar

+0

あなたは解決策を修正する必要があると思っています。OPは彼/彼女[ギャップがあるかもしれません](https://stackoverflow.com/questions/45021120/adding-numpy-arrays-like-counters#comment77018565_45021120)と彼らは["union"バージョン](https://stackoverflow.com/questions/45021120/adding-numpy-arrays-like-counters#comment77016647_45021120)を出力します。 – Divakar

0

これはnumpy_indexed典型グループ化の問題、次のとおりです。エレガントかつ効率的に解決するために作成されました(免責事項私はその作者):

import numpy_indexed as npi 
C = np.concatenate([A, B], axis=0) 
labels, sums = npi.group_by(C[:, 0]).sum(C[:, 1]) 

注:としてあなたのラベルの配列を維持するために、そのクリーナーseperate int array;浮動小数点数は、正負のゼロ、およびすべてのバイナリ状態を中継しない印刷された値で、物事にラベルを付けることになると厄介です。そのためにintを使う方が良いです。

+0

はpyinstallerとnumpy_indexed互換ですか?編集:それはPythonで実装されているか、Cの拡張機能がありますか? – Zoojay

+0

拡張子はありません。原則として、ソースをプロジェクトにコピーして実行するだけです。私はpythonパッケージ管理のためにcondaを強く推奨しますが、 –

+0

私はピップを使用してnumpy_indexedをダウンロードしようとすると、pipを使用してCondaをダウンロードしようとするとエラーが発生します。 numpy_indexedでは、私のエラーは次のようになります。 "コマンド" python setup.py egg_info "エラーコード1で失敗しました"そしてパスの終わりは "appdata \ local \ temp \ pip-build-u6xyi9 \ numpy-indexed \"です。 Condaをダウンロードしようとすると、「(condaからの)要件を満たすバージョンを見つけることができませんでした。」とその下の「menuinst(condaから)に一致するディストリビューションがありません」の下にあります。助けてください?私はそのスピードをテストしたいと思います。 – Zoojay

1

基本ヒストグラムthis will deal with gaps, tooを使用できます。必要に応じて、ゼロカウント項目を除外することができます。

import numpy as np 

x = np.array([[ 0., 2.], 
       [ 2., 2.], 
       [ 3., 1.]]) 

y = np.array([[ 0., 3.], 
       [ 1., 1.], 
       [ 2., 5.], 
       [ 5., 3.]]) 

c, w = np.vstack((x,y)).T 
h, b = np.histogram(c, weights=w, 
        bins=np.arange(c.min(),c.max()+2)) 
r = np.vstack((b[:-1], h)).T 
print(r) 
# [[ 0. 5.] 
# [ 1. 1.] 
# [ 2. 7.] 
# [ 3. 1.] 
# [ 4. 0.] 
# [ 5. 3.]] 
r_nonzero = r[r[:,1]!=0] 
関連する問題