스터디/Data

[Imple] 비즈니스 사례 실습 : 영업(Sales department) 사례

_leezoee_ 2024. 4. 12. 14:28

 

 

 

Udemy 강의 중 비즈니스 데이터 사이언스 사례 강의를 들으며 공부한 내용을 정리한 글이다.

 

 

연구 목표 설정

 

연구 목표 : 기업 과거 데이터를 기반으로 미래의 판매량을 예측해보기 (모든 계절적 영향을 고려)

 

데이터 집합 가져오기

 

먼저 사용할 라이브러리를 임포트한 뒤 구글 코랩에 마운트한다.

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import datetime
from google.colab import drive
drive.mount('../경로')

 

 

사용할 데이터를 확인한다.

sales_train_df = pd.read_csv('/content/drive/경로/train.csv')
sales_train_df.head(5) #데이터 확인
sales_train_df.info()
sales_train_df.describe()

데이터 통계분포 결과 확인

 

 

 

 

다음으로 매장 정보 데이터를 가져와서 분석해본다.

 

store_info_df = pd.read_csv('/content/drive/경로/store.csv')
store_info_df.head(5) #데이터 확인
store_info_df.info()
store_info_df.describe()

 

매장 정보 데이터 통계분포 결과 확인

 

 

 

 

 

데이터 탐색 & 시각화

 

두 개의 데이터 프레임을 합병하고 시각화하는 실습을 진행한다.

 

먼저 누락된 데이터가 있는지 없는지 살펴본다.

 

sns.heatmap(sales_train_df.isnull(), yticklabels=False, cbar = False, cmap='Blues')

 

누락값 히트맵 결과

 

 

별도로 누락된 값이 없음을 확인할 수 있다.

 

다음은 데이터 히스토그램을 시각화하여 변수와 분포에 대한 요약을 확인한다.

sales_train_df.hist(bins = 30, figsize = (20,20), color = 'r')

데이터 요소별 히스토그램 결과 일부 발췌

 

 

히스토그램을 통해 확인해본 중요한 요소들은 다음과 같다. (describe와 info 정보들과 비교해보기)

 

1. 고객 수는 하루 평균 600명 정도이고 최댓값은7000명 정도. (sales_train_df['Customers'].max() 로 확인 가)

2. 데이터가 요일에 따라 균일하게 분배되어있음.

3. 사용한 1000개 매장에 대한 모든 데이터가 균등하게 분포.

 

다음은 매장오픈 여부인 open 컬럼에 대한 데이터를 정제하는데

open이 1인 경우의 데이터만 써야한다 (매장이 문을 열었을 경우) 그래야 고객 수나 판촉 등의 다른 데이터가 유의미 하기 때문이다.

 

close_train_df = sales_train_df[sales_train_df['Open'] == 0]
open_train_df = sales_train_df[sales_train_df['Open'] == 1]

#매장 오픈한 데이터만 추출
sales_train_df = sales_train_df[sales_train_df['Open'] == 1]

#open 컬럼은 이제 필요없으니 삭제
sales_train_df.drop(['Open'], axis=1, inplace=True)

 

 

다음은 매장데이터에 대한 데이터 탐색을 진행한다.

먼저 누락된 데이터가 있는지 없는지 살펴본다.

sns.heatmap(store_info_df.isnull(), yticklabels=False, cbar=False, cmap='Blues')

누락값 히트맵 결과

 

 

누락값들이 많이 보이므로 각각에 대한 데이터를 잠시 살펴본다

먼저 경쟁 거리인 CompetitionDeistance 가 null 인 데이터를 살펴보도록 한다.

store_info_df[store_info_df['CompetitionDistance'].isnull()]

 

결과

 

CompetitionDeistance  외에도 많은 NaN 값이 보이는 걸 확인할 수 있다.

다음은 경쟁사 개업 달인 CompetitionOpenSinceMonth를 확인한다.

store_info_df[store_info_df['CompetitionOpenSinceMonth'].isnull()]

 

결과

 

실습을 진행하는 데이터프레임은 1000개 데이터인데 이 중 354개에 대한 결측요소를 확인할 수 있다. (사실상 1/3)

 

다음 Promo2 컬럼에 대한건데 Promo2 컬럼에 대한 값이 0이면 Promo2SinceWeek나 Year 등등 연관 값들이 NaN이 되어있음을 볼 수 있다. 더 자세히 보기위해 Promo2 가 0일 경우 데이터를 추출해본다.

store_info_df[store_info_df['Promo2'] == 0]

 

결과

Promo2가 0인경우 모든 관련 열이 NaN등으로 숫자가 아님을 볼 수 있다.

 

이제 저런 숫자가 아닌 값들을 0으로 바꿔주는 작업을 진행한다.

