[데이터 처리 #4] DataFrame 변경

개요

이전 포스팅 [데이터 처리 #3]에서는 DataFrame을 조회하는 방법에 대해 알아보았다.

시리즈와 데이터프레임 구조의 차이점을 알아보고, loc() 함수를 통해 특정 행과 열을 조회하거나 조건을 통해 필터링된 결과를 조회하는 방법에 대해 학습하였다.

2025.06.16 - [Study/Machine Learning, Deep Learning] - [데이터 처리 #3] DataFrame 조회

 

[데이터 처리 #3] DataFrame 조회

개요이전 포스팅 [데이터 처리 #2]에서는 DataFrame을 탐색하는 방법에 대해 알아보았다.주요 속성 및 메서드를 통해 데이터프레임의 기본 정보를 확인하고, 집계 함수를 통해 수치형 열들에 대한

storyinstory.tistory.com

 

이번 포스팅에서는 DataFrame에 대해 다음의 내용을 학습 목표로 삼는다.

  1. 데이터프레임에 필요한 새로운 열을 추가하는 방법
  2. 기존 열을 변경하거나 불필요한 열을 제거하는 방법
  3. 여러 데이터프레임을 하나로 연결하거나 병합하는 방법

데이터 정제 시, DataFrame에 대해 자유자재로 변경하는 법을 꼭 알아야 한다.

일반적으로 자주 사용되는 변경 방법들에 대해 소개하는 것에 의의를 두었음을 참고해주길 바란다.

 

열 이름 변경

# columns 속성 변경 : 모든 열 이름 변경
df.columns = ['total_bill', 'tip', 'sex', 'smoker', 'day', 'time', 'size']

# rename() 메서드 사용 : 지정한 열 이름 변경
# '기존명':'새로운 이름'
# inplace 옵션 (기본값:False) : 원본을 변경할 것인가

# 원본 변경 inplace=True
df.rename(columns= {
    'total_bill_amount': 'total_bill',
    'male_female': 'sex',
    'smoke_yes_no': 'smoker',
    'week_name': 'day',
    'dinner_lunch': 'time'}, inplace=True)

# 원본 변경 x (새로운 데이터프레임 반환)
new_df = df.rename(columns= {
    'total_bill_amount': 'total_bill',
    'male_female': 'sex',
    'smoke_yes_no': 'smoker',
    'week_name': 'day',
    'dinner_lunch': 'time'})

열 이름 변경 시, 실행 결과

 

열 추가

# 맨 뒤에 열 추가
# final_amt 열 추가
# total_bill의 각 열 값 + tip의 각 열 값 (두 열의 행 개수가 동일해야 함. 또한, NaN값이 없어야 함.)
df['final_amt'] = tip['total_bill'] + tip['tip']

맨 뒤에 추가된 final_amt 열 확인

  • 기존 데이터프레임에 없는 열을 변경하면, 그 열이 추가된다.
  • 맨 뒤 열로 추가되며, 원하는 위치에 열을 추가할 수는 없음. (바로 아래에서 원하는 위치 삽입 확인 가능)

 

# 지정한 위치에 열 추가

# insert() 메서드 구조
df.insert(삽입하고자 하는 index, 추가할 열이름, 추가할 시리즈 구조의 열 데이터)

# 예제
# 1번 인덱스 위치에, 'tip_tb'이름으로 열 추가 
# (기존의 1번 인덱스부터 마지막 인덱스들은 오른쪽으로 한 칸씩 밀림.)
df.insert(1, 'tip_tb', tip['total_bill'] / tip['size'])

지정한 위치에 추가된 tip_tb 열 확인

 

열 삭제

# 열 삭제 

# drop() 메서드 구조 (기본값 : axis=0, inplace=False)
df.drop(삭제할 열이름, axis=삭제방향(0 또는 1), inplace=원본삭제여부(True 또는 False))

# 예제1 : 열 1개 삭제
df.drop('final_amt', axis=1, inplace=True)

# 예제2 : 열 여러 개 삭제
new_df = df.drop(['tib_tb', 'day'], axis=1)

총 열 3개 삭제 (final_amt, tib_tb, day)

  • axis=0 : 행 삭제 (기본값)
  • axis=1 : 열 삭제

 

결측치 핸들링

데이터프레임 내에 결측치(NaN : Not a Number, null)이 존재하면 이에 따른 핸들링이 꼭 필요하다.

머신러닝/딥러닝 모델링 시, 데이터프레임 내에 결측치가 존재하면 모델은 이 값을 읽을 수 없기 때문이다. (자세한 내용은 추후 포스팅 예정)

그러므로, 결측치를 제거하거나 대체(채우기)하는 방법을 많이 사용한다.

이에 대해 자세히 알아보자.

 

결측치 조회

결측치 존재 여부를 확인하고 이를 어떻게 처리(핸들링)할 지 방법을 먼저 결정해야 한다.

다음의 방법 중 편한 방법을 사용하면 된다.

  • info()
  • isnull() 또는 isna()
  • notnull() 또는 notna()

코드 실행 시, 각 메서드에 대해 어떤 결과를 출력하는지 확인해보자

# info() 메서드
# 전체 행 개수보다 값 개수가 적은 경우 결측치 존재
df.info()

info() 실행 결과

 

# isnull() 또는 isna()
# 전체 데이터 중에서 결측치는 True로 표시
df.isna()
df.isnull()

isna() 또는 isnull() 실행 결과

 

# notna() 또는 notnull()
df.notna()
df.notnull()

notna() 또는 notnull() 실행 결과

 

# info() 처럼 결측치 개수를 각 열에 맞춰 조회하는 방법
# sum() 집계함수 활용
# 열의 결측치 개수 확인
df.isnull().sum()

집계함수를 활용한 결측치 조회 실행 결과

 

결측치 제거

# dropna() 메서드 사용.

# 어떤 열이든 결측치가 있는 행 제거
df.dropna(axis=0, inplace=True)

# 특정 열에 결측치가 있는 행 제거
# Ozone 열이 결측치인 행 제거
df.dropna(subset=['Ozone'], axis=0, inplace=True)

# 결측치가 있는 열을 제거 후, 새로운 데이터프레임 반환
dropped_new_df = df.dropna(axis=1)

 

결측치 대체(채우기)

fillna() : 다른값으로 결측치 대체

# 평균값으로 채우기
# 결측치가 있는 열의 평균값을 구한 후, 이 값으로 채움.
mean_Ozone = df['Ozone'].mean()
df['Ozone'].fillna(mean_Ozone, inplace=True)

# 특정값으로 채우기
# Solar.R 열의 누락된 값을 0으로 채우고, 새 데이터프레임 반환
new_df = df['Solar.R'].fillna(0)

 

ffill(), bfill() : 직전 행의 값 또는 바로 다음 행의 값으로 결측치 대체

# ffill() : 바로 앞의 값으로 변경
# Ozone 열의 누락된 값을 바로 앞의 값으로 채우기
df['Ozone'].ffill(inplace=True)

# bfill() : 바로 다음 값으로 변경
# Solar.R 열의 누락된 값을 바로 뒤의 값으로 채우기
df['Solar.R'].bfill(inplace=True)

 

interpolate() : 선형보간법으로 결측치 대체

# interpolate() : 선형보간법
df['Ozone'].interpolate(method='linear', inplace=True)
df['Solar.R'].interpolate(method='linear', inplace=True)

 

(선형보간법 TMI)

더보기

 

데이터프레임 합치기

concat() : 인덱스 값을 기준으로 합치기

concat 옵션에 따른 합치는 과정

  • 방향 선택
    • axis=0 : 세로(행) 합치기 (기본값)
    • axis=1 : 가로(열) 합치기
  • 방법 선택
    • join='outer' : 모든 행과 열 합치기
    • join='inner' : 매핑되는 행과 열만 합치기

예제를 통해 어떻게 합쳐지는지 파악해보자.

먼저, 다음의 두 데이터프레임을 합치려고 한다.

(왼쪽,오른쪽) = (pop01 데이터프레임, pop02 데이터프레임)

 

axis=1 옵션을 통해 가로(열)로 합친다고 가정했을 시, join 옵션에 따라 어떤 결과가 나오는지 살펴보자.

import pandas as pd
pop = pd.concat([pop01, pop02], join='outer', axis=1)

outer 실행 결과

import pandas as pd
pop = pd.concat([pop01, pop02], join='inner', axis=1)

inner 실행 결과

 

merge() : 두 데이터프레임에 공통으로 존재하는 특정 열을 지정하여 이를 기준으로 병합

merge 옵션에 따른 병합 과정

# merge 메서드 구조
import pandas as pd
new_df = pd.merge(df1, df2, on='열이름', how='병합방법')
  • how='left' : df1을 기준으로 병합
  • how='right' : df2를 기준으로 병합
  • how='outer' : 모든 행과 열 병합
  • how='inner' : 지정한 열을 기준으로 같은 인덱스로 매핑되는 행과열을 가로(열) 방향으로 병합

예제를 통해 어떻게 병합되는지 파악해보자.

먼저, 다음의 두 데이터프레임을 합치려고 한다.

데이터프레임 이름 : (왼쪽, 오른쪽) = (pop01, pop02)

 

'year' 열을 기준으로 inner와 outer 병합 결과를 확인하자.

import pandas as pd
pop = pd.merge(pop01, pop02, on='year', how='inner')

inner 병합 결과

import pandas as pd
pop = pd.merge(pop01, pop02, on='year', how='outer')

outer 병합 결과

 

마무리

이로써 데이터 분석에서 기본이 되는 DataFrame 자료구조에 대한 CRUD를 모두 학습하였다.

다양하고 편리한 유틸 함수들이 많으므로 이 시간 이후로 pandas 공식 문서를 정독해보기를 권한다.

이후 포스팅을 진행할 데이터 분석과 모델 개발에 있어, 데이터프레임은 초석이 되기 때문에 자유자재로 다룰 수 있도록 훈련하기를 바라며 데이터 처리 포스팅을 마친다.