2013-04-07 3 views
16

코드 최적화를 시도한 후에 마지막 리소스가 여러 코어를 사용하여 아래 코드를 실행하려고 시도하는 것 같습니다. 정확히 어떻게 여러 코어를 사용하여 훨씬 빠르게 실행할 수 있도록 내 코드를 변환/재구성하는 방법을 모르겠습니다. 최종 목표를 달성하기위한 지침을 얻을 수 있다면 감사하겠습니다. 최종 목표는 각 배열이 약 70 만 개의 요소를 보유하고있는 배열 A와 B에 대해이 코드를 가능한 빨리 실행할 수 있도록하는 것입니다. 다음은 작은 배열을 사용하는 코드입니다. 700k 요소 배열은 주석으로 처리됩니다.MATLAB의 "ismember"함수에 해당하는 파이썬

import numpy as np 

def ismember(a,b): 
    for i in a: 
     index = np.where(b==i)[0] 
     if index.size == 0: 
      yield 0 
     else: 
      yield index 


def f(A, gen_obj): 
    my_array = np.arange(len(A)) 
    for i in my_array: 
     my_array[i] = gen_obj.next() 
    return my_array 


#A = np.arange(700000) 
#B = np.arange(700000) 
A = np.array([3,4,4,3,6]) 
B = np.array([2,5,2,6,3]) 

gen_obj = ismember(A,B) 

f(A, gen_obj) 

print 'done' 
# if we print f(A, gen_obj) the output will be: [4 0 0 4 3] 
# notice that the output array needs to be kept the same size as array A. 

