Sparta/Theory

[250828] 스파르타코딩 본캠프 18일차 (1) - pandas 01

junecho 2025. 8. 28. 12:59

🟡 pandas 1차 강의 🟡

✅ 기본 구조                                                              

🔰 Series                                                                                                                    

1차원 배열 형태의 자료구조. 값(value)들의 모음에 각각 인덱스(index)라는 이름표가 붙어있는 구조

import pandas as pd

scores = pd.Series([90, 80, 85, 95])
print(scores)

*>>> 출력
0    90
1    80
2    85
3    95
dtype: int64*
subjects = pd.Series([90, 80, 85, 95], index=['국어','영어','수학','과학'])
print(subjects)
print(subjects["수학"])   # 출력 : *85*
print(subjects.values)    # 출력 : *[90 80 85 95]*
print(subjects.index)     # 출력 : *Index(['국어', '영어', '수학', '과학'], dtype='object')*

*>>> 출력
국어    90
영어    80
수학    85
과학    95
dtype: int64*

 

🔰 DataFrame                                                                                                               

2차원 표 형태의 자료구조로, 행(row)열(column)으로 구성

여러 개의 Series가 같은 인덱스를 기준으로 모여 있는 형태

SQL의 테이블과 비슷한 구조이며, 판다스에서 데이터를 다룰 때 가장 많이 사용하는 핵심 객체

✨ 파이썬의 딕셔너리(dict) 로부터 생성 ✨

data = {
    '이름': ['Alice', 'Bob', 'Charlie'],
    '나이': [25, 30, 35],
    '도시': ['New York', 'Los Angeles', 'Chicago']
}
df = pd.DataFrame(data)
print(df)

*>>> 출력
       이름 나이        도시
0    Alice  25     New York
1      Bob  30  Los Angeles
2  Charlie  35      Chicago*
print(df.head(n))      # 출력 : 상위 n개 행 표시. n생략시 5개 표시.
print(df.tail(n))      # 출력 : 하위 n개 행 표시. n생략시 5개 표시.
print(df.columns)      # 출력 : Index(['이름', '나이', '도시'], dtype='object')
print(df.index)        # 출력 : RangeIndex(start=0, stop=3, step=1)
print(df.shape)        # 출력 : (3, 3)
print(df.info())       # 각 컬럼의 타입, null 개수 등 정보 출력
print(df.describe())   # 수치형 컬럼들의 통계 요약

>>> 출력
↓ print(df.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3 entries, 0 to 2
Data columns (total 3 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   이름      3 non-null      object
 1   나이      3 non-null      int64 
 2   도시      3 non-null      object
dtypes: int64(1), object(2)
memory usage: 200.0+ bytes
None

↓ print(df.describe())
나이
count   3.0
mean   30.0
std     5.0
min    25.0
25%    27.5
50%    30.0
75%    32.5
max    35.0

 

🔰 판다스 주요 데이터 타입                                                                                       

1) 수치형 (Numeric Types)

  • int: 정수형 (예: int8, int16, int32, int64)
  • → 메모리 크기에 따라 나뉨 (int64가 기본)
  • float: 실수형 (예: float16, float32, float64)
  • → 소수점을 포함하는 데이터 (float64가 기본)

📌 활용: 평균, 합계, 표준편차, 수학 연산 가능

2) 문자열/범주형 (Text / Categorical Types)

  • object: 문자열, 혹은 혼합된 데이터(숫자+문자 등)를 저장하는 일반 타입(문자열이 들어오면 자동으로 object dtype으로 잡힘)
  • string: 판다스 1.0 이후 도입된 전용 문자열 타입
  • → object보다 일관성이 있고 문자열 메서드 사용에 안전함
  • category: 범주형 데이터 (카테고리) 저장용 특수 타입→ 순서(ordered=True)를 지정하면 크기 비교 가능
  • → 고유값을 코드로 매핑해 메모리 절약 & 연산 속도 향상

