결정트리를 이용해서 서울 자전거 공유 수요 예측해보기

1. 실습 주제

이 실습은 서울시 공공자전거 대여 수요를 예측하는 회귀 문제를 다룬다.
목표는 여러 환경 변수와 시간 정보를 바탕으로 특정 시점의 자전거 대여 수(Rented Bike Count)를 예측하는 것이다.

예측에 사용되는 대표 변수는 다음과 같다.

  • 날짜
  • 시간
  • 기온
  • 습도
  • 풍속
  • 가시거리
  • 이슬점 온도
  • 일사량
  • 강수량
  • 적설량
  • 계절
  • 공휴일 여부
  • 운영 여부

전체 흐름은 다음과 같다.

데이터 로드
↓
데이터 구조 확인
↓
EDA
↓
날짜형 변환 및 파생 변수 생성
↓
범주형 처리
↓
상관관계 및 다중공선성 점검
↓
회귀 모델 학습
↓
성능 비교
↓
중요 변수 해석

2. 데이터셋 컬럼 정리

이 데이터셋의 주요 컬럼은 다음과 같다.

컬럼명 의미
Date 날짜
Rented Bike Count 시간당 대여된 자전거 수
Hour 시간
Temperature 기온
Humidity 습도
Wind speed 풍속
Visibility 가시거리
Dew point temperature 이슬점 온도
Solar Radiation 태양 복사량
Rainfall 강우량
Snowfall 적설량
Seasons 계절
Holiday 공휴일 여부
Functioning Day 운영일 여부

이 실습의 목표 변수는 다음 하나이다.

Rented Bike Count

즉, 나머지 변수들을 독립변수로 사용하여 Rented Bike Count를 예측한다.


3. pd.read_csv()

개요

pd.read_csv()는 CSV 파일을 읽어 Pandas DataFrame으로 변환하는 함수이다.
이 실습에서는 서울 자전거 대여 데이터를 불러오는 시작점으로 사용된다.

한글이 포함된 CSV 파일은 인코딩 문제가 발생할 수 있기 때문에 encoding='CP949'를 함께 지정한다.
CP949는 Windows 환경에서 자주 쓰이는 한국어 인코딩 방식이므로, 한글 컬럼이나 데이터가 깨지지 않도록 할 때 적절하다.


실습 코드

bike_df = pd.read_csv("SeoulBikeData.csv", encoding="CP949")
bike_df

# 결과
# CSV 데이터가 DataFrame 형태로 로드된다.

주요 파라미터

파라미터 설명
filepath_or_buffer 읽을 CSV 파일 경로
encoding 문자 인코딩 방식
sep 구분자
header 컬럼명 행 지정

반환값

pandas.DataFrame

ai가 추천하는 심화 예제

df = pd.read_csv("SeoulBikeData.csv", encoding="CP949")

print(df.shape)

# 결과
# (행 개수, 열 개수)

4. DataFrame.info()

개요

info()는 데이터프레임의 전체 구조를 요약해서 보여주는 메서드이다.

확인할 수 있는 대표 정보는 다음과 같다.

  • 컬럼 개수
  • 각 컬럼의 non-null 개수
  • 데이터 타입
  • 메모리 사용량

전처리를 시작하기 전에 데이터 상태를 빠르게 점검할 때 가장 먼저 사용하는 메서드 중 하나이다.


실습 코드

bike_df.info()

# 결과
# 컬럼 수, non-null 개수, dtype, 메모리 사용량 등이 출력된다.

주요 역할

  • 결측치 존재 여부 확인
  • 숫자형 / 문자열형 컬럼 구분
  • 날짜형 변환 전후 비교
  • 전처리 방향 결정

반환값

None

info()는 값을 반환하기보다 정보를 출력하는 용도로 사용된다.


ai가 추천하는 심화 예제

print(bike_df.dtypes)

# 결과
# 각 컬럼의 자료형 출력

5. DataFrame.describe()

개요

describe()는 수치형 컬럼에 대한 기초 통계량 요약을 반환하는 메서드이다.

기본적으로 다음 정보를 제공한다.

  • count
  • mean
  • std
  • min
  • 25%
  • 50%
  • 75%
  • max

수치형 변수의 분포를 빠르게 파악하고, 값의 범위나 이상치 가능성을 점검할 때 유용하다.


실습 코드

bike_df.describe()

# 결과
# count, mean, std, min, 25%, 50%, 75%, max 출력

주요 역할

  • 수치형 컬럼의 평균과 분산 확인
  • 각 변수의 범위 확인
  • 이상치 후보 탐색
  • 모델 입력 전 데이터 감 잡기

반환값

pandas.DataFrame

ai가 추천하는 심화 예제

print(bike_df["Rented Bike Count"].describe())

# 결과
# 대여 수 컬럼의 통계량만 출력

6. DataFrame.columns

개요

columns는 데이터프레임의 컬럼명 목록을 조회하거나 변경할 때 사용하는 속성이다.

원본 데이터의 컬럼명이 길거나 공백, 대소문자, 표기 일관성 문제가 있을 때 분석하기 쉬운 형태로 다시 정리할 수 있다.


실습 코드