내가 뭘하려고하는 것은 MATLAB 기능으로 포맷 [2] (하나 ismember라고 모방하는 것입니다. [Lia,Locb] = ismember(A,B) 난 그냥 Locb 부분 만 얻기 위해 노력하고

. matlab에 가입일

A는 B의 구성원 메인의

아니다 목적지 Locb는 출력 배열 Locb가 0을 포함 B.의 구성원 인 각각의 값에 대한 B의 가장 낮은 인덱스를 포함 문제는 내가 abl 될 필요가있다. 이 작업을 최대한 효율적으로 수행 할 수 있습니다. 테스트를 위해 두 개의 700k 요소 배열이 있습니다. 생성기를 생성하고 생성기의 값을 검토하는 것은 작업을 빨리 완료하지 못하는 것 같습니다.

답변

13

멀티 코어에 대한 걱정하기 전에, 나는 사전을 사용하여 ismember 함수의 선형 스캔을 제거하는 것입니다 :

def ismember(a, b): 
    bind = {} 
    for i, elt in enumerate(b): 
     if elt not in bind: 
      bind[elt] = i 
    return [bind.get(itm, None) for itm in a] # None can be replaced by any other "not in b" value 

원래 구현은 각 요소에 대한 B의 요소의 전체 검사가 필요합니다, 그것은 O(len(A)*len(B))이됩니다. 위의 코드는 dict Bset을 생성하기 위해 B의 전체 스캔을 요구합니다. dict을 사용하면 A의 각 요소에 대해 B 상수의 각 요소를 효율적으로 조회하여 작업을 O(len(A)+len(B))으로 만듭니다. 여전히 느리다면 위의 기능을 여러 코어에서 실행하는 것에 대해 걱정하십시오.

편집 : 색인 생성을 약간 수정했습니다. 그 배열의 모든 당신이 인 경우 데이터 세트가이

A = [2378, 2378, 2378, 2378] 
B = [2378, 2379] 

처럼 보이는, 그래서 파이썬/0에서 배열을 시작 NumPy와 인덱스 1에서 시작하고 다음 결과 것, 아니 요소에 대해 0을 반환하기 때문에 matlab에 0을 사용합니다 위의 루틴은 0이 아닌 인덱스가없는 경우 None을 반환합니다. -1을 반환하면 옵션을 사용할 수 있지만 파이썬에서는이 값을 배열의 마지막 요소로 해석합니다. None은 배열에 대한 인덱스로 사용되는 경우 예외를 발생시킵니다. 다른 동작을 원하면 Bind.get(item,None) 표현식의 두 번째 인수를 반환 할 값으로 변경하십시오.

+0

와우 이것은 정말 빠릅니다! 당신은 당신의 해결책을 얼마나 고맙게 생각하는지 모른다. 고마워요! 성능 프로파일을 출력하기 위해 특정 도구를 사용합니까? – zd5151

+5

@ z5151 아니요, 직접적인 알고리즘 분석입니다. [Big-O 표기법 사용하기] (http://en.wikipedia.org/wiki/Big_O_notation) :'np.where '는'B '의 선형 스캔을 수행해야하는데,'O (len (B))' 작업. 그런 다음 원래 알고리즘을 대략'O (len (A) * len (B))'연산으로 만드는 'O (len (A))'연산을 필요로하는 외부 루프를 사용합니다. 'Bind'를 생성하려면'len (B)'연산이 필요합니다. 사전은 [해시 표] (http://en.wikipedia.org/wiki/Hash_table)로 구현되어 있으며, 일정한'O (1)'검색을하므로 A 검색은'O (len (A))'; 전반적인 복잡성은'O (len (A) + len (B))'입니다. – sfstewman

+0

알았어요. 위키피디아 참조 주셔서 감사합니다. – zd5151

1

목록 이해력을 사용해보십시오.

In [1]: import numpy as np 

In [2]: A = np.array([3,4,4,3,6]) 

In [3]: B = np.array([2,5,2,6,3]) 

In [4]: [x for x in A if not x in B] 
Out[4]: [4, 4] 

일반적으로 list comprehension은 for-loops보다 훨씬 빠릅니다.

동일한 길이 목록을 얻으려면;

In [19]: map(lambda x: x if x not in B else False, A) 
Out[19]: [False, 4, 4, False, False] 

이 작은 데이터 세트에 대한 매우 빠르다 :

In [20]: C = np.arange(10000) 

In [21]: D = np.arange(15000, 25000) 

In [22]: %timeit map(lambda x: x if x not in D else False, C) 
1 loops, best of 3: 756 ms per loop 

대규모 데이터 세트를 들어, 작업을 빠르게하기 위해 multiprocessing.Pool.map()를 사용하여 시도 할 수 있습니다.

+0

출력 배열은 동일한 크기를 유지해야한다. – zd5151

+0

@ z5151 : 향상된 대답을 참조하십시오. 원한다면'lambda' 표현식을 False 대신에 0을 반환하도록 바꿀 수 있습니다.하지만 결과에서 실제 0을 감출 것입니다. –

+0

이것은 요소 수가 적은 배열에 유용합니다. 목록 내포가 루프보다 훨씬 빠르다는 점을 강조해 주셔서 감사합니다. – zd5151

10

sfstewman의 탁월한 대답이 가장 좋은 방법 일 것입니다.

저는 numpy에서 독점적으로 동일한 것을 달성하는 방법을 추가하고 싶습니다.

numpy의 uniquein1d 기능을 사용합니다.

B_unique_sorted, B_idx = np.unique(B, return_index=True) 
B_in_A_bool = np.in1d(B_unique_sorted, A, assume_unique=True) 
  • B_unique_sorted 정렬 B의 고유 한 값을 포함합니다.
  • B_idx은 원래 값인 B에 대한 색인을 유지합니다.
  • B_in_A_boolB_unique_sorted의 값인지 B_unique_sorted 해당 점포의 크기 A에 부울 배열이다.
    참고 : 나는 B_idx
    주에 대한 반환 할 출력을 필요로하기 때문에에 (B에서 독특한 발스)을 찾아해야합니다 나는 A 이미 고유 있다고 가정합니다.

이제 당신이 B_in_A_bool를 사용하거나 마지막으로 원래 B

B_idx[B_in_A_bool] 

의 일반적인 발스에게

B_unique_sorted[B_in_A_bool] 

및 각각의 인덱스를 얻을 수 있습니다,이 상당히 빠르게보다 가정 내가 테스트하지는 않았지만 순수한 파이썬 용.

+0

가능한 한 numpy를 사용하기 위해 +1,이 방법으로 주요한 스피드 업을 달성 할 수 있습니다. (어려운 방법을 배웠으므로 _ <) –

+1

조심해! 이것은 색인의 순서를 유지하지 않습니다! 범위 (1,6)와 [5,1]로 시도하십시오. 색인의 순서가 필요하지 않은 경우 np.in1d ​​()를 사용하고 np.nonzero()를 사용할 수 있다고 생각합니다. [0] – aless80

+1

답변보기 : https://stackoverflow.com/questions/33678543/finding -indices-of-matches-of-one-array-in-another-array 올바른 순서로 색인을 얻습니다. – aless80

0

파이썬 0을 제외하고는 MATLAB과 일치하는 출력 인수 [Lia, Locb]를 반환하는 정확한 MATLAB도 같습니다. 0은 유효한 인덱스이기도합니다. 따라서이 함수는 0을 반환하지 않습니다. Locb (Locb> 0)를 반환합니다. 성능은 MATLAB과 동일합니다.

def ismember(a_vec, b_vec): 
    """ MATLAB equivalent ismember function """ 

    bool_ind = np.isin(a_vec,b_vec) 
    common = a[bool_ind] 
    common_unique, common_inv = np.unique(common, return_inverse=True)  # common = common_unique[common_inv] 
    b_unique, b_ind = np.unique(b_vec, return_index=True) # b_unique = b_vec[b_ind] 
    common_ind = b_ind[np.isin(b_unique, common_unique, assume_unique=True)] 
    return bool_ind, common_ind[common_inv] 

비트 (~ 5 배)를 느리게하지만, 고유 한 기능을 사용하지 않는 다른 구현은 여기에서 :

def ismember(a_vec, b_vec): 
    ''' MATLAB equivalent ismember function. Slower than above implementation''' 
    b_dict = {b_vec[i]: i for i in range(0, len(b_vec))} 
    indices = [b_dict.get(x) for x in a_vec if b_dict.get(x) is not None] 
    booleans = np.in1d(a_vec, b_vec) 
    return booleans, np.array(indices, dtype=int) 
관련 문제