📌 활용: 성별, 지역, 직업 등 집단을 나타내는 데이터

3) 불리언 (Boolean Type)

  • bool: True / False 값 저장
  • 최근엔 boolean (nullable) 타입도 있음 → 결측치(NaN)와 함께 사용 가능

📌 활용: 조건 필터링, 마스크 연산

4) 날짜/시간 (Datetime Types)

  • datetime64[ns]: 날짜/시간 데이터 (년, 월, 일, 시, 분, 초, 나노초 단위)
  • timedelta[ns]: 두 시점 사이의 차이(시간 간격)
  • period: 일정한 기간(예: 월별, 연도별)

📌 활용: 시계열 분석, 날짜 인덱스, 리샘플링

5) 결측치/특수값

  • NaN: 수치형에서의 결측치 (Not a Number)
  • NaT: 날짜형에서의 결측치 (Not a Time)
  • None: 파이썬 기본 결측값 (object 컬럼에서 보통 NaN처럼 처리됨)

dtype 확인 & 변환

  • 확인: df.dtypes, df.info()
  • 변환: astype() 메서드 활용
df['age'] = df['age'].astype('int')
df['gender'] = df['gender'].astype('category')
df['joined'] = pd.to_datetime(df['joined'])

정리

  • 수치형(int/float) → 연산, 통계에 사용
  • 문자열(object/string) → 텍스트 데이터
  • 범주형(category) → 라벨/집단 구분, 메모리 효율
  • 불리언(bool) → 조건 필터링
  • 날짜(datetime, timedelta) → 시계열 처리

 

 

 

✅ 데이터 불러오기 및 저장                                    

🔰 CSV 파일 읽기/쓰기                                                                                        

pd.read_csv('파일경로')

  • : 파일 경로 또는 URL로부터 CSV 파일을 읽어 DataFrame 을 얻음
  • 구분자가 콤마가 아닌 경우 sep 인자를 지정할 수 있고, 헤더가 없는 파일은 header=None으로 읽은 뒤 컬럼 이름을 지정
  • 한글이 포함된 CSV의 경우 인코딩 문제로 읽지 못할 때 pd.read_csv('file.csv', encoding='utf-8') 혹은 필요한 인코딩(e.g. 'cp949')을 지정
  • parse_dates=['Order Date']처럼 날짜 컬럼을 바로 날짜 타입으로 읽도록 지정할 수 있음
orders = pd.read_csv("superstore_orders.csv")
print(orders.head(5))

*>>> 출력
Row ID        Order ID  Order Date   Ship Date       Ship Mode Customer ID  ....
0       1  CA-2017-152156  08/11/2017  11/11/2017    Second Class    CG-12520   
1       2  CA-2017-152156  08/11/2017  11/11/2017    Second Class    CG-12520   
2       3  CA-2017-138688  12/06/2017  16/06/2017    Second Class    DV-13045   
3       4  US-2016-108966  11/10/2016  18/10/2016  Standard Class    SO-20335   
4       5  US-2016-108966  11/10/2016  18/10/2016  Standard Class    SO-20335* 

 

DataFrame.to_csv('파일경로',  index=False)

  • : 편집 또는 분석한 데이터프레임을 CSV로 저장
  • Index=False를 지정하면 행 인덱스 저장하지 않고 오직 데이터만 저장 (행 번호 의미 없는 경우 다수)
orders.to_csv('processed_orders.csv', index=False)

 

🔰 Excel 파일 읽기/쓰기                                                                                        

  • pd.read_excel('파일경로', sheet_name=0)
    • : 엑셀 파일 읽기
    • sheet_name 파라미터로 시트 이름이나 번호를 지정하여 특정 시트만 불러옴 (기본 0 첫번째)
  • DataFrame.to_excel('파일경로', index=False)
    • : 데이터프레임을 엑셀 파일로 저장
  • DataFrame.to_excel(writer, sheet_name='Sheet1')
    • : 여러 데이터프레임을 다른 시트에 쓸 수 있음
