Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

Pandas에서 중복 행 찾고 필터링하는 방법 총정리

데이터 분석을 하다 보면 중복된 행을 무조건 삭제하기보다는 먼저 살펴보며 데이터를 깊이 이해해야 하는 경우가 종종 있습니다. 다행히 Pandas에는 중복 데이터를 손쉽게 다룰 수 있는 다양한 메서드가 마련되어 있습니다.

이 글에서는 duplicated(), drop_duplicates(), unique(), nunique() 네 가지 핵심 메서드를 예제와 함께 자세히 알아보겠습니다.

.duplicated() 메서드

duplicated() 메서드는 DataFrame에서 중복된 행을 추출할 때 사용합니다. 중복 값이 포함된 HR 데이터셋을 불러와 실습해 보겠습니다.

import pandas as pd
import numpy as np

# 특정 컬럼만 선택하여 HR 데이터셋 불러오기
df = pd.read_csv("https://raw.githubusercontent.com/sasankac/TestDataSet/master/HRDataset.csv",
                 usecols=("Employee_Name", "PerformanceScore", "Position", "CitizenDesc"))

# 직원 이름 기준으로 정렬 후 원본에 반영
df.sort_values("Employee_Name", inplace=True)
df.head(3)
Employee_NamePositionCitizenDescPerformanceScore
0AdinolfiProduction Technician IUS CitizenExceeds
1AdinolfiSr. DBAUS CitizenFully Meets
2AdinolfiProduction Technician IIUS CitizenFully Meets

keep 파라미터의 기본 동작

duplicated()는 기본적으로 keep 파라미터에 따라 동작하며, 각 값의 첫 번째 등장은 '중복 아님'으로 표시합니다.

즉, 어떤 행이 여러 번 나타나더라도 그 행 자체가 중복으로 표시되는 것이 아니라, 첫 번째 등장 이후의 행들만 중복으로 표시됩니다. 비유하자면 바구니에 사과가 3개 들어 있다면, 첫 번째 사과는 '중복 아님'으로, 나머지 두 개는 '중복'으로 표시하는 방식입니다.

예제

df["Employee_Name"].head(3)

출력 결과:

0    Adinolfi
1    Adinolfi
2    Adinolfi
Name: Employee_Name, dtype: object
df["Employee_Name"].duplicated().head(3)

출력 결과:

0    False
1     True
2     True
Name: Employee_Name, dtype: bool

중복 행을 실제로 추출하려면(첫 번째 등장은 제외하고 이후 등장만 출력) 이 불리언 시리즈를 DataFrame에 전달하면 됩니다.

df.shape
(310, 4)
df[df["Employee_Name"].duplicated()]
Employee_NamePositionCitizenDescPerformanceScore
1AdinolfiSr. DBAUS CitizenFully Meets
2AdinolfiProduction Technician IIUS CitizenFully Meets
3AdinolfiProduction Technician IUS CitizenFully Meets
4AdinolfiProduction ManagerUS CitizenFully Meets
6AndersonProduction Technician IUS CitizenExceeds
...............
303WangProduction Technician IIUS CitizenFully Meets
304WangProduction Technician IIUS CitizenFully Meets
305WangProduction Technician IUS CitizenPIP
306WangCIOUS CitizenExceeds
307WangData AnalystUS CitizenFully Meets

전체 310행 중 79개의 중복 행.duplicated() 메서드로 추출되었습니다.

keep='last' 옵션

기본 설정에서는 첫 번째 등장이 '중복 아님'으로 표시되지만, keep='last' 인자를 전달하면 이 동작을 반대로 바꿀 수 있습니다.

사과 비유로 말하면, 앞의 두 사과는 '중복'으로 표시하고 마지막 사과만 '중복 아님'으로 남기는 방식입니다.

df[df["Employee_Name"].duplicated(keep="last")]
Employee_NamePositionCitizenDescPerformanceScore
0AdinolfiProduction Technician IUS CitizenExceeds
1AdinolfiSr. DBAUS CitizenFully Meets
2AdinolfiProduction Technician IIUS CitizenFully Meets
3AdinolfiProduction Technician IUS CitizenFully Meets
5AndersonProduction Technician IUS CitizenFully Meets
...............
302WangProduction Technician IIUS CitizenExceeds
303WangProduction Technician IIUS CitizenFully Meets
304WangProduction Technician IIUS CitizenFully Meets
305WangProduction Technician IUS CitizenPIP
306WangCIOUS CitizenExceeds

keep=False 옵션

keep 파라미터는 False도 받을 수 있으며, 이 경우 두 번 이상 등장하는 모든 값을 중복으로 표시합니다. 즉, 위 예제들처럼 첫 번째나 마지막 하나만 남기는 것이 아니라, 3개의 사과가 모두 '중복'으로 표시됩니다.

주의 – False를 지정할 때는 따옴표 없이 작성해야 합니다.

df[df["Employee_Name"].duplicated(keep=False)]
Employee_NamePositionCitizenDescPerformanceScore
0AdinolfiProduction Technician IUS CitizenExceeds
1AdinolfiSr. DBAUS CitizenFully Meets
2AdinolfiProduction Technician IIUS CitizenFully Meets
3AdinolfiProduction Technician IUS CitizenFully Meets
4AdinolfiProduction ManagerUS CitizenFully Meets
...............
303WangProduction Technician IIUS CitizenFully Meets
304WangProduction Technician IIUS CitizenFully Meets
305WangProduction Technician IUS CitizenPIP
306WangCIOUS CitizenExceeds
307WangData AnalystUS CitizenFully Meets

