Pandas에서 중복 행 목록을 얻으려면 어떻게해야합니까?

Aug 21 2020

358 개 샘플에 10 만 개 이상의 변수 (행)가있는 빅 데이터 프레임이 있습니다.

모든 샘플에서 어떤 변수가 동일 (중복)되는지 알고 싶습니다.

샘플 데이터 프레임은 다음과 같습니다.

         Sample1 Sample2 Sample3 Sample4 Sample5
1000084  0.0     0.0     0.0     0.0     0.0    
1000092  0.0     0.0     0.0     0.0     0.0
1000096  0.0     0.0     1.0     0.0     0.0
1000110  0.0     0.0     1.0     0.0     0.0
1000116  0.0     0.0     0.0     0.0     0.0

필요한 결과는 다음과 같거나 동일한 행 목록이 될 수 있습니다.

 {1000084:[1000092, 1000116], 1000096:[1000110]}

pandas에서 복제 방법을 시도했지만 고유 항목 또는 고유 항목과 첫 번째 또는 마지막 복제 만 남깁니다.

이 코드로 시도했지만 나이가 들었습니다.

duplicated_index = set()
duplicates = {}

for i, pos in enumerate(df.index, 0):
    #check if the row has marked as duplicate, if so, ignore it
    if i in duplicated_index:
        continue
    for j in range(i+1, df.shape[0]):
        if all(df.iloc[i] == df.iloc[j]):
             duplicated_index.add(j)
             tmp = duplicates.setdefault(pos, [])
             duplicates[pos].append(df.iloc[j].name)

이 목록을 얻고 어떤 행이 다른 행과 동일한 지 식별하는 더 적절한 방법이 있습니까?

답변

3 wwii Aug 21 2020 at 21:43

모든 열을 그룹화합니다. 둘 이상의 항목이있는 그룹을 찾아 목록에 넣습니다. for 루프를 사용합니다.

>>> gb = df.groupby(df.columns.to_list())
>>> d = {}
>>> for a,b in gb:
...     if len(b) > 1:
...         d[b.index[0]] = b.index[1:].to_list()

        
>>> d
{1000084: [1000092, 1000116], 1000096: [1000110]}
>>>

위와 동일한 groupby를 사용하여 그룹의 인덱스를 반환하는 함수를 작성하고 집계 메서드를 사용하여 사전을 구성합니다 .

def f(thing):
    return thing.index.to_list()

>>> {key:val for key,*val in gb.aggregate(f) if val}
{1000084: [1000092, 1000116], 1000096: [1000110]}

이 실행 시간은 열 행 수 (항목 수)에 따라 선형 적으로 확장되는 것 같습니다 .


다음은 테스트를위한 큰 DataFrame입니다. 불행히도 중복 행을 생성하고 싶지 않습니다. 아마도 groupby의 경우 최악의 경우 일 수 있습니다.

import itertools,string
import numpy as np
nrows,ncols = 100000,300

a = np.random.randint(1,3,(nrows,ncols))
# or using the new random stuff
#from numpy.random import default_rng
#rng = default_rng()
#a = rng.integers(1,3,(nrows,ncols))

index = np.arange(1000000,1000000+nrows,dtype=np.int64)
cols = [''.join(thing) for thing in itertools.combinations(string.ascii_letters,3)]
df2 = pd.DataFrame(data=a,index=index,columns=cols[:ncols])
2 BENY Aug 21 2020 at 21:37

reset_index그런 다음 groupby추가agg

l = df.reset_index().groupby(list(df))['index'].agg(list).tolist()
Out[291]: [[1000084, 1000092, 1000116], [1000096, 1000110]]
1 gunsodo Aug 21 2020 at 21:29

pandasduplicated()중복 된 모든 행을 반환 하는 자체 함수 가 있습니다.

duplicated_rows = df[df.duplicated(subset=['col1', 'col2', 'col3'], keep=False)]

문서 에 따르면 ,

  • subset중복 여부를 확인해야하는 선택한 열의 목록이 될 수 있습니다. 기본적으로 모든 열을 사용합니다.
  • keep모든 발생 False을 유지하도록 설정됩니다 .

결과를 목록 목록으로 원할 경우 위에서 작성한 코드를 약간 수정하면 문제가 해결 될 수 있습니다.

1 anky Aug 21 2020 at 22:33

또 다른 접근 방식을 추가 pd.factorize하고Index.groupby

idx = pd.factorize(list(map(tuple,df.to_numpy().tolist())))[0]

d = {g[0]: [*g[1:]] for _,g in df.index.groupby(idx).items() if len(g)>1}

{1000084: [1000092, 1000116], 1000096: [1000110]}

또는 df.to_records()이전 방법보다 느릴 수 있습니다.

idx = pd.factorize(df.to_records(index=False))[0]
d = {g[0]: [*g[1:]] for _,g in df.index.groupby(idx).items() if len(g)>1}