<머신러닝 • 딥러닝 문제해결 전략> 6장의 내용을 실습했습니다.
데이터 둘러보기
dataframe 형태로 훈련, 테스트, 제출 샘플 데이터를 불러옵니다.
import numpy as np
import pandas as pd # 판다스 임포트
# 데이터 경로
data_path = '/kaggle/input/bike-sharing-demand/'
train = pd.read_csv(data_path + 'train.csv') # 훈련 데이터
test = pd.read_csv(data_path + 'test.csv') # 테스트 데이터
submission = pd.read_csv(data_path + 'sampleSubmission.csv') # 제출 샘플 데이터
train.shape, test.shape
훈련데이터가 10,886행 12열로, 테스트 데이터가 6493행 9열로 구성되어 있음을 확인했습니다.
열의 개수 = 피처 개수인데, 두 데이터의 피처 개수가 서로 다르니 각각 어떤 피처 데이터를 담고 있는지 확인해보도록 하겠습니다.
train.head()
test.head()
테스트 데이터는 훈련 데이터 피처에서 casual과 registered가 빠졌습니다.
submission.head()
train.info()
test.info()
더 효과적인 분석을 위한 피처 엔지니어링
datetime 피처가 시각화하기에 적합하지 않은 형태임으로 시각화하기 전에 분석하기 적합한 형태로 변환(피처 엔지니어링) 해보았습니다. datetime은 연도, 월, 일, 시간, 분, 초로 구성되어 있습니다. 따라서 세부적으로 분석하기 위해 split()을 사용해 구성요소별로 나누어 보았습니다.
print(train['datetime'][100]) #datetime 100번째 원소
print(train['datetime'][100].split()) #공백기준으로 문자열 나누기
print(train['datetime'][100].split()[0]) # 날짜
print(train['datetime'][100].split()[1]) # 시간
datetime 피처는 object 타입이기 때문에 문자열처럼 다룰 수 있습니다. split()함수를 사용해 공백 기준으로 앞 뒤 문자를 나누었습니다. 첫번째 문자열 '2011-01-05'는 날짜 문자열, 두번째 문자열 '09:00:00'은 시간 문자열입니다.
" - " 문자를 기준으로 나누어 연도, 월, 일을 구분했습니다
print(train['datetime'][100].split()[0]) # 날짜
print(train['datetime'][100].split()[0].split("-")) # "-"기준으로 문자열 나누기
print(train['datetime'][100].split()[0].split("-")[0]) # 연도
print(train['datetime'][100].split()[0].split("-")[1]) # 월
print(train['datetime'][100].split()[0].split("-")[2]) # 일
" : " 문자를 기준으로 시간문자열을 시, 분, 초로 나누어 보았습니다.
print(train['datetime'][100].split()[1]) # 시간
print(train['datetime'][100].split()[1].split(":")) # ":"기준으로 문자열 나누기
print(train['datetime'][100].split()[1].split(":")[0]) # 시간
print(train['datetime'][100].split()[1].split(":")[1]) # 분
print(train['datetime'][100].split()[1].split(":")[2]) # 초
train['date'] = train['datetime'].apply(lambda x: x.split()[0]) # 날짜 피처 생성
# 연도, 월, 일, 시, 분, 초 피처를 차례로 생성
train['year'] = train['datetime'].apply(lambda x: x.split()[0].split('-')[0])
train['month'] = train['datetime'].apply(lambda x: x.split()[0].split('-')[1])
train['day'] = train['datetime'].apply(lambda x: x.split()[0].split('-')[2])
train['hour'] = train['datetime'].apply(lambda x: x.split()[1].split(':')[0])
train['minute'] = train['datetime'].apply(lambda x: x.split()[1].split(':')[1])
train['second'] = train['datetime'].apply(lambda x: x.split()[1].split(':')[2])
calendar, datetime '라이브러리'를 활용해 요일 피처를 생성해보았습니다. (datetime 라이브러리는 datetime 피처와 다른 것임)
# 요일 피처 생성
from datetime import datetime # datetime 라이브러리 임포트
import calendar
print(train['date'][100]) # 날짜
print(datetime.strptime(train['date'][100], '%Y-%m-%d')) #datetime 타입으로 변경
#정수로 요일 반환
print(datetime.strptime(train['date'][100], '%Y-%m-%d').weekday())
#문자열로 요일 반환
print(calendar.day_name[datetime.strptime(train['date'][100], '%Y-%m-%d').weekday()])
calendar와 datetime 라이브러리를 이용하면 요일피처를 문자로 구할 수 있습니다. 0은 월요일, 1은 화요일, 2는 수요일 순으로 매핑됩니다.
train['weekday'] = train['date'].apply(
lambda dateString:
calendar.day_name[datetime.strptime(dateString, "%Y-%m-%d").weekday()])
apply()를 적용해 요일(weekday) 피처를 추가했습니다.
train['season'] = train['season'].map({1: 'Spring',
2: 'Summer',
3: 'Fall',
4: 'Winter'})
train['weather'] = train['weather'].map({1: 'Clear',
2: 'Mist, Few clouds',
3: 'Light Snow, Rain, Thunderstorm',
4: 'Heavy Rain, Thunderstorm, Snow, Fog'})
seoson 과 weather 피처를 시각화 시 의미가 잘 드러나도록 map()함수를 사용하여 문자열로 바꾸었습니다.
train.head()
date, year, month, day, hour, minute, second, weekday 피처가 추가되었고 season과 weather 피처는 숫자에서 문자로 형태가 바뀌었습니다.
데이터 시각화
%matplotlib inline을 추가하면 주피터 노트북에서 바로 출력해준다고 합니다.
import seaborn as sns # seaborn : matplotlib에 고수준 인터페이스를 덧씌운 라이브러리
import matplotlib as mpl # matplotlib : 파이썬으로 데이터 시각화할 때 표준처럼 사용되는 라이브러리
import matplotlib.pyplot as plt
%matplotlib inline
분포도
타깃값의 분포를 알면 훈련시 타깃값을 그대로 사용할지 변환해 사용할지 파악할 수 있기 때문에 분포도를 그려보았습니다.
mpl.rc('font', size=15) # 폰트 크기를 15로 설정
sns.displot(train['count']); # 분포도 출력
sns.displot(np.log(train['count']));
데이터 분포를 정규분포에 가깝게 하기 위해 count를 로그 변환한 값의 분포도입니다.
막대그래프
seaborn의 barplot() 함수를 사용해 막대그래프를 그릴수 있습니다.
막대그래프를 그리는 step1: 3행 2열 Figure 준비합니다.
mpl.rc('font', size=14) # 폰트 크기 설정
mpl.rc('axes', titlesize=15) # 각 축의 제목 크기 설정
figure, axes = plt.subplots(nrows=3, ncols=2) # 3행 2열 Figure 생성
plt.tight_layout() # 그래프 사이에 여백 확보
figure.set_size_inches(10, 9) # 전체 Figure 크기를 10*9인치로 설정
axes에 어떤 객체가 할당되어 있는지 출력해보았습니다.
axes
스텝2 : 각 축에 서브플롯을 할당하기
# 스텝2 : 각 축에 서브 플롯 할당
# 각 축에 연도, 월, 일, 시간, 분, 초별 평균 대여 수량 막대 그래프 할당
sns.barplot(x='year', y='count', data=train, ax=axes[0, 0])
sns.barplot(x='month', y='count', data=train, ax=axes[0, 1])
sns.barplot(x='day', y='count', data=train, ax=axes[1, 0])
sns.barplot(x='hour', y='count', data=train, ax=axes[1, 1])
sns.barplot(x='minute', y='count', data=train, ax=axes[2, 0])
sns.barplot(x='second', y='count', data=train, ax=axes[2, 1])
스텝3 : (선택) 세부 설정
# 스텝3 : 세부 설정
# 3-1 : 서브플롯에 제목 달기
axes[0, 0].set(title='Rental amounts by year')
axes[0, 1].set(title='Rental amounts by month')
axes[1, 0].set(title='Rental amounts by day')
axes[1, 1].set(title='Rental amounts by hour')
axes[2, 0].set(title='Rental amounts by minute')
axes[2, 1].set(title='Rental amounts by second')
# 3-2 : 1행에 위치한 서브플롯들의 x축 라벨 90도 회전
axes[1, 0].tick_params(axis='x', labelrotation=90)
axes[1, 1].tick_params(axis='x', labelrotation=90)
박스플롯
# 스텝1 : m행 n열 Figure 준비
figure, axes = plt.subplots(nrows=2, ncols=2) # 2행 2열
plt.tight_layout()
figure.set_size_inches(10, 10)
# 스텝2 : 서브플롯 할당
# 계절, 날씨, 공휴일, 근무일별 대여 수량 박스 플롯
sns.boxplot(x='season', y='count', data=train, ax=axes[0, 0])
sns.boxplot(x='weather', y='count', data=train, ax=axes[0, 1])
sns.boxplot(x='holiday', y='count', data=train, ax=axes[1, 0])
sns.boxplot(x='workingday', y='count', data=train, ax=axes[1, 1])
# 스텝3 : 세부 설정
# 3-1 : 서브플롯에 제목 달기
axes[0, 0].set(title='Box Plot On Count Across Season')
axes[0, 1].set(title='Box Plot On Count Across Weather')
axes[1, 0].set(title='Box Plot On Count Across Holiday')
axes[1, 1].set(title='Box Plot On Count Across Working Day')
# 3-2 : x축 라벨 겹침 해결
axes[0, 1].tick_params(axis='x', labelrotation=10) # 10도 회전
포인트플롯
# 스텝 1 : m행 n열 Figure 준비
mpl.rc('font', size=11)
figure, axes = plt.subplots(nrows=5) # 5행 1열
figure.set_size_inches(12, 18)
# 스텝2 : 서브플롯 할당
# 근무일, 공휴일, 요일, 계절, 날씨에 따른 시간대별 평균 대여 수량 포인트 플롯
sns.pointplot(x='hour', y='count', data=train, hue='workingday', ax=axes[0])
sns.pointplot(x='hour', y='count', data=train, hue='holiday', ax=axes[1])
sns.pointplot(x='hour', y='count', data=train, hue='weekday', ax=axes[2])
sns.pointplot(x='hour', y='count', data=train, hue='season', ax=axes[3])
sns.pointplot(x='hour', y='count', data=train, hue='weather', ax=axes[4])
회귀선을 포함한 산점도 그래프
회귀선을 포함한 산점도 그래프는 수치형 데이터 간 상관관계를 파악하는데 용이하다고 합니다. 이 그래프는 seaborn의 regplot()함수로 그릴 수 있습니다. regplot()함수의 파라미터 중 scatter_kws={'alpha' : 0.2}는 산점도 그래프에 찍히는 점의 투명도를 조절합니다. 1이면 불투명, 0이면 완전 투명해 보이지 않는다고 합니다.
# 스텝1 : m행 n열 Figure 준비
mpl.rc('font', size=15)
figure, axes = plt.subplots(nrows=2, ncols=2) # 2행 2열
plt.tight_layout()
figure.set_size_inches(7, 6)
# 스텝2 : 서브플롯 할당
# 온도, 체감 온도, 풍속, 습도 별 수량 산점도 그래프
sns.regplot(x='temp', y='count', data=train, ax=axes[0, 0],
scatter_kws={'alpha' : 0.2}, line_kws={'color': 'blue'})
sns.regplot(x='atemp', y='count', data=train, ax=axes[0, 1],
scatter_kws={'alpha' : 0.2}, line_kws={'color': 'blue'})
sns.regplot(x='windspeed', y='count', data=train, ax=axes[1, 0],
scatter_kws={'alpha' : 0.2}, line_kws={'color': 'blue'})
sns.regplot(x='humidity', y='count', data=train, ax=axes[1, 1],
scatter_kws={'alpha' : 0.2}, line_kws={'color': 'blue'})
히트맵
데이터 간 관계를 색상으로 표현한 그래프인 히트맵을 이용하여 수치형 데이터끼리 어떤 상관 관계가 있는지 알아보겠습니다. 히트맵은 이처럼 비교할 데이터가 많을 때 주로 사용되며, heatmap() 함수를 사용합니다.
train[['temp', 'atemp', 'humidity', 'windspeed', 'count']].corr()
# 피처 간 상관관계 매트릭스
corrMat = train[['temp', 'atemp', 'humidity', 'windspeed', 'count']].corr()
fig, ax = plt.subplots()
fig.set_size_inches(10, 10)
sns.heatmap(corrMat, annot=True) # 상관관계 히트맵 그리기
ax.set(title='Heatmap of Numerical Data')
'Data > MLDL' 카테고리의 다른 글
범주형 경진대회 이진분류 (0) | 2022.10.31 |
---|---|
자전거 대여 수요 예측(2) (0) | 2022.09.26 |
하이퍼파라미터 최적화 (0) | 2022.09.19 |
주요 머신러닝 모델 (0) | 2022.09.19 |
교차검증 (0) | 2022.09.19 |