str_cols = ['Promo2SinceWeek', 'Promo2SinceYear', 'PromoInterval', 'CompetitionOpenSinceYear', 'CompetitionOpenSinceMonth']

#반복문
for str in str_cols:
    store_info_df [str].fillna(0, inplace = True)

 

데이터가 잘 바뀌었는지 히트맵을 통해 다시 확인.

sns.heatmap(store_info_df.isnull(), yticklabels=False, cbar=False, cmap='Blues')

0으로 채운 후 히트맵 결과

 

 

그래도 누락된 데이터는 샘플데이터의 평균값으로 대체해준다.

store_info_df['CompetitionDistance'].fillna(store_info_df['CompetitionDistance'].mean(), inplace=True)

 

다시 히트맵을 통해 데이터 확인.

sns.heatmap(store_info_df.isnull(), yticklabels=False, cbar=False, cmap='Blues')

 

최종 히트맵

 

 

드디어 데이터 프레임의 모든 누락 정보를 제거했다!

 

이제 매장 정보 데이터 프레임의 속성들을 히스토그램을 통해 시각화해본다.

store_info_df.hist(bins = 30, figsize = (20, 20), color = 'r')

매장 데이터 요소별 히스토그램 결과 일부 발췌

 

간단히 살펴보면 CompetitionDistance 는 대부분 짧은 거리 안에 있다고 볼 수 있다 (0과 3000m 즉 3km 사이에 많이 분포함을 볼 수 있음)

Promo2를 보면 절반 정도의 매장들이 Promo 즉 판촉행사를 진행중임을 볼 수 있다.

위 사진에는 안나왔으나 Store 히스토그램이 균등하게 분포되어있음도 확인할 수 있다.

 

 

다음으로는 두 데이터 프레임을 병합하고 그 데이터를 시각화한다.

 

먼저 데이터에서 Store 열을 기반으로 두 데이터 프레임을 병합한다.

sales_train_all_df = pd.merge(sales_train_df, store_info_df, how = 'inner', on = 'Store')

 

다음으로 데이터 간 상관관계 확인

correlations = sales_train_all_df.corr()['Sales'].sort_values()

 

다음은 히트맵으로 시각화를 진행하고 모든 연관성을 하나의 도표로 비교해본다.

correlations = sales_train_all_df.corr()
f, ax = plt.subplots(figsize = (20,20))
sns.heatmap(correlations, annot = True)

 

히트맵 결과 일부 발췌

 

 

다음은 datetime 을 이용해 연,월,일별 데이터를 구분해본다.

#연도추출
sales_train_all_df['Year'] = pd.DatetimeIndex(sales_train_all_df['Date']).year
#월 추출
sales_train_all_df['Month'] = pd.DatetimeIndex(sales_train_all_df['Date']).month
#일 추출
sales_train_all_df['Day'] = pd.DatetimeIndex(sales_train_all_df['Date']).day

 

 

 

모델 학습

페이스북이 만든 시계열 예측 라이브러리를 사용 (Prophet 프로펫)

 

먼저 필요한 라이브러리를 설치, import 해준다

!pip install fbprophet
from fbprophet import Prophet

 

프로펫을 사용하기 위해서 날짜와 판매액 열 이름을 ds와 y로 바꿔주고 함수를 만든다.

(모델도 만듦)

#날짜를 소문자 ds로 변경, 판매액은 대문자 Y로 변경
#함수제작 : 매장ID를 넣어주고 특정 매장의 미래를 예측
def sales_predictions(Store_ID, sales_df, periods) : 
    sales_df = sales_df[sales_df['Store'] == Store_ID]
    sales_df = sales_df[['Date', 'Sales']].rename(columns = {'Date' : 'ds' , 'Sales' : 'Y'})
    sales_df = sales_df.sort_values('ds')
    
    #프로펫 모델에서 객체를 인스턴스화
    #미래시계열 예측
    model = Prophet()
    model.fit(sales_df)
    future = model.make_future_dataframe(periods = periods)]
    forecast = model.predict(future)
    figure = model.plot(forecast, xlabel = 'Date', ylabel = 'Sales')
    figure2 = model.plot_components(forecast)
#데이터 프레임을 따라 10번 매장의 미래 60일 예측 실행
sales_predictions(10, sales_train_all_df, 60)

forecast 시각화 결과

 

검은 점들은 모델훈련에 사용한 과거 데이터를 표시

파란색으로 forecast 예측 데이터 표시

추세그래프

 

 

ds 판매량 추세를 살펴보면 실제 판매량이 증가하고있음을 알 수 있다.

Day of week 요일별 추세를 살펴보면 월요일정도에 가장 많은 판매가 일어남을 알 수 있다.

Day of year 연도별 추세를 살펴보면 12월 정도에 가장 많은 판매가 일어남을 알 수 있다.

 

 

 

이런식으로 페이스북의 프로펫 모델을 이용한 실습까지 해보았다!