bike_df.columns

# 결과
# 현재 컬럼명 목록 출력

컬럼명 변경:

bike_df.columns = [
    'Date', 'Rented Bike Count', 'Hour', 'Temperature', 'Humidity',
    'Wind speed', 'Visibility', 'Dew point temperature',
    'Solar Radiation', 'Rainfall', 'Snowfall', 'Seasons',
    'Holiday', 'Functioning Day'
]

주요 역할

  • 현재 컬럼명 확인
  • 컬럼명 표준화
  • 이후 코드 가독성 향상

반환값

pandas.Index

ai가 추천하는 심화 예제

print(list(bike_df.columns))

# 결과
# 컬럼명을 리스트 형태로 출력

7. DataFrame.head()

개요

head()는 데이터프레임의 상위 N개 행을 반환하는 메서드이다.

파일을 읽은 직후 데이터가 정상적으로 들어왔는지 확인하거나, 전처리 후 결과를 즉시 점검할 때 자주 사용한다.


실습 코드

bike_df.head()

# 결과
# 상위 5개 행 출력

주요 역할

  • 데이터 로드 상태 확인
  • 컬럼명 변경 확인
  • 파생 변수 생성 결과 확인
  • 전처리 중간 점검

파라미터

파라미터 설명
n 출력할 행 수, 기본값 5

반환값

pandas.DataFrame

ai가 추천하는 심화 예제

print(bike_df.head(10))

# 결과
# 상위 10개 행 출력

8. sns.scatterplot()

개요

scatterplot()은 두 변수 간 관계를 점 형태로 시각화하는 함수이다.
회귀 문제에서는 입력 변수와 목표 변수 사이에 어떤 관계가 있는지 탐색할 때 매우 유용하다.

이 실습에서는 여러 기상 변수와 시간 변수가 Rented Bike Count와 어떤 패턴을 가지는지 확인한다.


실습 코드

sns.scatterplot(x='Temperature', y='Rented Bike Count', data=bike_df, alpha=0.3)
sns.scatterplot(x='Wind speed', y='Rented Bike Count', data=bike_df, alpha=0.3)
sns.scatterplot(x='Visibility', y='Rented Bike Count', data=bike_df, alpha=0.3)
sns.scatterplot(x='Hour', y='Rented Bike Count', data=bike_df, alpha=0.3)

# 결과
# 각 변수와 대여 수의 관계가 산점도로 표시된다.

주요 역할

  • 선형성 여부 확인
  • 비선형 패턴 탐색
  • 특정 구간 데이터 밀집 여부 확인
  • 이상치 후보 탐색

주요 파라미터

파라미터 설명
x x축 변수
y y축 변수
data 사용할 DataFrame
alpha 점 투명도

반환값

matplotlib.axes.Axes

ai가 추천하는 심화 예제

sns.scatterplot(x='Humidity', y='Rented Bike Count', data=bike_df, alpha=0.2)

# 결과
# 습도와 대여 수 관계 시각화

9. isna()sum()

개요

isna()는 각 값이 결측치인지 아닌지를 True/False로 반환하고,
그 뒤 sum()을 적용하면 컬럼별 결측치 개수를 계산할 수 있다.

실무에서 결측치는 모델 성능과 전처리 전략에 직접 영향을 주기 때문에 반드시 먼저 확인해야 한다.


실습 코드

bike_df.isna().sum()

# 결과
# 각 컬럼별 결측치 개수 출력

주요 역할

  • 결측치 존재 여부 확인
  • 결측치 처리 필요성 판단
  • 데이터 품질 점검

반환값

pandas.Series

ai가 추천하는 심화 예제

print(bike_df.isna().mean())

# 결과
# 각 컬럼별 결측치 비율 출력

10. pd.to_datetime()

개요

pd.to_datetime()는 문자열 형태의 날짜 데이터를 datetime 타입으로 변환하는 함수이다.

날짜를 문자열 상태로 두면 연, 월, 일, 요일 같은 구성 요소를 직접 꺼내기 어렵다.
따라서 날짜 기반 feature engineering을 하려면 먼저 datetime 타입으로 변환해야 한다.


실습 코드

bike_df['Date'] = pd.to_datetime(bike_df['Date'], format='%d/%m/%Y')
bike_df['Date']

# 결과
# Date 컬럼이 datetime 타입으로 변환된다.

주요 역할

  • 문자열 날짜를 날짜형 데이터로 변환
  • .dt.year, .dt.month, .dt.day 사용 가능
  • 시계열 관련 파생 변수 생성 가능

주요 파라미터

파라미터 설명
arg 변환 대상
format 날짜 형식 지정
errors 변환 실패 처리 방식

반환값

pandas.Series 또는 datetime 객체

ai가 추천하는 심화 예제

bike_df["weekday"] = bike_df["Date"].dt.dayofweek

print(bike_df[["Date", "weekday"]].head())

# 결과
# 요일 숫자 컬럼 추가

11. .dt.year, .dt.month, .dt.day

개요

.dt는 datetime 타입 Series에서 날짜 구성 요소를 추출하는 접근자이다.