물결표(~)로 고유값만 추출하기

마지막으로, 데이터셋에서 완전히 고유한 값(단 한 번만 등장한 값)만 추출하려면 물결표(~) 기호로 조건을 부정(negate)하면 됩니다.

df_unique = ~df["Employee_Name"].duplicated(keep=False)
df[df_unique]
Employee_NamePositionCitizenDescPerformanceScore
7AndreolaSoftware EngineerUS CitizenFully Meets
25BozziProduction ManagerUS CitizenFully Meets
26BramanteDirector of OperationsUS CitizenExceeds
27BrillProduction Technician IUS CitizenFully Meets
34BurkettProduction Technician IIUS CitizenFully Meets
...............
276SweetwaterSoftware EngineerUS CitizenExceeds
277SzaboProduction Technician INon-CitizenFully Meets
278TavaresProduction Technician IIUS CitizenFully Meets
308ZhouProduction Technician IUS CitizenFully Meets
309ZimaNaNNaNNaN

drop_duplicates() 메서드

drop_duplicates()는 앞서 본 메서드와 매우 유사하지만, Series가 아닌 DataFrame 전체에 적용할 수 있다는 점이 다릅니다.

참고: 이 메서드는 DataFrame의 모든 컬럼을 기준으로 중복 행을 판별하여 제거합니다.

len(df)

출력 결과:

310
len(df.drop_duplicates())

출력 결과:

290

subset 파라미터

subset 파라미터에 문자열 형태의 컬럼명 리스트를 전달하면, 지정한 컬럼만을 기준으로 중복 여부를 검사할 수 있습니다.

df1 = df.drop_duplicates(subset=["Employee_Name"], keep="first")
df1
Employee_NamePositionCitizenDescPerformanceScore
0AdinolfiProduction Technician IUS CitizenExceeds
5AndersonProduction Technician IUS CitizenFully Meets
7AndreolaSoftware EngineerUS CitizenFully Meets
14AthwalProduction Technician IUS CitizenFully Meets
20BeakProduction Technician IUS CitizenFully Meets
...............
293Von MassenbachProduction Technician IIUS CitizenFully Meets
295WallaceProduction Technician IUS CitizenNeeds Improvement
300WangProduction Technician IEligible NonCitizenFully Meets
308ZhouProduction Technician IUS CitizenFully Meets
309ZimaNaNNaNNaN

여러 개의 컬럼을 지정할 수도 있으며, 앞서 설명한 모든 keep 파라미터(first, last, False)를 그대로 활용할 수 있습니다.

df1 = df.drop_duplicates(subset=["Employee_Name", "CitizenDesc"], keep=False)
df1
Employee_NamePositionCitizenDescPerformanceScore
7AndreolaSoftware EngineerUS CitizenFully Meets
16BeakProduction Technician IEligible NonCitizenFully Meets
25BozziProduction ManagerUS CitizenFully Meets
26BramanteDirector of OperationsUS CitizenExceeds
27BrillProduction Technician IUS CitizenFully Meets
...............
287TejedaNetwork EngineerEligible NonCitizenFully Meets
286TejedaSoftware EngineerNon-CitizenFully Meets
300WangProduction Technician IEligible NonCitizenFully Meets
308ZhouProduction Technician IUS CitizenFully Meets
309ZimaNaNNaNNaN

unique() 메서드

unique() 메서드는 Series에서 고유값을 찾아 배열(Array) 형태로 반환합니다. 이 메서드는 결측값(NaN)을 제외하지 않는다는 점에 유의하세요.

len(df["Employee_Name"])

출력 결과:

310
df["Employee_Name"].unique()

출력 결과:

array(['Adinolfi', 'Anderson', 'Andreola', 'Athwal', 'Beak', 'Bondwell',
       'Bozzi', 'Bramante', 'Brill', 'Brown', 'Burkett', 'Butler',
       'Carabbio', 'Carey', 'Carr', 'Carter', 'Chace', 'Champaigne',
       ... 생략 ...
       'Von Massenbach', 'Wallace', 'Wang', 'Zhou', 'Zima'], dtype=object)
len(df["Employee_Name"].unique())

출력 결과:

231

nunique() 메서드

nunique() 메서드는 Series에 포함된 고유값의 개수를 반환합니다. 기본적으로 dropna=True 파라미터가 적용되어 결측값은 개수에서 제외됩니다.

결측값까지 포함하여 세고 싶다면 dropna 파라미터에 False를 전달하면 됩니다.

df["Employee_Name"].nunique()

출력 결과:

231
df["Employee_Name"].nunique(dropna=False)

출력 결과:

231

마무리

정리하면, duplicated()는 중복 여부를 확인하고 추출할 때, drop_duplicates()는 중복 행을 실제로 제거할 때, unique()nunique()는 고유값과 그 개수를 확인할 때 각각 유용하게 사용할 수 있습니다. 상황에 맞는 메서드를 조합하면 데이터 정제 작업을 훨씬 효율적으로 수행할 수 있습니다.