드디어 데이터 전처리다. 어려운데 재밌다. 엑셀 피벗테이블 만들기 위해 데이터 정제하는 것과 비슷한 작업이다. 아직 명령어가 익숙하지 않아서 머리 긁적이는 구간이 많지만 나중에 익숙해지면 훨씬 재밌어질 것 같다. 나 사실 데이터 엔지니어 체질인가...? 그나저나 여차저차 벌써 부트캠프 일주일차다. 진짜 거짓말 안 하고 일주일 동안 실력이 40배는 성장한 듯. 내일은 시각화랑 상관관계 도출 실습이다! 아자아자 화이팅!!
이상치, 정규화는 공식이 있는데 반드시 외워야 할 것 같다. 이해도 어렵고 기억도 잘 안 난다. 이럴 줄 알았으면 어릴 때 수학공부 좀 열심히 해둘 걸 그랬다.
학습시간 09:00~01:00(당일16H/누적102H)
데이터 정제하면서 조건을 거는 경우가 종종 있다. 역시나 아직 변수 조건식이 익숙하다. 나중에 더 어려운 파일을 다루다 보면 쿼리 조건식을 반드시 사용해야할 것 같다. 미리 익숙해져야지.
''' 조건 정의 '''
condition1 = df['A'] == 'Yes' # A열 Yes
condition2 = df['B'] > df['B'].mean() # B열 평균 이상
condition3 = df['C'] == 10 # C열 10
''' 조건식 '''
# 변수 앞에 '~'를 붙이면 not과 같은 의미
# not and or 순서로 연산
# 1 만족 or (2 만족 and 3 불만족)
df[condition1 | (condition2 & ~condition3)]
''' 쿼리함수 예시 '''
df.query('A > 10000')
''' 함수 만들어서 사용 시 @를 붙임 '''
df.query('A > @A_mean')
''' 쿼리 조건식 '''
df.query('A not in ["a1", "a2"]')
드디어 알았다! 데이터 전처리는 pandas를 사용한다. 가끔 numpy 함수가 필요할 때가 있는 것 같다. 그리고 전처리가 끝나면 상관관계를 분석하기 위해 matplotlib 혹은 seaborn을 활용한다.
시작은 언제나 같다. 라이브러리와 데이터를 불러와서 확인한다.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_csv('folder/file.csv')
df.info() # 데이터 요약
df.dtypes # 타입 확인
df.describe() # 수치 통계
df.shape # 행열 크기 확인
# A열 타입 변경
df['A'] = df['A'].astype('float')
# A열 기준 내림차순 정렬
df.sort_values(by='A', ascending=False)
# A열을 인덱스로 설정
df.set_index('A', inplace=True)
# 열 이름 전체 확인 후 변경
df.columns
df.columns = [' ', ' ', ' ', ' ']
# 열 이름 개별 변경
dict = {'loan_id' : 'id'}
df.rename(columns=dict, inplace=True)
결측값을 반드시 채워야하는 것인지 잘 모르겠다. 일단 알아두자.
''' 1. 확인 '''
df.isnull().sum() # 결측값 확인
df[df.isnull().any(axis=1)] # 결측값 도표화
df[df['A'].isnull()] # A열 결측값 행 보기
df['A'].value_counts(dropna=False) # A열 값 확인
''' 2. 삭제 '''
df.drop(rows=['A', 'B']) # 행 삭제
df.drop(columns=['A', 'B']) # 열삭제
df.dropna(axis=1) # 결측치가 있는 열 삭제
df.dropna(axis=0) # 결측치가 있는 행 삭제
df.dropna(subset=['A']) # A열에 결측치 있는 행 삭제
''' 3. 입력 '''
df['A'].fillna(df.mean()) # 결측값에 평균값 입력
df['A'].fillna(df.median()) # 결측값에 중앙값 입력
df['A'].fillna(df.mode()) # 결측값에 최빈값 입력
중복값은 대부분 삭제한다고 하던데, 만약 df.duplicated().sum()를 이용한 중복값이 데이터의 절반이면 어쩌지? 아직 조금 더 확인할 필요가 있을 것 같다.
''' 1. 확인 '''
df.duplicated().sum() # 중복값 확인
df[df.duplicated(keep=False)] # 중복값 도표화
df[df.duplicated(subset=['A'], keep=False)] # A열 중복값 행 보기
.sort_values(by=['A']) # A열 기준 정렬
''' 2. 삭제 '''
df.drop_duplicates(inplace=True) # 모든 중복값 삭제
df.drop_duplicates(subset=['A']) # A열에서 중복이면 삭제
df.drop(['A', 'B'], inplace=True) # 일반 삭제
가장 어려운 부분이다. 데이터의 모든 열을 다 처리해줘야 하는 건지, 내가 원하는 열만 해도 괜찮은 건지는 잘 모르겠다.
''' 수치 정제 '''
q1 = airbnb_df['A'].quantile(0.25) # 1사분위수 설정
q3 = airbnb_df['A'].quantile(0.75) # 3사분위수 설정
iqr = q3 - q1 # 이상치 범위 설정
lower_limit = q1 - 1.5 * iqr # 이상치 하한선 설정
upper_limit = q3 + 1.5 * iqr # 이상치 상한선 설정
# A열 정상치만 남기는 수식
df[(df['A'] <= upper_limit) & (df['A'] >= lower_limit)]
# A열 이상치만 남기는 수식
df[(df['A'] > upper_limit) | (df['A'] < lower_limit)]
''' 문자열 정제 '''
df['A'].unique() # A열 중복이 아닌 값 출력
df['A'].str.lower() # A열 소문자로 변환
df['A'].str.upper() # A열 대문자로 변환
df['A'].str.capitalize() # 첫 글자 대문자로 변환
df['A'].str.split(',').str[0] # A열 ','로 분리 후 0번 값 선택
df['A'].str.strip() # 양측 공백 제거
df['A'].str.lstrip() # 좌측 공백 제거
df['A'].str.rstrip() # 우측 공백 제거
df['A'].str.replace('a', 'b', regex=False) # 문자 a를 b로 변경
''' 시간 정제 '''
# datetime 타입으로 변환
df['A'] = pd.to_datetime(df['A'])
df['A'].dt.year # 년도 추출
df['A'].dt.month # 월 추출
df['A'].dt.day # 일 추출
df['A'].dt.hour # 시간 추출
df['A'].dt.minute # 분 추출
df['A'].dt.second # 초 추출
df['A'].dt.dayofweek # 요일 추출
# 포맷 변경(표현식 외우기)
df['A'] = df['A'].dt.strftime('%Y-%m-%d-%H-%M-%S')
시각화를 위해 반드시 필요한 작업인 것 같다. 공식이 이해가 잘 안 된다 ㅠㅠ
''' 정규화(0~1) 공식 '''
# (기존값 - 최소값) / (최대값 - 최소값)
df['A'] = (df['A'] - df['A'].min()) / (df['A'].max() - df['A'].min())
''' 표준화(-1~1) 공식 '''
# (기존값 - 평균) / 표준편차
df['A'] = (df['A'] - df['A'].mean()) / df['A'].std()
''' 응용 '''
df['B'] = pd.cut(df['A'], bins=[1,2,3,4,5], labels=['a1', 'a2', 'a3', 'a4'])
''' 함수로 문자열 구분도 가능 '''
def age_group(x):
if (x >= 10) & (x < 20):
return '10s'
elif (x >= 20) & (x < 30):
return '20s'
elif (x >= 30) & (x < 40):
return '30s'
elif (x >= 40) & (x < 50):
return '40s'
elif (x >= 50) & (x < 60):
return '50s'
else:
return '60s'
df['age_group'] = df['age'].apply(age_group)