import pandas as pd

df_sample = pd.DataFrame({"X": [1, 2], "Y": [3, 4]})    # 샘플 데이터프레임 생성
df_sample.to_excel("sample.xlsx", index=False)          # Excel로 저장
df_new = pd.read_excel("sample.xlsx")                   # Excel로부터 읽기
print(df_new)

*>>> 출력
   X  Y
0  1  3
1  2  4*
# orders라는 df를 상위 3줄만 가져와서 orders_sample.xlsx 로 저장하겠다
orders.head(3).to_excel("orders_sample.xlsx", index=False) 
orderxl = pd.read_excel("orders_sample.xlsx")
print(orderxl)

*>>> 출력
  Row ID        Order ID  Order Date   Ship Date     Ship Mode Customer ID  \\
0       1  CA-2017-152156  08/11/2017  11/11/2017  Second Class    CG-12520   
1       2  CA-2017-152156  08/11/2017  11/11/2017  Second Class    CG-12520   
2       3  CA-2017-138688  12/06/2017  16/06/2017  Second Class    DV-13045*   

 

🔰 JSON 파일 읽기/쓰기                                                                                        

  • pd.read_json('파일경로')
    • : JSON 구조가 표 형태로 바로 떨어지는 경우에만 데이터프레임으로 만들 수 있음
  • DataFrame.to_json('파일경로', orient='records')
    • : 데이터를 JSON 파일로 저장
    • orient=’records’ ⇒ 밑의 예씨와 같이 리스트 내부에 각 행이 객체(record)로 표현된 JSON 형태로 저장됨 (orient=’columns’ 로 저장하면 조금 다른 포맷이 되므로 일반적으로 ’records’)
    # people.JSON 파일 
    [
      {"name": "Alice", "age": 25, "city": "NY"},
      {"name": "Bob", "age": 30, "city": "LA"}
    ]
    
    people = pd.read_json('people.json')
    print(people)
    
    *>>> 출력
        name  age city
    0  Alice   25   NY
    1    Bob   30   LA*
    

 

 

 

✅ 데이터 인덱싱 / 슬라이싱                                   

🔰 .loc                                                                                                                     

.loc[행인덱스, 열이름]

라벨 기반 인덱싱

  • 인덱스의 이름이나 컬럼 이름을 사용해 원하는 부분의 데이터를 가져옴
  • 양끝을 모두 포함 ⭕ (숫자 라벨이어도 .loc[1:3]이라면 1,2,3 인덱스를 모두 포함)

예시 ) 인덱스 라벨이 문자형인 데이터프레임 생성. 인덱스 라벨은 a, b, c, d,e

df = pd.DataFrame({'val': [10, 20, 30, 40, 50]}, index=['a','b','c','d','e'])
print(df)

*>>> 출력
   val
a   10
b   20
c   30
d   40
e   50*
print(df.loc["a" : "c"])

>>> 출력
   val
a   10
b   20
c   30
  • df.loc['b'] : 인덱스 'b'인 한 행을 선택하면 그 행이 Series로 반환
  • df.loc[:, 'val'] : : 을 사용해 모든 행에 대해 특정 열만 선택
  • df.loc[df['val'] > 20] : boolean 배열(조건) 사용 가능
print(df.loc['b', 'val'])              # 출력 : 20
print(df.loc[['a','c'], 'val'])        # 출력 : a    10  c    30
print(df.loc[:, 'val'])
print(df.loc[df['val'] > 20])

*>>> 출력
↓ print(df.loc[:, 'val'])
a    10
b    20
c    30
d    40
e    50

↓ print(df.loc[df['val'] > 20])
   val
c   30
d   40
e   50*

 

 

🔰 .iloc                                                                                                                    

.iloc[행번호, 열번호]