날짜 자체를 그대로 모델에 넣기보다는, 연/월/일 같은 수치형 파생 변수를 만들어 모델이 패턴을 학습하기 쉽게 만드는 경우가 많다.


실습 코드

bike_df['year'] = bike_df['Date'].dt.year
bike_df['month'] = bike_df['Date'].dt.month
bike_df['day'] = bike_df['Date'].dt.day
bike_df.head()

# 결과
# year, month, day 컬럼이 새롭게 생성된다.

주요 역할

  • 날짜 정보를 수치형 변수로 분해
  • 월별, 일별 패턴 반영
  • 계절성, 시계열 특징 반영

반환값

pandas.Series

ai가 추천하는 심화 예제

bike_df["day_name"] = bike_df["Date"].dt.day_name()

print(bike_df[["Date", "day_name"]].head())

# 결과
# 날짜와 요일 이름 출력

12. plt.figure(), sns.lineplot(), plt.xticks(), plt.show()

개요

이 조합은 시계열 흐름이나 연속적인 변화를 선 그래프로 시각화할 때 사용된다.

이 실습에서는 날짜에 따른 자전거 대여량 변화를 확인하여, 특정 시기에 수요가 증가하거나 감소하는 흐름이 있는지 탐색한다.


실습 코드

plt.figure(figsize=(14, 4))
sns.lineplot(x='Date', y='Rented Bike Count', data=bike_df)
plt.xticks(rotation=45)
plt.show()

# 결과
# 날짜에 따른 대여 수 변화가 선 그래프로 출력된다.

개별 역할

plt.figure(figsize=(14, 4))

그래프 전체 크기를 설정한다.

sns.lineplot(...)

연속형 데이터의 추세를 선 그래프로 시각화한다.

plt.xticks(rotation=45)

x축 레이블을 회전시켜 날짜가 겹치지 않게 만든다.

plt.show()

현재까지 설정한 그래프를 실제로 출력한다.


ai가 추천하는 심화 예제

plt.figure(figsize=(12, 4))
sns.lineplot(x='month', y='Rented Bike Count', data=bike_df)
plt.show()

# 결과
# 월 기준 대여 수 패턴 확인

13. 불리언 인덱싱 + groupby() + mean()

개요

실습에서는 특정 연도 데이터만 선택한 뒤, 월별 평균 대여량을 계산하기 위해
조건 필터링 + 그룹 연산 + 평균 집계를 함께 사용한다.

이 방식은 범주별 평균 패턴을 확인할 때 매우 자주 쓰인다.


실습 코드

bike_df[bike_df['year'] == 2017].groupby('month')['Rented Bike Count'].mean()
bike_df[bike_df['year'] == 2018].groupby('month')['Rented Bike Count'].mean()

# 결과
# 연도별 월 평균 대여 수가 Series로 출력된다.

개별 동작

불리언 인덱싱

bike_df[bike_df['year'] == 2017]

조건을 만족하는 행만 선택한다.

groupby('month')

선택된 데이터를 월 기준으로 그룹화한다.

['Rented Bike Count']

그룹화 후 관심 있는 컬럼만 선택한다.

mean()

각 그룹의 평균값을 계산한다.


주요 역할

  • 특정 연도 데이터만 선택
  • 월 기준 집계
  • 월별 평균 수요 파악

반환값

pandas.Series

ai가 추천하는 심화 예제

monthly_mean = bike_df.groupby(['year', 'month'])['Rented Bike Count'].mean()

print(monthly_mean.head())

# 결과
# 연도-월 기준 평균 대여 수 출력

14. pd.cut()

개요

pd.cut()은 연속형 데이터를 구간(bin)으로 나누어 범주형 변수로 변환하는 함수이다.

숫자 데이터가 그대로 존재할 때보다, 의미 있는 구간으로 묶어주면 패턴을 더 해석하기 쉬운 경우가 많다.
특히 시간처럼 연속적인 숫자를 새벽, 아침, 오후, 저녁처럼 바꾸면 사람이 이해하기도 쉽고, 모델에도 유용한 범주형 feature가 된다.

pd.cut()은 기본적으로 오른쪽 경계를 포함하는 방식으로 동작한다.


실습 코드

bike_df['TimeOfDay'] = pd.cut(
    bike_df['Hour'],
    bins=[0, 5, 11, 17, 23],
    labels=['Dawn', 'Morning', 'Afternoon', 'Evening'],
    include_lowest=True
)

# 결과
# Hour 값이 시간대 범주로 변환된다.

구간 의미

  • 0 ≤ Hour ≤ 5Dawn
  • 5 < Hour ≤ 11Morning
  • 11 < Hour ≤ 17Afternoon
  • 17 < Hour ≤ 23Evening

주요 역할

  • 시간 정보를 해석 가능한 범주로 변환
  • 시간대별 수요 패턴 반영
  • 범주형 feature 생성

주요 파라미터

파라미터 설명
x 구간화할 데이터
bins 구간 경계값
labels 각 구간 이름
include_lowest 최솟값 포함 여부

반환값

pandas.Series (category)

ai가 추천하는 심화 예제

