Numpy에서 대칭 쌍을 빠르게 찾기


15
from itertools import product
import pandas as pd

df = pd.DataFrame.from_records(product(range(10), range(10)))
df = df.sample(90)
df.columns = "c1 c2".split()
df = df.sort_values(df.columns.tolist()).reset_index(drop=True)
#     c1  c2
# 0    0   0
# 1    0   1
# 2    0   2
# 3    0   3
# 4    0   4
# ..  ..  ..
# 85   9   4
# 86   9   5
# 87   9   7
# 88   9   8
# 89   9   9
# 
# [90 rows x 2 columns]

이 데이터 프레임에서 모든 대칭 쌍의 마지막 복제본을 빠르게 찾고 식별하고 제거하려면 어떻게합니까?

대칭 쌍의 예는 '(0, 1)'이 '(1, 0)'과 같습니다. 후자는 제거해야합니다.

알고리즘은 빠르므로 numpy를 사용하는 것이 좋습니다. 파이썬 객체로의 변환은 허용되지 않습니다.


1
당신이 이해하는 것에 대한 예를 들어 주 symmetric pairs시겠습니까?
yatu

(0, 1) == (1,0)은 True
불행한 고양이

1
(0, 1) == (0, 1)도 참입니까?
wundermahn

@JerryM. 네, 그러나 제거하는 것은 사소한 df.drop_duplicates()
The Unfun Cat

2
@ molybdenum42 itertools 제품을 사용하여 예제를 작성하지만 데이터 자체는 itertools 제품으로 작성되지 않습니다.
The Unfun Cat

답변:


13

값을 정렬 한 후 다음을 수행 할 수 있습니다 groupby.

a= np.sort(df.to_numpy(), axis=1)
df.groupby([a[:,0], a[:,1]], as_index=False, sort=False).first()

옵션 2 : 당신이 쌍을 많이 가지고있는 경우 c1, c2, groupby속도가 느려질 수 있습니다. 이 경우 다음과 같이 새 값을 할당하고 필터링 할 수 있습니다 drop_duplicates.

a= np.sort(df.to_numpy(), axis=1) 

(df.assign(one=a[:,0], two=a[:,1])   # one and two can be changed
   .drop_duplicates(['one','two'])   # taken from above
   .reindex(df.columns, axis=1)
)

7

한 가지 방법은 np.uniquewith return_index=True를 사용하고 결과를 사용하여 데이터 프레임을 인덱싱하는 것입니다.

a = np.sort(df.values)
_, ix = np.unique(a, return_index=True, axis=0)

print(df.iloc[ix, :])

    c1  c2
0    0   0
1    0   1
20   2   0
3    0   3
40   4   0
50   5   0
6    0   6
70   7   0
8    0   8
9    0   9
11   1   1
21   2   1
13   1   3
41   4   1
51   5   1
16   1   6
71   7   1
...

1
네, 그렇지 않으면 고유함이 대칭 쌍을 감지하지 못합니다 @DanielMesejo
yatu

좋아, 나는 당신이 쌍을 정렬 그래서 참조
Dani Mesejo

예,하지만 [1, 0]을 [0, 1]로 변환한다는 의미입니까?
Dani Mesejo

6

frozenset

mask = pd.Series(map(frozenset, zip(df.c1, df.c2))).duplicated()

df[~mask]

1
여기 각 열에서 튜플을 천천히 반복하지 않습니까? 여전히 공감.
Unfun Cat

예, 반복하고 있습니다. 아니요, 생각만큼 느리지 않습니다.
piRSquared '10

5

내가 할 것이다

df[~pd.DataFrame(np.sort(df.values,1)).duplicated().values]

팬더와 numpy tri에서

s=pd.crosstab(df.c1,df.c2)
s=s.mask(np.triu(np.ones(s.shape)).astype(np.bool) & s==0).stack().reset_index()

5

다음은 정수에 대한 NumPy 기반 하나입니다.

def remove_symm_pairs(df):
    a = df.to_numpy(copy=False)
    b = np.sort(a,axis=1)
    idx = np.ravel_multi_index(b.T,(b.max(0)+1))
    sidx = idx.argsort(kind='mergesort')
    p = idx[sidx]
    m = np.r_[True,p[:-1]!=p[1:]]
    a_out = a[np.sort(sidx[m])]
    df_out = pd.DataFrame(a_out)
    return df_out

인덱스 데이터를 그대로 유지하려면을 사용하십시오 return df.iloc[np.sort(sidx[m])].

일반적인 숫자 (int 치의 / 수레 등)의 경우, 우리는 사용 view-based을 -

# https://stackoverflow.com/a/44999009/ @Divakar
def view1D(a): # a is array
    a = np.ascontiguousarray(a)
    void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
    return a.view(void_dt).ravel()

간단하게 얻을 수있는 단계 교체 idxidx = view1D(b)의를 remove_symm_pairs.


1

이것이 빠르고 변수가 정수이면 다음과 같은 트릭이 도움이 v,w될 수 있습니다. 벡터의 열이되게하십시오. 구성 [v+w, np.abs(v-w)] =: [x, y]; 그런 다음이 행렬을 사전 식으로 정렬하고 중복을 제거한 다음 마지막으로 다시 매핑합니다 [v, w] = [(x+y), (x-y)]/2.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.