정수 기반 인덱싱

  • 0부터 시작하는 정수 인덱스 위치로 데이터를 선택
  • 파이썬의 리스트 슬라이싱과 유사하게 동작하며, 끝 범위를 포함 ❌
print(df.iloc[0:2])

*>>> 출력
   val
a   10
b   20*

 

 

🔰                                                                                                                              

  • 컬럼 선택
    • 특정 열 선택 : df['컬럼명']
    • ex. orders['Profit']은 orders 데이터프레임에서 'Profit' 컬럼만 추출하여 Series로 반환
    • 여러 열 선택 : df[['컬럼1','컬럼2']] 같이 리스트로 컬럼명 전달
    • ex. df.loc[:, ['컬럼1','컬럼2']]와 같은 표현은 모든 행에 대해 두 컬럼을 선택
  • 행 슬라이싱
    • 범위로 슬라이싱 할 때 .loc과 .iloc를 모두 사용 가능
    • 보통은 행은 .iloc로 번호 기반 슬라이싱을, 열은 이름으로 지정하는 혼합 형태를 씀
    • ex. df.iloc[:5, :3]는 첫 5행, 첫 3열 데이터를 선택
  • 특정 컬럼의 값 분포
    • value_counts()
    • ex. df[특정 컬럼].value_counts()

 

 

 

✅ 조건 필터링                                                          

단일 조건으로 필터링

  • 판다스에서는 조건식을 활용한 불리언 인덱싱(Boolean Indexing)으로 필터링을 간단하게 구현
  • DataFrame이나 Series에 조건식을 적용하면 True/False 값으로 이루어진 동일한 크기의 불리언 Series가 만들어짐. 이 값을 인덱싱에 사용하면 True에 해당하는 행만 선택됨
  • 조건식을 대괄호 [] 안에 넣어 인덱싱함으로써 매우 간단히 필터링을 수행
  • 예시 ) seaborn 라이브러리의 tips 데이터셋 사용하여 진행
import seaborn as sns

tips = sns.load_dataset("tips")
print(tips.head(6))

>>> 출력
   total_bill   tip     sex smoker  day    time  size
0       16.99  1.01  Female     No  Sun  Dinner     2
1       10.34  1.66    Male     No  Sun  Dinner     3
2       21.01  3.50    Male     No  Sun  Dinner     3
3       23.68  3.31    Male     No  Sun  Dinner     2
4       24.59  3.61  Female     No  Sun  Dinner     4
5       25.29  4.71    Male     No  Sun  Dinner     4
  • tip 금액이 5 초과인 경우를 필터링 ⇒ tips['tip'] > 5
high_tips = tips[tips["tip"] > 5]
print(high_tips[["total_bill", "tip", "day"]].head())

>>> 출력
    total_bill   tip  day
23       39.42  7.58  Sat
44       30.40  5.60  Sun
47       32.40  6.00  Sun
52       34.81  5.20  Sun
59       48.27  6.73  Sat

 

여러 조건 결합

  • 조건을 여러 개 결합할 때는 논리 연산자 &(AND), |(OR), ~(NOT) 등을 사용
  • 이 때 반드시 각 조건을 괄호로 묶고, 파이썬의 and/or 대신 판다스용 & / | 를 사용
  • 예시 ) 요일이 Sun 이면서 팁이 5 초과인 경우
cond = (tips["day"] == "Sun") & (tips["tip"] > 5)
suntip = tips[cond]
print(suntip[["total_bill", "tip", "day"]].head())

*>>> 출력
     total_bill   tip  day
44        30.40  5.60  Sun
47        32.40  6.00  Sun
52        34.81  5.20  Sun
116       29.93  5.07  Sun
155       29.85  5.14  Sun*

 

.loc 를 사용한 조건 필터링

  • df.loc[ 조건식 ]
  • tips.loc[tips['time']=='Dinner', :] : Dinner인 모든 행을 선택

⇒ .loc 안에서 콤마 좌측에 조건식을 넣고, 콤마 우측에 :를 넣어 모든 컬럼을 선택. 이는 tips[tips['time']=='Dinner']와 동일한 결과

 

