2017-08-21 13 views
1
a = np.array([5,8,3,4,2,5,7,8,1,9,1,3,4,7]) 
b = np.array ([3,4,7,8,1,3]) 

2つの連続した項目(つまりインデックス[0,1]、[2,3]など)でグループ化された2つの整数リストがあります。 アイテムのペアは、どちらのリストでも同じ順序または逆の順序では重複として検出されません。2つの配列間でグループ化された項目の一致を見つける

1つのリストは、他のリストよりも大幅に大きくなります。 大きなリストのグループ化された項目のうち小さい方の項目にインデックスを割り当てる効率的な方法を見つけようとしています。

上記の例では、所望の出力は次のようになります。一例として、最初のグループは、([3,4])の指標11,12になぜなら一致としてを得てはならない、ということ

[2,3,6,7,10,11] #indices 

お知らせその場合3は[1,3]の第2要素であり、4は[4,7]の第1要素です。

答えて

1

は、ここで要素のグループのNumPy viewを利用して一つのアプローチだ -

# Taken from https://stackoverflow.com/a/45313353/ 
def view1D(a, b): # a, b are arrays 
    a = np.ascontiguousarray(a) 
    void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1])) 
    return a.view(void_dt).ravel(), b.view(void_dt).ravel() 

def grouped_indices(a, b): 
    a0v, b0v = view1D(a.reshape(-1,2), b.reshape(-1,2)) 
    sidx = a0v.argsort() 
    idx = sidx[np.searchsorted(a0v,b0v, sorter=sidx)] 
    return ((idx*2)[:,None] + [0,1]).ravel() 

abから任意のグループの間にメンバーシップが存在しない場合には、我々はマスク使用してそれを除外することができます:a0v[idx] == b0vを。

サンプル実行 -

In [345]: a 
Out[345]: array([5, 8, 3, 4, 2, 5, 7, 8, 1, 9, 1, 3, 4, 7]) 

In [346]: b 
Out[346]: array([3, 4, 7, 8, 1, 3]) 

In [347]: grouped_indices(a, b) 
Out[347]: array([ 2, 3, 6, 7, 10, 11]) 

np.searchsorted交換するnp.in1dを使用してもう1 - あなたがペアであなたの配列をグループ化しているので

def grouped_indices_v2(a, b): 
    a0v, b0v = view1D(a.reshape(-1,2), b.reshape(-1,2)) 
    return (np.flatnonzero(np.in1d(a0v, b0v))[:,None]*2 + [0,1]).ravel() 
+0

をラヴェル、あなたの答えをありがとうございました。 'inedd'が正しく動作しなかった理由を推測しましたか?' searchsorted'は私が既にチェックした実際のセットで行います。 'b'のすべての要素は' a'に含まれています。ペアになった要素は 'a'と' b'の一意の項目です。 – Tony

+0

@ Tonyおそらく、 'b'のグループ化の順序が' a'の順序と同じではないためです。これは 'array([3、4、7、8、1、3]) 'の代わりに' b'が 'array([1,3,3,4,7,8])'のようなものです。 – Divakar

2

を、あなたは比較のために2列にそれらを再構築することができます。その後、より短い配列の各要素をより長い配列と比較して、ブール配列を減らすことができます。そこから、再構成されたnp.arangeを使ってインデックスを取得するのは簡単なことです。

import numpy as np 
from functools import reduce 

a = np.array([5,8,3,4,2,5,7,8,1,9,1,3,4,7]) 
b = np.array ([3,4,7,8,1,3]) 

# reshape a and b into columns 
a2 = a.reshape((-1,2)) 
b2 = b.reshape((-1,2)) 

# create a generator of bools for the row of a2 that holds b2 
b_in_a_generator = (np.all(a2==row, axis=1) for row in b2) 

# reduce the generator to get an array of boolean that is True for each row 
# of a2 that equals one of the rows of b2 
ix_bool = reduce(lambda x,y: x+y, b_in_a_generator) 

# grab the indices by slicing a reshaped np.arange array 
ix = np.arange(len(a)).reshape((-1,2))[ix_bool] 

ix 
# returns: 
array([[ 2, 3], 
     [ 6, 7], 
     [10, 11]]) 

あなたが平らな配列をしたい場合は、単に再びix

ix.ravel() 
# returns 
array([ 2, 3, 6, 7, 10, 11]) 
+0

ありがとう、華麗な答え。私は@Divakarを受け入れたものとして選んだのは、本当に大きなセットの場合、 'reduce(lambda ...)'がかなり時間がかかるからです – Tony

関連する問題