bike_df["TempLevel"] = pd.cut(
    bike_df["Temperature"],
    bins=[-20, 0, 10, 20, 30, 40],
    labels=["Very Cold", "Cold", "Mild", "Warm", "Hot"]
)

print(bike_df[["Temperature", "TempLevel"]].head())

# 결과
# 기온이 구간별 범주로 변환된다.

15. sns.barplot()

개요

barplot()은 범주형 변수별 수치형 값의 대표 통계량을 막대로 시각화하는 함수이다.

기본적으로는 각 범주별 평균(mean) 을 계산해 막대 높이로 표현한다.
즉, 개별 데이터 하나하나를 보여주는 것이 아니라, 집단의 평균적 특성을 비교하는 그래프라고 이해하면 된다.

실질적으로는 내부에서 groupby()와 집계를 수행한 뒤 결과를 그리는 것과 유사하다.


실습 코드

sns.barplot(x='Functioning Day', y='Rented Bike Count', data=bike_df)

# 결과
# 운영일 여부에 따른 평균 대여 수가 막대그래프로 표시된다.

그래프 해석 방법

  • x축은 비교 대상 범주
  • y축은 수치형 값
  • 막대 높이는 기본적으로 평균
  • 막대 높이 차이는 집단 간 평균 차이를 의미

estimator 옵션을 통해 평균 대신 합계, 중앙값 같은 다른 집계 방식도 사용할 수 있다.


주요 역할

  • 범주별 평균 비교
  • 운영일 여부가 수요에 미치는 영향 확인
  • 계절별, 휴일별 평균 비교 가능

반환값

matplotlib.axes.Axes

ai가 추천하는 심화 예제

sns.barplot(x='Seasons', y='Rented Bike Count', data=bike_df)

# 결과
# 계절별 평균 대여 수 비교

16. value_counts()

개요

value_counts()는 범주형 데이터에서 각 값이 몇 번 등장했는지 계산하는 메서드이다.

범주 분포를 파악할 때 가장 먼저 확인하는 메서드이며, 클래스 불균형이나 특정 값의 편중 여부를 빠르게 확인할 수 있다.


실습 코드

bike_df['Functioning Day'].value_counts()

# 결과
# Yes, No의 개수 출력

주요 역할

  • 범주 분포 확인
  • 운영일 / 비운영일 비율 확인
  • 데이터 불균형 여부 파악

반환값

pandas.Series

ai가 추천하는 심화 예제

print(bike_df["Seasons"].value_counts(normalize=True))

# 결과
# 계절별 비율 출력

17. 조건 필터링

개요

실습에서는 특정 조건에 맞는 데이터만 선택해서 따로 확인하는 방식도 사용한다.

Pandas에서 조건 필터링은 매우 기본적인 데이터 선택 방식이며, 특정 집단만 분석하거나 비교할 때 필수적이다.


실습 코드

bike_df[bike_df['Functioning Day'] == 'Yes']
bike_df[bike_df['Functioning Day'] == 'No']

# 결과
# 운영일 / 비운영일 데이터만 각각 추출된다.

주요 역할

  • 특정 범주 데이터만 분리
  • 범주별 상태 비교
  • 추가 분석을 위한 부분집합 생성

ai가 추천하는 심화 예제

winter_df = bike_df[bike_df["Seasons"] == "Winter"]

print(winter_df.head())

# 결과
# 겨울 데이터만 추출

18. drop()

개요

drop()은 특정 행 또는 열을 삭제하는 메서드이다.

머신러닝에서는 모델에 직접 넣기 어려운 컬럼을 제거하거나,
서로 지나치게 비슷한 정보를 담고 있는 컬럼을 정리할 때 자주 사용한다.


실습 코드 1

bike_df = bike_df.drop('Date', axis=1)
bike_df.head()

# 결과
# Date 컬럼 제거

실습 코드 2

bike_df = bike_df.drop(['Dew point temperature', 'Hour', 'Humidity', 'year'], axis=1)
bike_df.head()

# 결과
# 다중공선성이 높은 컬럼 일부 제거

주요 역할

  • 직접 모델 입력이 어려운 컬럼 제거
  • 중복 정보가 많은 컬럼 제거
  • 다중공선성 완화

주요 파라미터

파라미터 설명
labels 삭제 대상
axis 0은 행, 1은 열
errors 없는 컬럼 처리 방식

반환값

pandas.DataFrame

ai가 추천하는 심화 예제

reduced_df = bike_df.drop(columns=["Snowfall", "Rainfall"], errors="ignore")

print(reduced_df.head())

# 결과
# 지정 컬럼 제거 후 DataFrame 출력

19. select_dtypes(), columns, tolist(), nunique()

개요

이 조합은 범주형 컬럼을 자동으로 찾고, 각 범주형 컬럼의 고유값 개수를 확인할 때 사용된다.

범주형 컬럼을 하나씩 수동으로 찾기보다, 데이터 타입 기준으로 자동 탐색하면 전처리 과정을 훨씬 효율적으로 만들 수 있다.


실습 코드

bike_df.select_dtypes(exclude=['number']).columns.tolist()

# 결과
# 숫자형이 아닌 컬럼 리스트 반환
for i in bike_df.select_dtypes(exclude=['number']).columns.tolist():
    print(i, bike_df[i].nunique())