필터링된 데이터 활용

  • 필터링 결과도 데이터프레임이므로, 이어서 다른 연산을 할 수 있음
  • 예시 ) 요일에 팁을 $5 넘게 준 그룹들의 평균 총 지불 금액은 얼마?
  • mean_total = suntip["total_bill"].mean() print(f"일요일에 $5 초과 팁을 준 그룹들의 총 지불액 평균 : ${mean_total:.2f}") *>>> 출력 일요일에 $5 초과 팁을 준 그룹들의 총 지불액 평균 : $26.39*

 

 

 

✅ 데이터 정렬 / 정제                                               

🔰 데이터 정렬                                                                                                       

데이터 정렬 (sorting) : 데이터를 값의 크기나 알파벳순으로 순서대로 배치

sort_values() - 값을 기준으로 정렬

  • 기본은 오름차순(ascending=True)이며, 내림차순은 ascending=False
  • by 파라미터에 컬럼명을 지정하여 정렬 기준 컬럼을 설정 (Series에는 by 없이 자기 자신의 값 기준으로 정렬)
  • by 파라미터를 사용해서 여러 컬럼을 기준으로 정렬도 가능하고 ascending=[False, True] 처럼 각기 다른 정렬을 줄 수 있음
  • 예시 ) tips 에서 팁 금액이 큰 순서대로 상위 몇 개 행을 보고 싶다
sorted_tips = tips.sort_values(by="tip", ascending=False)
print(sorted_tips[["total_bill", "tip", "size"]].head(3))

*>>>
     total_bill    tip  size
170       50.81  10.00     3
212       48.33   9.00     4
23        39.42   7.58     4*

sort_index() - 인덱스를 기준으로 정렬

  • 행 인덱스 라벨을 기준으로 정렬
  • 기본 오름차순이며, ascending=False로 내림차순 정렬
  • 예시 ) 인덱스 내림차순
reverse_idx = tips.sort_index(ascending=False)
print(reverse_idx.head(4))

*>>> 출력
     total_bill   tip     sex smoker   day    time  size
243       18.78  3.00  Female     No  Thur  Dinner     2
242       17.82  1.75    Male     No   Sat  Dinner     2
241       22.67  2.00    Male    Yes   Sat  Dinner     2
240       27.18  2.00  Female    Yes   Sat  Dinner     2*

 

🔰 데이터 정제                                                                                                   

데이터 정제(cleaning) : 데이터셋에서 잘못되거나 불필요한 데이터를 수정 또는 제거하는 모든 작업

컬럼명 정리

  • DataFrame.rename()
  • orders.columns = [col.lower() for col in orders.columns] 식으로 컬럼명을 전부 소문자로 바꾸는 식의 처리도 할 수 있음
# Order Date 컬럼 -> Order_Date 로 변경
orders = orders.rename(columns={'Order Date': 'Order_Date'})
print(orders.head(3))

>>>
   Row ID        Order ID  Order_Date   Ship Date     Ship Mode Customer ID  \
0       1  CA-2017-152156  08/11/2017  11/11/2017  Second Class    CG-12520   
1       2  CA-2017-152156  08/11/2017  11/11/2017  Second Class    CG-12520   
2       3  CA-2017-138688  12/06/2017  16/06/2017  Second Class    DV-13045

 

불필요한 컬럼 제거

  • DataFrame.drop()
  • 컬럼을 제거할 때는 axis=1 또는 columns= 파라미터를 사용
# 'Row ID' 컬럼은 행별 식별자. 단순 행 번호이므로 불필요하여 제거
 orders = orders.drop(columns=['Row ID'])

데이터 값 수정 / 제거

  • Series.str.strip() : 불필요한 좌우 공백 제거
  • Series.str.lower() or Series.str.upper() : 대소문자 섞인 값을 통일
import pandas as pd 

