이번 글은 코드잇 강의를 수강하면서 배운 내용을 주로 하여 정리되어 있습니다. (코드잇 스프린트 데이터 애널리스트 트랙 1기 훈련생)
문자 데이터 가공하기
대소문자 처리하기
데이터프레임을 다루다보면 숫자형 데이터 뿐만 아니라 문자형 데이터 또한 다뤄야 하는 상황을 겪게 됩니다.
이러한 상황 속에서, pandas에서는 문자열 데이터를 처리하기 위해 편리한 메소드로 str.upper(), str.lower(), str.title(), str.capitalize() 등과 같은 주요 메소드를 제공합니다.
# 데이터프레임에서 문자형 컬럼의 값들의 종류 확인하기
df['column_name(categoric)'].unique()
# 문자형 컬럼의 값을 확인할 때, 같은 범주인데도 대문자나 소문자로 다르게 표현된 경우, 컴퓨터는 이를 서로 다른 값으로 인식하여 반환합니다.
# 그래서 이 문자열 데이터를 통일하기 위해 다양한 메소드를 활용합니다.
# 문자형 컬럼의 값들을 모두 소문자로 변환하기
df['column_name(categoric)'] = df['column_name(categoric)'].str.lower() # str은 컬럼과 lower함수를 이어주는 역할을 합니다.
# 문자형 컬럼의 값들을 모두 대문자로 변환하기
df['column_name(categoric)'] = df['column_name(categoric)'].str.upper()
# 문자형 컬럼의 값들의 첫 글자만 대문자로, 나머지는 소문자로 변환하기
df['column_name(categoric)'] = df['column_name(categoric)'].str.capitalize()
문자형 컬럼의 값들을 모두 소문자로 변환하기 | df['column_name'].str.lower() |
문자형 컬럼의 값들을 모두 대문자로 변환하기 | df['column_name'].str.upper() |
문자형 컬럼의 값들의 첫 글자만 대문자로, 나머지는 소문자로 변환하기 | df['column_name'].str.capitalize() |
문자열 분리하기
데이터프레임을 다루다보면 한 컬럼에 2가지 내용으로 이루어진 값들이 있는 문자형 컬럼이 있는 경우가 있으며, 이 내용을 분리하고 싶은 경우 split을 활용하여 문자열을 분리할 수 있습니다.
# 2가지 내용이 ,로 구분되어 있는 경우 ,를 기준으로 컬럼의 값을 분리하기
df['column_name(categoric)'].str.split(',')
# ,를 기준으로 분리한 내용 중 앞부분의 내용만 가져오기
df['column_name(categoric)'].str.split(',').str[0]
# 분리한 앞부분의 내용을 새로운 컬럼으로 생성하기
df['new_column_1'] = df['column_name(categoric)'].str.split(',').str[0]
# ,를 기준으로 분리한 내용 중 뒷부분의 내용만 가져오기
df['column_name(categoric)'].str.split(',').str[1]
# 분리한 뒷부분의 내용을 새로운 컬럼으로 생성하기
df['new_column_2'] = df['column_name(categoric)'].str.split(',').str[1]
# 분리를 통해 모두 새로운 컬럼을 생성한 경우 기존 컬럼을 삭제하기
df = df.drop(columns='column_name(categoric)')
지정한 기준에 따라 컬럼의 값을 분리하기( , 가 예시로 사용) | df['column_name'].str.split(',') |
기준에 따라 분리한 내용 중 앞부분의 내용만 가져오기 | df['column_name'].str.split(',').str[0] |
기준에 따라 분리한 내용 중 뒷부분의 내용만 가져오기 | df['column_name'].str.split(',').str[1] |
불필요한 문자 제거하기
위에 방법에 따라 분리한 내용에 불필요한 문자나 공백이 포함되어 있는 경우나 기존 데이터프레임에 특정 컬럼에 불필요한 문자가 포함되어 있는 경우에 이를 제거할 필요가 있습니다.
# 문자 앞뒤에 존재하는 불필요한 공백 제거하기
df['column_name(categoric)'] = df['column_name(categoric)'].str.strip()
# 불필요한 문자 제거하기 (밑은 문자에 .이 있다고 가정하고 이를 제거하는 예시입니다.)
df['column_name(categoric)'] = df['column_name(categoric)'].str.replace('.', '', regex=False)
# 위 코드를 한번에 실행하기
df['column_name(categoric)'].str.strip().str.replace('.', '', regex=False)
문자 앞뒤에 존재하는 불필요한 공백 제거하기 | df['column_name'].str.strip() |
불필요한 문자 제거하기(예시로 . 를 제거) | df['column_name'].str.replace('.', '', regex=False) |
Pandas에서 문자 데이터 가공을 위한 코드 리스트
문자형 컬럼의 값들을 모두 소문자로 변환하기 | df['column_name'].str.lower() |
문자형 컬럼의 값들을 모두 대문자로 변환하기 | df['column_name'].str.upper() |
문자형 컬럼의 값들의 첫 글자만 대문자로, 나머지는 소문자로 변환하기 | df['column_name'].str.capitalize() |
지정한 기준에 따라 컬럼의 값을 분리하기( , 가 예시로 사용) | df['column_name'].str.split(',') |
기준에 따라 분리한 내용 중 앞부분의 내용만 가져오기 | df['column_name'].str.split(',').str[0] |
기준에 따라 분리한 내용 중 뒷부분의 내용만 가져오기 | df['column_name'].str.split(',').str[1] |
문자 앞뒤에 존재하는 불필요한 공백 제거하기 | df['column_name'].str.strip() |
불필요한 문자 제거하기(예시로 . 를 제거) | df['column_name'].str.replace('.', '', regex=False) |
숫자 데이터 가공하기
새로운 값 계산하기
데이터프레임에는 주로 숫자로 이루어진 데이터가 많이 포함되어 있는 경우가 흔합니다.
Pandas는 이러한 숫자형 데이터에 대해 사칙연산 등의 간단한 연산을 통해 새로운 컬럼을 생성하는 기능을 제공합니다.
# 두 개의 숫자형 컬럼의 비율 확인하기
df['column_a'] / df['column_b'] # 두 컬럼의 각 행의 값들이 나누어진 비율로 구성된 시리즈를 출력합니다.
# 나누기를 하면 소수점 이하 자리가 길어져서 한눈에 보기 어려울 수 있으므로 round 함수를 사용하여 반올림할 수 있습니다.
round(df['column_a'] / df['column_b'], 2) # 소수점 둘쩨자리에서 반올림합니다.
# 두 개의 숫자형 컬럼 비율 값으로 새로운 컬럼 생성하기
df['column_a_b_ratio'] = round(df['column_a'] / df['column_b'], 2)
정규화
데이터프레임을 다루는 경우에 숫자 데이터를 있는 그대로 사용하기보다는 전처리를 하고나서 이용하는 경우가 일반적인데, 이 중에 대표적인 전처리 방식에는 스케일링(scaling)이 있습니다.
스케일링은 숫자 데이터의 범위나 단위를 일정하게 맞추는 것을 말합니다.
스케일링을 하는 이유
- 모델 성능 향상: 많은 머신러닝 알고리즘은 데이터의 크기와 범위에 민감합니다. 스케일링을 통해 모델이 모든 피처를 균등하게 학습하도록 할 수 있습니다.
- 학습 속도 증가: 경사 하강법 같은 최적화 알고리즘은 데이터가 적절하게 스케일링되면 더 빠르게 수렴합니다. 스케일링을 통해 계산이 더 효율적으로 이루어집니다.
- 피처 중요도 균형: 스케일링을 통해 모든 피처가 동일한 범위에 있게 하여 특정 피처가 모델에 과도한 영향을 주지 않도록 합니다. 예를 들어, 키(cm)와 몸무게(kg)를 비교할 때 단위 차이로 인해 몸무게가 더 큰 영향을 미칠 수 있습니다.
- 수치 안정성 향상: 데이터 값이 너무 크거나 작으면 계산 과정에서 문제가 발생할 수 있습니다. 예를 들어, 매우 큰 숫자는 오버플로우를, 매우 작은 숫자는 언더플로우를 일으킬 수 있습니다. 스케일링을 통해 이러한 문제를 방지할 수 있습니다.
- 단위 차이 제거: 피처들이 서로 다른 단위를 가지는 경우, 스케일링을 통해 단위 차이를 제거할 수 있습니다. 예를 들어, 연봉(달러)와 근무 기간(년)을 함께 사용할 때, 스케일링을 통해 이들 간의 단위 차이를 없애고 비교 가능하게 만듭니다.
스케일링은 정규화와 표준화롤 나누어지며, 이번 목차에서는 정규화에 대해 설명하겠습니다.
정규화(Normalization)는 데이터를 모두 0과 1사이의 값으로 바꾸는 것을 말합니다.
정규화는 머신러닝 알고리즘에서 변수들 간의 스케일 차이로 인해 발생할 수 있는 문제를 줄여줍니다.
정규화는 보통 Min-Max 정규화 방법과 Z-Score 정규화 방법이 사용되며, 일반적으로 사용되는 방법은 Min-Max 정규화입니다.
Min-Max 정규화는 데이터의 각 값을 특정 범위(주로 0에서 1 사이)로 스케일링하는 방법으로, 데이터의 최소값과 최대값을 기준으로 값을 변환합니다.
Min-Max 정규화
Min-Max 정규화 수식
- X : 원본 데이터 값
- X_min : 데이터의 최소값
- X_max : 데이터의 최대값
- X′ : 정규화된 데이터 값
단계별 과정
- 최소값 및 최대값 계산: 각 특징(feature)의 최소값과 최대값을 계산합니다.
- 값 변환: 위의 수식을 사용하여 각 값을 변환합니다.
# 각 컬럼(예시로 A라는 컬럼을 사용)에 대해 최소값과 최대값을 계산
min_A = df['A'].min()
max_A = df['A'].max()
# Min-Max 정규화 수식 적용
df['A_normalized'] = (df['A'] - min_A) / (max_A - min_A)
정규화의 장점
- 간단한 구현: 구현이 간단하고 계산 비용이 적습니다.
- 모든 값의 범위를 동일하게 조정: 0과 1 사이로 값을 조정하여 변수 간의 스케일 차이를 없앱니다.
정규화의 단점
- 극단값에 민감: 최소값과 최대값이 극단값(outlier)에 크게 영향을 받습니다. 극단값이 있을 경우, 정규화된 값이 0과 1의 범위를 벗어날 수 있습니다.
- 새로운 데이터: 새로운 데이터가 추가되면 최소값과 최대값이 변경될 수 있어 다시 정규화해야 할 수도 있습니다.
표준화
표준화(Standardization, Standard Scaling)는 각 값이 평균에 비해 얼마나 크거나 작은지 나타내는 것입니다.
표준화는 데이터의 평균을 0, 표준편차를 1로 변환하는 과정입니다.이를 통해 데이터가 평균이 0이고 분산이 1인 표준 정규 분포를 따르도록 변환합니다.
이는 각 특징(feature)의 스케일을 맞추고 비교할 수 있도록 도와줍니다.
표준화 과정에서 사용되는 z-score는 각 데이터 포인트가 평균으로부터 얼마나 떨어져 있는지를 표준편차 단위로 나타낸 값입니다.
z-score를 계산하는 공식은 다음과 같습니다.
표준화 수식
- X : 원본 데이터 값
- μ : 데이터의 평균
- σ : 데이터의 표준편차
- X′ : 표준화된 데이터 값
단계별 과정
- 평균 계산: 각 특징의 평균을 계산합니다.
- 표준편차 계산: 각 특징의 표준편차를 계산합니다.
- 값 변환: 위의 수식을 사용하여 각 값을 변환합니다.
# 각 컬럼(예시로 A라는 컬럼을 사용)에 대해 평균과 표준편차를 계산
mean_A = df['A'].mean()
std_A = df['A'].std()
# 표준화 수식 적용
df['A_standardized'] = (df['A'] - mean_A) / std_A
표준화의 장점
- 스케일 차이 제거: 각 특징의 스케일 차이를 제거하여 모든 특징이 동일한 스케일을 갖도록 합니다.
- 모델 성능 향상: 특히 거리 기반 알고리즘(e.g., KNN, SVM)에서 모델 성능을 향상시킬 수 있습니다.
- 중심과 분산 통일: 데이터의 중심을 0으로 맞추고 분산을 통일함으로써, 데이터 분포의 특성을 유지하면서 비교 가능하게 만듭니다.
표준화의 단점
- 극단값에 덜 민감: Min-Max 정규화에 비해 극단값(outlier)에 덜 민감하지만, 여전히 극단값이 있을 경우 평균과 표준편차에 영향을 줄 수 있습니다.
- 데이터 분포 가정: 표준화는 데이터가 정규 분포를 따른다고 가정합니다. 정규 분포가 아닐 경우, 표준화가 최적의 방법이 아닐 수 있습니다.
이와 같이 표준화를 통해 각 데이터 포인트는 z-score로 변환되며, 이는 데이터 포인트가 평균으로부터 얼마나 떨어져 있는지를 표준편차 단위로 나타낸 값입니다. 표준화된 데이터를 사용하면 서로 다른 단위를 가진 데이터 세트를 동일한 기준에서 비교할 수 있어 분석이 용이해집니다.
cut()함수를 이용한 데이터 구간화
데이터 구간화(Binning)란 연속적인 숫자 데이터를 여러 개의 구간으로 분류하는 것을 의미합니다.
cut() 함수는 연속형 데이터를 구간화하는 경우에 유용하게 사용할 수 있는 함수입니다.
주로 연속형 데이터를 특정 구간으로 나누고, 각 데이터가 속한 구간을 라벨링하여 범주형 데이터로 변환하는데 사용됩니다.
cut() 함수의 주요 파라미터
- x: 구간화할 대상 데이터 (주로 Series나 1차원 배열).
- bins: 구간의 경계값들을 지정하거나 구간의 수를 지정.
- labels: 각 구간에 부여할 라벨 (생략 가능).
- right: 구간의 경계값 포함 여부 (기본값은 True로, 구간의 오른쪽 경계를 포함).
import pandas as pd
# 예시 데이터 생성
data = {'age': [15, 22, 35, 45, 55, 62, 75]}
df = pd.DataFrame(data)
# 나이 구간화: 10대, 20대, 30대, 40대, 50대, 60대 이상
bins = [10, 20, 30, 40, 50, 60, 70, 80]
labels = ['10s', '20s', '30s', '40s', '50s', '60s', '70s']
df['age_group'] = pd.cut(df['age'], bins=bins, labels=labels, right=False) # bins를 3으로 지정하는 경우 3개의 구간으로 분류합니다.
print("\n나이를 연령대로 구분한 DataFrame:\n", df)
cut() 함수 사용 시 주의사항
- 구간 경계값 지정: bins 인자는 구간 경계값들을 나타내는 리스트입니다. 이 리스트의 길이는 구간의 수보다 하나 더 많아야 합니다.
- 경계값 포함 여부: right=False로 설정하면 구간의 왼쪽 경계를 포함하고 오른쪽 경계를 포함하지 않습니다. (right=True는 기본값으로, 오른쪽 경계를 포함합니다.)
- 라벨 지정: labels 인자를 사용하여 각 구간에 부여할 라벨을 지정할 수 있습니다. labels 리스트의 길이는 bins 리스트의 길이보다 하나 적어야 합니다.
# 심화 예시
# 예시 데이터 생성
np.random.seed(0)
data = np.random.randint(1, 100, 20)
df = pd.DataFrame(data, columns=['value'])
print("원본 DataFrame:\n", df)
# 구간 경계값 자동 설정 (구간의 수 지정)
df['group_auto'] = pd.cut(df['value'], bins=5)
print("\n자동 구간 설정 (구간의 수 지정):\n", df)
# 구간 경계값 수동 설정
bins = [0, 20, 40, 60, 80, 100]
labels = ['Very Low', 'Low', 'Medium', 'High', 'Very High']
df['group_manual'] = pd.cut(df['value'], bins=bins, labels=labels)
print("\n수동 구간 설정 (라벨 지정):\n", df)
# 구간 경계값 포함 여부 설정
df['group_right_false'] = pd.cut(df['value'], bins=bins, labels=labels, right=False)
print("\n구간 경계값 포함 여부 (right=False):\n", df)
apply() 함수
apply() 기본 사용법
- DataFrame이나 Series의 값 하나하나에 함수를 적용하는 함수입니다.
- 다른 함수를 인자로 받아 해당 함수를 데이터에 적용합니다.
import pandas as pd
import numpy as np
# 예시 DataFrame 생성
df = pd.DataFrame([[1, 16], [9, 25]], columns=['column1', 'column2'])
print("원본 DataFrame:\n", df)
# apply()를 사용하여 column2의 값에 제곱근 함수 적용
df['column2'] = df['column2'].apply(np.sqrt) # 4와 5 출력
print("\n제곱근을 적용한 DataFrame:\n", df)
사용자 정의 함수와 apply() 사용
원하는 기능을 구현한 함수를 만들어 데이터에 적용할 수 있습니다.
# patient.csv 파일을 불러와 DataFrame으로 저장
patient_df = pd.read_csv('data/patient.csv')
print("환자 데이터:\n", patient_df.head())
# 연령대를 구분하는 함수 정의
def group_age(x):
if x >= 10 and x < 20:
return '10s'
elif x >= 20 and x < 30:
return '20s'
elif x >= 30 and x < 40:
return '30s'
elif x >= 40 and x < 50:
return '40s'
elif x >= 50 and x < 60:
return '50s'
else:
return '60s'
# apply()를 사용하여 age 컬럼에 연령대 함수 적용
patient_df['age_group'] = patient_df['age'].apply(group_age)
print("\n연령대를 추가한 DataFrame:\n", patient_df.head())
람다 함수와 apply()
람다 함수는 간단한 함수를 정의할 때 사용하며, 코드가 간결해지고 메모리 절약에 도움이 됩니다.
# 미터를 인치로 변환하는 람다 함수 적용
patient_df['height_in_inches'] = patient_df['height'].apply(lambda x: 39.370079 * x)
print("\n키를 인치로 변환한 DataFrame:\n", patient_df.head())
# BMI 값을 계산하여 새로운 컬럼에 저장
patient_df['bmi'] = round(patient_df['weight'] / (patient_df['height'] ** 2), 1)
print("\nBMI를 계산한 DataFrame:\n", patient_df.head())
# BMI가 30을 넘으면 'Y', 그렇지 않으면 'N'을 반환하는 람다 함수 적용
patient_df['obesity'] = patient_df['bmi'].apply(lambda x: 'Y' if x > 30 else 'N')
print("\n비만 여부를 추가한 DataFrame:\n", patient_df.head())
여러 파라미터를 가진 함수와 apply() 사용
파라미터가 여러 개인 함수를 람다 함수와 함께 사용할 수 있습니다.
# 특정 구간에 있는지 확인하는 함수 정의
def isin_interval(x, n_lower, n_upper):
if n_lower <= x < n_upper:
return 'Y'
else:
return 'N'
# 특정 BMI 구간을 확인하는 람다 함수 적용
patient_df['normal_weight'] = patient_df['bmi'].apply(lambda x: isin_interval(x, 18.5, 25))
print("\n정상 체중 여부를 추가한 DataFrame:\n", patient_df.head())
결론
- apply() 함수는 데이터 전처리와 가공에 매우 유용한 함수입니다.
- 다양한 함수와 결합하여 데이터를 원하는 형태로 자유롭게 변환할 수 있습니다.
- 람다 함수와 함께 사용하면 코드가 간결해지고, 특정 조건을 적용하는 복잡한 로직도 쉽게 구현할 수 있습니다.
이번 글에서는 문자형 데이터 가공하기 / 대소문자 처리하기 / 문자열 분리하기 / 불필요한 문자 제거하기 / 숫자 데이터 가공하기 / 새로운 값 계산하기 / 정규화 / 표준화 / cut() 함수 / apply()함수가 포함된 내용을 정리했으며, 파이썬에서 데이터 분석을 하거나 프로그래밍을 하는 사람들에게 알아두면 유용한 개념들로 이번 기회를 통해 다른 분들도 정리하면 좋을 것 같습니다.
글 읽어주셔서 감사합니다.
출처 및 참고자료 : 코드잇 사이트 강의 'DataFrame 마스터하기' https://www.codeit.kr/topics/mastering-dataframe
'프로그래밍 언어 > Python' 카테고리의 다른 글
[파이썬 개념 정리 15] Pandas의 DataFrame 마스터하기 5️⃣ (데이터 합치기) (0) | 2024.08.01 |
---|---|
[파이썬 개념 정리 14] Pandas의 DataFrame 마스터하기 4️⃣ (날짜와 시간 데이터 다루기) (0) | 2024.07.31 |
[파이썬 개념 정리 12] Pandas의 DataFrame 마스터하기 2️⃣ (데이터 전처리) (0) | 2024.07.28 |
[파이썬 개념 정리 11] Pandas의 DataFrame 마스터하기 1️⃣ (DataFrame의 기본) (0) | 2024.07.28 |
[파이썬 개념 정리 10] 객체와 클래스 개념 정리 (0) | 2024.07.18 |
데이터 분석을 공부하고 카페를 열심히 돌아다니는 이야기
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!