# 결과
# 범주형 컬럼별 고유값 개수 출력

개별 설명

select_dtypes(exclude=['number'])

숫자형이 아닌 컬럼만 선택한다.

.columns

선택된 데이터프레임의 컬럼명을 가져온다.

.tolist()

컬럼명을 파이썬 리스트로 변환한다.

nunique()

해당 컬럼의 고유값 개수를 계산한다.


주요 역할

  • 범주형 컬럼 자동 탐색
  • 원-핫 인코딩 대상 추출
  • 각 컬럼의 범주 개수 확인

ai가 추천하는 심화 예제

cat_cols = bike_df.select_dtypes(exclude=['number']).columns.tolist()

print(cat_cols)

# 결과
# 범주형 컬럼 목록 출력

20. pd.get_dummies()

개요

pd.get_dummies()는 범주형 변수를 원-핫 인코딩하는 함수이다.

문자열로 되어 있는 범주형 변수는 대부분의 머신러닝 모델에 바로 넣을 수 없기 때문에,
각 범주를 0과 1로 이루어진 별도 컬럼으로 바꿔주는 과정이 필요하다.

drop_first=True를 사용하면 첫 번째 범주를 제거하여, 선형회귀에서 발생할 수 있는 더미 변수 함정을 어느 정도 줄일 수 있다.


실습 코드

bike_df = pd.get_dummies(
    bike_df,
    columns=bike_df.select_dtypes(exclude=['number']).columns.tolist(),
    drop_first=True
)
bike_df.head()

# 결과
# 범주형 컬럼이 더미 변수로 변환된다.

주요 역할

  • 범주형 데이터를 수치형으로 변환
  • 모델 입력 가능 상태로 변경
  • 범주 정보를 유지한 채 숫자형 특성 생성

주요 파라미터

파라미터 설명
data 대상 DataFrame
columns 인코딩할 컬럼
drop_first 첫 범주 제거 여부

반환값

pandas.DataFrame

ai가 추천하는 심화 예제

encoded = pd.get_dummies(bike_df, columns=["Seasons"], drop_first=False)

print(encoded.head())

# 결과
# Seasons 컬럼이 여러 더미 컬럼으로 분리된다.

21. corr()sort_values()

개요

corr()는 숫자형 컬럼들 간의 상관계수를 계산하는 메서드이다.
기본적으로 Pearson 상관계수를 사용하며, 값의 범위는 -1 ~ 1이다.

  • 1에 가까울수록 강한 양의 상관
  • -1에 가까울수록 강한 음의 상관
  • 0에 가까울수록 선형 관계가 약함

보통 절댓값 기준으로 0.5 이상이면 비교적 강한 관계로 해석하기도 한다.

실습에서는 목표 변수와 어떤 feature가 강한 관련이 있는지 보고,
또 독립변수끼리 너무 강한 상관이 있는지 확인하여 다중공선성 문제를 점검한다.


실습 코드

correlation_matrix = bike_df.corr()
correlation_matrix

target_corr = correlation_matrix['Rented Bike Count'].sort_values(ascending=False)
print(target_corr)

# 결과
# 전체 상관관계 행렬과 목표 변수 기준 정렬 결과 출력

주요 역할

  • 목표 변수와 관련성 높은 feature 찾기
  • 독립변수 간 강한 상관 확인
  • 다중공선성 후보 변수 식별

반환값

  • corr()pandas.DataFrame
  • sort_values()pandas.Series

ai가 추천하는 심화 예제

top_corr = correlation_matrix["Rented Bike Count"].abs().sort_values(ascending=False)

print(top_corr.head(10))

# 결과
# 목표 변수와 절대 상관이 큰 상위 변수 출력

22. 다중공선성

개요

다중공선성은 독립변수들 사이에 강한 상관관계가 존재하는 현상을 의미한다.

이 문제가 심하면 다음과 같은 문제가 생길 수 있다.

  • 각 변수의 개별 영향 해석이 어려워짐
  • 회귀계수가 불안정해짐
  • 작은 데이터 변화에도 계수가 크게 달라질 수 있음
  • 모델 해석 신뢰도가 떨어짐
  • 예측 성능이 저하될 수 있음

따라서 선형 회귀 모델을 사용할 때는 상관관계와 VIF를 통해 다중공선성을 꼭 점검하는 것이 좋다.


23. sns.heatmap()

개요

heatmap()은 상관관계 행렬처럼 2차원 데이터를 색상으로 표현하는 시각화 함수이다.

숫자만 표로 보는 것보다 변수 간 관계를 훨씬 직관적으로 파악할 수 있다.


실습 코드

plt.figure(figsize=(16, 12))
sns.heatmap(correlation_matrix, annot=True, fmt='.2f', cmap='coolwarm')
plt.title('Feature Correlation Heatmap')
plt.show()

# 결과
# 컬럼 간 상관관계를 색상과 숫자로 보여주는 히트맵이 출력된다.

주요 역할

  • 변수 간 관계를 한눈에 확인
  • 양의 상관 / 음의 상관 구분
  • 상관이 높은 변수 빠르게 탐색

주요 파라미터