cities = pd.Series([' new york', 'Los Angeles ', 'Chicago', ' new york'])
cleaned1 = cities.str.strip()
cleaned2 = cities.str.strip().str.title()
print(cleaned1)
print(cleaned2)

>>>
*↓* print(cleaned1)
0       new york
1    Los Angeles
2        Chicago
3       new york
dtype: object

*↓* print(cleaned2)
['New York' 'Los Angeles' 'Chicago']

 

 

 

✅ 결측치 처리                                                         

결측치(Missing Data)❓

데이터셋에서 값이 채워져 있지 않은 항목. 보통 빈 값, NULL, NaN(Not a Number) 등의 형태로 표현

예시) 간단한 데이터프레임 생성

import numpy as np

df_miss = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'age': [25, np.nan, 30],
    'city': ['New York', 'Los Angeles', np.nan]
})
print(df_miss)

*>>> 출력
      name   age         city
0    Alice  25.0     New York
1      Bob   NaN  Los Angeles
2  Charlie  30.0          NaN*

🔰 결측치 확인                                                                                                   

isnull() / notnull()

  • Series나 DataFrame의 각 원소가 결측치인지 아닌지를 True/False로 나타내는 동일한 모양의 객체를 반환
  • df.isnull()은 결측이면 True, 값이 있으면 False
  • df.notnull()은 반대로 값이 있으면 True

df.isnull().sum()

  • 각 컬럼별 결측치 개수 확인 (True를 1로 간주하여 합계)
  • 또는 df.info()에서도 Non-Null Count를 보여주므로 간접적으로 알 수 있음
print(df_miss.isnull().sum())

>>>
name    0
age     1
city    1
dtype: int64

# df_miss 데이터프레임에서 Bob의 나이(age)가 NaN으로 결측이며, 
# Charlie의 도시(city)가 NaN으로 결측

 

🔰 결측치 삭제                                                                                                   