파라미터 설명
annot 셀에 수치 표시 여부
fmt 숫자 형식
cmap 색상 팔레트

반환값

matplotlib.axes.Axes

ai가 추천하는 심화 예제

sns.heatmap(correlation_matrix[["Rented Bike Count"]].sort_values(by="Rented Bike Count", ascending=False), annot=True)

# 결과
# 목표 변수 기준 상관관계만 세로로 확인

24. variance_inflation_factor()

개요

variance_inflation_factor()는 독립변수 하나가 다른 독립변수들에 의해 얼마나 잘 설명되는지를 수치로 나타내는 함수이다.

즉, 특정 변수가 나머지 변수들과 얼마나 겹치는 정보를 가지고 있는지를 보여주는 지표라고 볼 수 있다.
이 값이 높을수록 다중공선성이 크다고 해석한다.

일반적인 해석 기준은 다음과 같다.

VIF 값 해석
< 5 문제 없음
5 ~ 10 주의
>= 10 다중공선성 의심

실습 코드

from statsmodels.stats.outliers_influence import variance_inflation_factor

X = bike_df.drop(columns=['Rented Bike Count'], errors='ignore')
X = X.select_dtypes(include='number')
X = X.loc[:, X.nunique() > 1]
X = X.astype(float)

vif_df = pd.DataFrame({
    'Feature': X.columns,
    'VIF': [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
}).sort_values(by='VIF', ascending=False)

# 결과
# 각 변수별 VIF를 계산한 DataFrame 생성

주요 역할

  • 다중공선성이 높은 변수 탐색
  • 제거 대상 변수 선정
  • 회귀 모델 안정성 향상

반환값

float

각 변수마다 하나의 VIF 값이 계산된다.


ai가 추천하는 심화 예제

high_vif = vif_df[vif_df["VIF"] > 10]

print(high_vif)

# 결과
# 다중공선성이 높은 변수만 필터링

25. train_test_split()

개요

train_test_split()은 데이터를 학습용과 테스트용으로 분리하는 함수이다.

머신러닝 모델은 학습 데이터로만 훈련하고,
훈련에 사용하지 않은 테스트 데이터로 성능을 평가해야 일반화 성능을 제대로 확인할 수 있다.


실습 코드

X_train, X_test, y_train, y_test = train_test_split(
    bike_df.drop('Rented Bike Count', axis=1),
    bike_df['Rented Bike Count'],
    test_size=0.3,
    random_state=2026
)

# 결과
# 학습 데이터와 테스트 데이터가 분리된다.

주요 역할

  • 학습용 / 평가용 데이터 분리
  • 과적합 여부 점검
  • 재현성 확보

주요 파라미터

파라미터 설명
test_size 테스트셋 비율
random_state 랜덤 시드
shuffle 셔플 여부

반환값

X_train, X_test, y_train, y_test

ai가 추천하는 심화 예제

print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)

# 결과
# 학습/테스트 데이터 크기 확인

26. 결정트리 기본 이론

결정트리는 데이터를 기반으로 조건 분기를 반복하면서 예측을 수행하는 트리 구조 모델이다.

구조는 다음과 같이 이해할 수 있다.

  • 루트 노드에서 시작
  • 가장 적절한 조건으로 데이터를 분할
  • 하위 노드에서 다시 분할 반복
  • 더 이상 나누기 어렵거나 멈춤 조건에 도달하면 리프 노드 생성
  • 리프 노드에서 최종 예측값 결정

회귀 문제에서는 분할 기준으로 주로 MSE 또는 MAE 같은 오차 기준을 사용한다.
최종적으로는 리프 노드에 속한 샘플들의 평균값을 예측값으로 사용한다.

분류 문제에서는 Gini 불순도나 Entropy를 많이 사용한다.

Gini 불순도

한 노드가 얼마나 섞여 있는지를 나타내는 지표이다.
같은 클래스만 모여 있을수록 낮다.

Entropy

정보의 불확실성을 나타내는 지표이다.
값이 클수록 더 섞여 있고 예측이 어렵다.


27. DecisionTreeRegressor()

개요

DecisionTreeRegressor()는 회귀 문제를 위한 결정트리 모델이다.

입력 데이터를 반복적으로 분할하면서 각 구간의 목표값을 더 잘 설명하도록 트리를 만들어 간다.
비선형 관계를 잘 학습할 수 있고, 해석도 비교적 쉬운 편이다.


실습 코드

from sklearn.tree import DecisionTreeRegressor

dtr = DecisionTreeRegressor(random_state=2026)
dtr.fit(X_train, y_train)
pred1 = dtr.predict(X_test)

sns.scatterplot(x=y_test, y=pred1)

# 결과
# 실제값과 예측값의 관계를 산점도로 확인

주요 역할

  • 비선형 패턴 학습
  • 변수 간 상호작용 반영
  • 해석 가능한 회귀 모델 제공

주요 파라미터

파라미터 설명
random_state 난수 고정
max_depth 트리 최대 깊이
min_samples_leaf 리프 노드 최소 샘플 수

반환값

DecisionTreeRegressor 객체

ai가 추천하는 심화 예제

dtr = DecisionTreeRegressor(random_state=2026, max_depth=10)
dtr.fit(X_train, y_train)

print(dtr.get_depth())

# 결과
# 실제 학습된 트리 깊이 출력

28. LinearRegression()

개요

LinearRegression()은 입력 변수와 목표 변수 사이의 선형 관계를 학습하는 회귀 모델이다.

가장 기본적인 회귀 모델이며, 각 변수의 영향력을 해석하기 쉬워서 기준선 모델로 자주 사용된다.

수식 형태는 다음과 같다.

[
y = w_1x_1 + w_2x_2 + \cdots + b
]

여기서 각 $w$는 feature의 영향력, $b$는 절편이다.


실습 코드

from sklearn.linear_model import LinearRegression

lr = LinearRegression()
lr.fit(X_train, y_train)
pred2 = lr.predict(X_test)

sns.scatterplot(x=y_test, y=pred2)

# 결과
# 실제값과 선형회귀 예측값 비교 산점도

주요 역할

  • 해석 가능한 기준선 모델
  • 각 변수의 선형 영향 추정
  • 다른 모델과 성능 비교 기준 제공

주요 속성

속성 설명
coef_ 회귀계수
intercept_ 절편

ai가 추천하는 심화 예제

print(lr.coef_)
print(lr.intercept_)

# 결과
# 각 변수의 선형 영향도와 절편 출력

29. 하이퍼파라미터가 적용된 결정트리

개요

기본 결정트리는 트리가 너무 깊어지면 과적합이 발생할 수 있다.
이를 완화하기 위해 max_depth, min_samples_leaf 같은 하이퍼파라미터를 조절한다.

max_depth는 트리의 최대 깊이를 제한하고,
min_samples_leaf는 리프 노드가 너무 작은 샘플 수를 가지지 않도록 제한한다.


실습 코드

dtr = DecisionTreeRegressor(random_state=2026, max_depth=50, min_samples_leaf=30)
dtr.fit(X_train, y_train)
pred3 = dtr.predict(X_test)

# 결과
# 트리 복잡도를 제어한 결정트리 예측 수행

주요 역할

  • 과적합 완화
  • 지나치게 세밀한 분할 방지
  • 일반화 성능 향상

ai가 추천하는 심화 예제

print(root_mean_squared_error(y_test, pred3))

# 결과
# 하이퍼파라미터 조정 후 RMSE 확인

30. RandomForestRegressor()

개요

RandomForestRegressor()는 여러 개의 결정트리를 학습시키고,
그 예측 결과를 평균내어 최종 예측값을 만드는 앙상블 회귀 모델이다.

단일 결정트리보다 과적합 위험이 낮고, 더 안정적인 성능을 보이는 경우가 많다.


실습 코드

from sklearn.ensemble import RandomForestRegressor

rf = RandomForestRegressor(random_state=2026)
rf.fit(X_train, y_train)
pred4 = rf.predict(X_test)

# 결과
# 랜덤 포레스트 예측 수행

주요 역할

  • 여러 트리를 조합한 안정적 예측
  • 비선형 패턴 학습
  • 변수 중요도 제공

주요 파라미터

파라미터 설명
n_estimators 트리 개수
random_state 난수 고정
max_depth 각 트리 최대 깊이

반환값

RandomForestRegressor 객체

ai가 추천하는 심화 예제

rf = RandomForestRegressor(n_estimators=200, random_state=2026)
rf.fit(X_train, y_train)

print(rf.feature_importances_)

# 결과
# 각 변수 중요도 출력

31. fit()

개요

fit()은 모델을 학습시키는 메서드이다.

입력 데이터 X_train과 정답 y_train을 이용해 모델 내부 파라미터를 결정한다.
모델을 만든 직후에는 단순 객체 상태이지만, fit() 이후에는 실제 예측 가능한 상태가 된다.


실습 코드

dtr.fit(X_train, y_train)
lr.fit(X_train, y_train)
rf.fit(X_train, y_train)

# 결과
# 각 모델이 학습 완료 상태가 된다.

주요 역할

  • 입력과 정답 사이 관계 학습
  • 모델 내부 파라미터 최적화
  • 예측 가능한 상태로 전환

반환값

self

ai가 추천하는 심화 예제

model = LinearRegression()
returned = model.fit(X_train, y_train)

print(returned is model)

# 결과
# True

32. predict()

개요

predict()는 학습된 모델을 이용해 새로운 입력 데이터의 예측값을 계산하는 메서드이다.

회귀 문제에서는 연속형 숫자 예측값이 반환된다.


실습 코드

pred1 = dtr.predict(X_test)
pred2 = lr.predict(X_test)
pred3 = dtr.predict(X_test)
pred4 = rf.predict(X_test)

# 결과
# 각 모델의 예측값 배열 반환

주요 역할

  • 테스트셋 예측
  • 성능 평가 지표 계산
  • 실제값과 예측값 비교

반환값

numpy.ndarray

ai가 추천하는 심화 예제

sample_pred = rf.predict(X_test.iloc[:5])

print(sample_pred)

# 결과
# 상위 5개 샘플 예측값 출력

33. root_mean_squared_error()

개요