dropna

  • 결측치가 있는 행(row) 또는 열(column)을 제거
  • 하나라도 결측치가 있는 행을 모두 제거
  • 결측치가 데이터의 일부 열에만 집중되어 있다면, 특정 열만 제거
    • df.dropna(subset=['컬럼명1', '컬럼명2'], inplace=False
    • thresh(임계치) 옵션으로 일정 개수 이상의 값이 있는 행만 남기는 등의 조정
print(df_miss.dropna())

>>>
    name   age      city
0  Alice  25.0  New York

위 결과를 보면 결측치가 있던 행(인덱스 1과 2)이 제거되고, Alice의 데이터만 남음

이렇게 하면 간단히 결측치를 없앨 수 있지만, 데이터 손실이 크기 때문에 상황에 따라 적절치 않을 수 있음

df.dropna(axis=1)

  • 특정 축 방향으로 삭제 ⇒ 결측치 있는 컬럼을 제거
print(df_miss.dropna(axis=1))

*>>> 출력
      name
0    Alice
1      Bob
2  Charlie*

결측치 있던 컬럼인 age와 city 컬럼이 날아가고 name만 남음

이는 일반적으로 정보 손실이 크므로 잘 안 씀

대신 행 삭제는 흔히 사용되지만, 가능한 경우에만 사용

 

🔰 결측치 대체                                                                                                   

fillna

  • 완전히 지워버리기 어려운 경우, 결측값을 다른 값으로 대체(impute)
  • 고정값 대체 : df.fillna(0)처럼 하나의 값(예: 0)으로 모든 결측치를 채움. 또는 컬럼별로 다른 값으로 채우고 싶다면 딕셔너리를 인자로 df.fillna({'age': df['age'].mean(), 'city': 'Unknown'})
  • 통계값으로 대체 : 보통 수치형 데이터는 평균이나 중앙값으로 결측치를 채우고, 범주형 데이터는 최빈값 또는 'Unknown'같은 표시로 채우기도 함
  • inplace=True : 원 데이터프레임을 직접 수정. inplace를 사용하지 않으면 df_filled = df_miss.fillna({...}) 형태로 새로운 객체를 받아야 함. 코드 스타일에 따라 둘 중 편한 것 쓰기
df_filled = df_miss.copy()
df_filled["age"].fillna(df_filled["age"].mean(), inplace=True)
df_filled["city"].fillna("Unknown", inplace=True)
print(df_filled)

*>>> 출력
      name   age         city
0    Alice  25.0     New York
1      Bob  27.5  Los Angeles
2  Charlie  30.0      Unknown*

Bob의 age가 27.5로 채워짐 (25과 30의 평균인 27.5를 대입).

Charlie의 city가 'Unknown' 문자열로 채워짐

이렇게 하면 더 이상 결측치가 없으므로 이후 분석에서 오류가 날 가능성이 줄어든다

 

결측치 처리 전략

어떤 방법이 좋은지는 데이터의 특성과 분석 목적에 따라 다름.

중요한 컬럼에 결측치가 많다면 행을 버리는 것은 위험하고, 그렇다고 함부로 채우는 것도 왜곡을 줄 수 있음.

따라서,

  • 가능한 한 데이터 수집 단계에서 결측을 줄이도록 하고,
  • 불가피한 결측에 대해서는 삭제해도 되는지, 대체해야 하는지 판단하라
  • 대체한다면 그 근거(평균? 이전값? 도메인 지식 기반?)를 생각해야 하며, 결측치를 별도의 범주로 취급하는 방법도 있다.

 

 

 

 

✅ 중복 제거                                                              

중복 데이터(duplicates)❓

데이터셋에서 완전히 동일한 행이 반복되는 경우나, 특정 기준으로 볼 때 중복인 데이터 포인트

중복 데이터는 분석 결과를 왜곡시킬 수 있으므로, 적절히 제거하거나 처리

duplicated()

  • 각 행이 이전에 나타난 적이 있는지 여부를 True/False로 표시한 불리언 Series를 반환
  • 기본으로 첫 번째 등장만 False (중복 아님)이고, 그 이후 중복들은 True로 표시. (duplicated(keep='first')가 기본 동작.
  • 반대로 'last'로 하면 마지막만 남기고 처음들을 True로 표시, False로 하면 모든 중복을 True 표시).
df_dup = pd.DataFrame({'A': [1, 1, 2, 3], 'B': [5, 5, 6, 7]})
print(df_dup)
print("--------Duplicates :\\n", df_dup.duplicated())

>>> 출력
   *A  B
0  1  5
1  1  5
2  2  6
3  3  7
--------Duplicates :
0    False
1     True
2    False
3    False*

drop_duplicates()

  • 중복 행을 제거
  • 기본적으로 처음 등장한 행은 남기고 이후 중복은 제거하며 (keep='first'), 인덱스는 기존 순서를 유지합니다 (인덱스가 재정렬되진 않음).
  • 원본을 변경하려면 inplace=True를 쓰거나, 결과를 새로운 데이터프레임으로 받아야 함
print(df_dup.drop_duplicates())

*>>> 출력
   A  B
0  1  5
2  2  6
3  3  7*

 

특정 열 기준 중복 제거

  • 가령 여러 열 중 특정 열만 보고 중복 판단을 할 수도 있음
  • df.drop_duplicates(subset=['컬럼명'])으로 지정하면 해당 컬럼값이 같은 행들 중 중복을 제거
  • 예를 들어 subset=['A']로 하면 A열 값이 같은 행은 하나만 남기고 제거

keep 옵션

  • keep='first'|'last'|False 옵션으로 중복 데이터 중 어느 것을 남길지 결정
  • 기본 'first'는 처음 발견을 남김, 'last'는 마지막 발견을 남김, False는 중복된 것 전부 제거 (이 경우 중복 그룹의 데이터가 아예 없어짐)

 

 

 

 


🔰 과제                                                                                                  

실습