root_mean_squared_error()는 회귀 모델의 RMSE를 계산하는 함수이다.

RMSE는 예측값과 실제값의 차이를 제곱한 뒤 평균을 내고, 다시 제곱근을 취한 값이다.

[
RMSE = \sqrt{\frac{1}{n}\sum (y_i - \hat{y}_i)^2}
]

오차 단위를 원래 목표 변수와 동일하게 유지하기 때문에 해석이 직관적이다.
값이 작을수록 성능이 좋은 모델로 본다.


실습 코드

from sklearn.metrics import root_mean_squared_error

root_mean_squared_error(y_test, pred1)
root_mean_squared_error(y_test, pred2)
root_mean_squared_error(y_test, pred3)
root_mean_squared_error(y_test, pred4)

# 결과
# 각 모델의 RMSE 값 반환

모델별 성능

실습 결과는 다음과 같이 정리된다.

  • 결정트리: 386.77321542142454
  • 선형회귀: 446.47481228386397
  • 결정트리(하이퍼파라미터 적용): 334.1314843839107
  • 랜덤 포레스트: 288.8180227712803

이 결과를 보면 랜덤 포레스트가 가장 낮은 RMSE를 기록하여 가장 좋은 성능을 보였다.


반환값

float

ai가 추천하는 심화 예제

rmse_rf = root_mean_squared_error(y_test, pred4)
print(rmse_rf)

# 결과
# 랜덤 포레스트 RMSE 출력

34. plot_tree()

개요

plot_tree()는 학습된 결정트리의 구조를 시각화하는 함수이다.

트리 모델은 내부 의사결정 흐름을 그림으로 볼 수 있다는 점이 큰 장점이다.
어떤 feature가 어떤 기준으로 분기되는지 확인할 수 있어, 모델 해석에 유리하다.


실습 코드

from sklearn.tree import plot_tree

plt.figure(figsize=(24, 12))
plot_tree(dtr, max_depth=5, fontsize=10, feature_names=X_train.columns)
plt.show()

# 결과
# 결정트리 상위 구조가 시각화된다.

주요 역할

  • 트리 분기 조건 확인
  • 어떤 feature가 중요한지 파악
  • 모델의 의사결정 구조 해석

주요 파라미터

파라미터 설명
decision_tree 시각화할 모델
max_depth 표시할 최대 깊이
fontsize 글자 크기
feature_names 변수 이름

반환값

list of matplotlib artists

ai가 추천하는 심화 예제

plt.figure(figsize=(18, 8))
plot_tree(dtr, max_depth=3, feature_names=X_train.columns, fontsize=8)
plt.show()

# 결과
# 더 단순한 깊이의 트리 구조 확인

35. feature_importances_, DataFrame(), sort_values(), head(), sns.barplot()

개요

랜덤 포레스트와 같은 트리 기반 모델은 각 feature가 예측에 얼마나 기여했는지를 변수 중요도 형태로 제공한다.

실습에서는 중요도 배열을 표와 그래프로 정리해, 어떤 변수가 수요 예측에 큰 영향을 미치는지 해석한다.


실습 코드

rf.feature_importances_

# 결과
# 각 feature 중요도 배열 출력
feature_imp = pd.DataFrame({
    'features': X_train.columns,
    'importances': rf.feature_importances_
})
top10 = feature_imp.sort_values('importances', ascending=False).head(10)
top10

# 결과
# 중요도 상위 10개 변수 추출
plt.figure(figsize=(5, 10))
sns.barplot(x='importances', y='features', data=top10)

# 결과
# 상위 중요 변수 시각화

개별 역할

feature_importances_

트리 기반 모델이 계산한 변수 중요도 배열을 반환한다.

pd.DataFrame()

중요도 결과를 표 형태로 정리한다.

sort_values()

중요도 기준으로 정렬한다.

head()

상위 N개만 추출한다.

sns.barplot()

중요한 변수를 시각적으로 비교한다.


주요 역할

  • 중요한 입력 변수 파악
  • 모델 해석 가능성 확보
  • feature selection 근거 제공

ai가 추천하는 심화 예제

top5 = feature_imp.sort_values("importances", ascending=False).head(5)

print(top5)

# 결과
# 중요도 상위 5개 변수 출력

36. 전체 실습 흐름 요약

pd.read_csv()
↓
info() / describe() / columns / head()
↓
sns.scatterplot()
↓
isna().sum()
↓
pd.to_datetime()
↓
.dt.year / .dt.month / .dt.day
↓
sns.lineplot()
↓
groupby().mean()
↓
pd.cut()
↓
sns.barplot() / value_counts()
↓
drop()
↓
select_dtypes() / nunique()
↓
pd.get_dummies()
↓
corr()
↓
sns.heatmap()
↓
variance_inflation_factor()
↓
drop()로 다중공선성 높은 변수 제거
↓
train_test_split()
↓
DecisionTreeRegressor()
↓
LinearRegression()
↓
DecisionTreeRegressor(하이퍼파라미터 적용)
↓
RandomForestRegressor()
↓
fit()
↓
predict()
↓
root_mean_squared_error()
↓
plot_tree()
↓
feature_importances_