Data Analysis

기상데이터와 GS25 판매량 데이터를 이용한 분석 리포트 - 1

Joon09 2021. 3. 8. 22:38
반응형

Data download and python code link

 

Joonyeong97/GS25_weather_data

Contribute to Joonyeong97/GS25_weather_data development by creating an account on GitHub.

github.com

진행사항

  • 일단위로 진행하기엔 무리가 있을듯 하여, 월 단위로 분석을 진행할 예정입니다.

    분석 진행 사항

  • 애자일 방식으로 진행 예정, 틀을 정하지 않고서 자유로운 분석을 추구했습니다.
    • 이번 리포트는 도메인 지식을 쌓는 시간으로 정했습니다.
    • 데이터 전처리에 신경을 많이 쓰고, 최대한 데이터를 파악하려고 합니다.
  • 중간고사 리포트는 EDA와 시각화를 통한 추세파악 진행예정
  • 유통 데이터와 기상 데이터를 사용할 예정
  • 세부적으로 경기도 권역만 분석을 실시할 예정
  • 그 외 서울과 인천 지역은 지역별 판매량 시각화와 날짜별 판매량 시각화 총 두개만 진행 후 더이상 진행하지 않을 예정

추후 진행 방안

  • 세부적으로 경기도 광주시와 경기도 성남시의 판매를 통계학적으로 비교하고, 가설을 세워서 검증할 예정
    • ex) 라면판매량은 경기광주시와 경기성남시의 차이가 없다.
    • ex2) 날씨가 추워지면 라면판매량이 증가할까?

에로사항

  • GS25.csv의 데이터중 법정구역이 합쳐져있음, 기존에 집계 처리가 되어있는 상태여서 복구할 수 없음
  • 날씨 데이터와 병합하여 분석할 예정이여서 삭제하고 진행 하였습니다.
    • '가평군양평군'
    • '여주시이천시'
    • '연천군포천군'
    • '오산시안성시평택시'

 

 

Data Load

  • Library load
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams['figure.figsize'] = [18, 12]
plt.rcParams['font.family'] = 'NanumGothic'
from statannot import add_stat_annotation
import numpy as np
from scipy import stats
gs25 = pd.read_csv('Data/GS25.csv',encoding='cp949')
data_w = pd.read_csv('Data/기상데이터.csv',encoding='cp949')

Data Validation

 

GS25 데이터 확인

 

  • 전체 판매량
gs25['date_year'] = gs25['korea_cvs.sale_dt'].astype(str).str[:4]
print('총 판매량 : ',len(gs25), '\n'
    '2017년 판매량 : ',len(gs25[gs25['date_year'] == '2016']),'비율 : ',
      round(len(gs25[gs25['date_year'] == '2016'])/len(gs25)*100,2),'%', '\n'
      '2018년 판매량 : ',len(gs25[gs25['date_year'] == '2017']),'비율 : ',
      round(len(gs25[gs25['date_year'] == '2017'])/len(gs25)*100,2),'%' '\n'
      '2019년 판매량 : ',len(gs25[gs25['date_year'] == '2018']),'비율 : ',
      round(len(gs25[gs25['date_year'] == '2018'])/len(gs25)*100,2),'%')

총 판매량 :  2707786 
2017년 판매량 :  923321 비율 :  34.1 % 
2018년 판매량 :  904207 비율 :  33.39 %
2019년 판매량 :  880258 비율 :  32.51 %

  • 성별 판매량
print('총 판매량 : ',len(gs25), '\n'
    '여성 판매량 : ',len(gs25[gs25['korea_cvs.gen_cd'] == 'F']),'비율 : ',
      round(len(gs25[gs25['korea_cvs.gen_cd'] == 'F'])/len(gs25)*100,2),'%', '\n'
      '남성 판매량 : ',len(gs25[gs25['korea_cvs.gen_cd'] == 'M']),'비율 : ',
      round(len(gs25[gs25['korea_cvs.gen_cd'] == 'M'])/len(gs25)*100,2),'%')

총 판매량 :  2707786 
여성 판매량 :  1442960 비율 :  53.29 % 
남성 판매량 :  1264826 비율 :  46.71 %

 

  • 연령별 판매량
age_list = list(set(gs25['korea_cvs.age_cd']))
age_list.sort()
age_list

['00~19', '20~39', '40~59', '60~99']

print('총 판매량 : ',len(gs25), '\n'
    '00~19 : ',len(gs25[gs25['korea_cvs.age_cd'] == age_list[0]]),'비율 : ',
      round(len(gs25[gs25['korea_cvs.age_cd'] == age_list[0]])/len(gs25)*100,2),'%', '\n'
      '20~39 : ',len(gs25[gs25['korea_cvs.age_cd'] == age_list[1]]),'비율 : ',
      round(len(gs25[gs25['korea_cvs.age_cd'] == age_list[1]])/len(gs25)*100,2),'%', '\n'
     '40~59 : ',len(gs25[gs25['korea_cvs.age_cd'] == age_list[2]]),'비율 : ',
      round(len(gs25[gs25['korea_cvs.age_cd'] == age_list[2]])/len(gs25)*100,2),'%', '\n'
     '60~99 : ',len(gs25[gs25['korea_cvs.age_cd'] == age_list[3]]),'비율 : ',
      round(len(gs25[gs25['korea_cvs.age_cd'] == age_list[3]])/len(gs25)*100,2),'%', '\n') 

총 판매량 :  2707786 
00~19 :  389610 비율 :  14.39 % 
20~39 :  1118350 비율 :  41.3 % 
40~59 :  924433 비율 :  34.14 % 
60~99 :  275393 비율 :  10.17 % 

  • 카테고리별 판매량
category_list = list(set(gs25['korea_cvs.category']))
category_list.sort()
category_list

['과자',
 '라면',
 '마스크',
 '맥주',
 '면도기',
 '생리대',
 '생수',
 '숙취해소제',
 '스타킹',
 '아이스크림',
 '우산',
 '탄산음료']

category_rank = dict()
print('총 판매량 : ',len(gs25))
for category in category_list:
    print('{} : '.format(category),len(gs25[gs25['korea_cvs.category'] == category]),
          '비율 : ',round(len(gs25[gs25['korea_cvs.category'] == category])/len(gs25)*100,2),'%')
    category_rank[category] = round(len(gs25[gs25['korea_cvs.category'] == category])/len(gs25)*100,2)

총 판매량 :  2707786
과자 :  428685 비율 :  15.83 %
라면 :  413521 비율 :  15.27 %
마스크 :  65748 비율 :  2.43 %
맥주 :  313128 비율 :  11.56 %
면도기 :  51970 비율 :  1.92 %
생리대 :  158116 비율 :  5.84 %
생수 :  310041 비율 :  11.45 %
숙취해소제 :  184866 비율 :  6.83 %
스타킹 :  103876 비율 :  3.84 %
아이스크림 :  318908 비율 :  11.78 %
우산 :  55153 비율 :  2.04 %
탄산음료 :  303774 비율 :  11.22 %

category_df = pd.DataFrame([category_rank], index = ['판매량(%)']).T
category_df = category_df.sort_values('판매량(%)',ascending=False)
category_df

시각화

sns.barplot(x=category_df.index, y=category_df['판매량(%)'], data=category_df)
plt.title('카테고리별 판매량', fontsize=20)
plt.ylabel('판매량(%)', fontsize=18)
plt.xlabel('품목', fontsize=18)
plt.show()

기상데이터 확인

데이터 전처리 진행

data_w.columns=['관측일',
                '관측번호',
                '지역',
                '법정동',
                '최고기온',
                '최대풍속',
                '최소기온',
                '평균기온',
                '평균상대습도',
                '평균풍속',
                '합계강수량']

feature 생성

data_w['관측일(월)'] = (data_w['관측일'].astype(str).str[:6]).astype(int)

데이터 형변환

data_w['관측일'] = pd.to_datetime(data_w['관측일'],format="%Y%m%d")
weather_col = ['최고기온','최대풍속','최소기온','평균기온', '평균상대습도','평균풍속', '합계강수량']
def whether_line_visualizition(data_w,weather_col,x='관측일',title=''):
    for col in weather_col:
        ax = sns.lineplot(x=x, y=col ,hue='지역',data=data_w)

        plt.title('{0} 지역별 {1}'.format(title,col), fontsize=20)
        plt.ylabel('{}'.format(col), fontsize=14)
        plt.xlabel('Date', fontsize=14)
        plt.legend(fontsize=12, loc='best')

        plt.show()



Data Preprocessing

gs25['korea_cvs.sale_dt(month)'] = (gs25['korea_cvs.sale_dt'].astype(str).str[:6]).astype(int)
gs25 = gs25.drop('korea_cvs.sale_dt',axis=1)
# 데이터 집계 처리
gs25_month = gs25.groupby(['korea_cvs.pvn_nm',
                           'korea_cvs.sale_dt(month)',
                           'korea_cvs.gen_cd','korea_cvs.age_cd',
                           'korea_cvs.category',
                           'korea_cvs.bor_nm']).sum().reset_index()
data_w_mean=(data_w[['관측일(월)',
                     '법정동',
                     '최고기온',
                     '최대풍속',
                     '최소기온',
                     '평균기온',
                     '평균풍속',
                     '합계강수량']].groupby(['관측일(월)','법정동']).mean().reset_index())
# 합쳐진 법정동 제외진행
gs25_month = gs25_month[(gs25_month['korea_cvs.bor_nm'] != '가평군양평군') &
                       (gs25_month['korea_cvs.bor_nm'] != '여주시이천시') &
                       (gs25_month['korea_cvs.bor_nm'] != '연천군포천군') &
                       (gs25_month['korea_cvs.bor_nm'] != '오산시안성시평택시')]
# 기온 데이터와 GS25데이터 조인
merge_data = pd.merge(gs25_month,
                      data_w_mean,
                      how='inner',
                      left_on=['korea_cvs.sale_dt(month)',
                               'korea_cvs.bor_nm'],right_on=['관측일(월)','법정동'])
# 년 단위 추가
merge_data['korea_cvs.sale_dt(year)'] = (merge_data['korea_cvs.sale_dt(month)']
                                         .astype(str).str[:4]).astype(int)

지역분할

gyunggido = merge_data[merge_data['korea_cvs.pvn_nm'] == '경기도']
seoul = merge_data[merge_data['korea_cvs.pvn_nm'] == '서울특별시']
incheon = merge_data[merge_data['korea_cvs.pvn_nm'] == '인천광역시']
gyunggido_area_list = list(set(gyunggido['korea_cvs.bor_nm']))
seoul_area_list = list(set(seoul['korea_cvs.bor_nm']))
incheon_area_list = list(set(incheon['korea_cvs.bor_nm']))

날짜 분할

full_month = list(set(merge_data['korea_cvs.sale_dt(month)']))
full_month.sort()
# 201601~201812 월별로 분할
def month_slice(dataframe,full_month):
    month_slice = []
    for month in full_month:
        month_slice.append(dataframe[dataframe['korea_cvs.sale_dt(month)'] == month])
    return month_slice
gyunggido_month_slice = month_slice(gyunggido,full_month)
seoul_month_slice = month_slice(seoul,full_month)
incheon_month_slice = month_slice(incheon,full_month)

지역 세분화

# 지역별 dictionary 생성
def area_slice(dataframe,area_list):
    area_dict = dict()
    for area in area_list:
        area_dict[area] = dataframe[dataframe['korea_cvs.bor_nm'] == area]
    return area_dict
gyunggido_area = area_slice(gyunggido,gyunggido_area_list)
seoul_area = area_slice(seoul,seoul_area_list)
incheon_area = area_slice(incheon,incheon_area_list)
temp = (gyunggido_area['광주시'][['korea_cvs.sale_dt(month)',
                               '최고기온',
                               '최대풍속',
                               '최소기온',
                               '평균기온',
                               '평균풍속',
                               '합계강수량']]).drop_duplicates('korea_cvs.sale_dt(month)')
temp.index = temp['korea_cvs.sale_dt(month)']

시각화 (지역별)

X는 품목별, Y는 Count, 분류를 성별로 나눠서 box plot으로 확인합니다.

여기서는 날짜별로 하나씩 찍어내면서 성별로 어떤 품목이 가장 많이 판매되었는지 확인하는 시각화 자료입니다.

def visualization_area(dataframe_dict,
                       area_list,
                       x='korea_cvs.category',
                       y='korea_cvs.adj_qty',
                       category=str('korea_cvs.gen_cd')):
    plt.rcParams['figure.figsize'] = [20, 8]
    for area in area_list:
        for year in [2016,2017,2018]:
            sns.boxplot(x=x, y=y, hue=category, data=gyunggido_area[area][gyunggido_area[area]['korea_cvs.sale_dt(year)'] == year])

            plt.ylabel('Count', fontsize=18)
            plt.xlabel('품목', fontsize=18)

            plt.title('{0} 년도 {1} 판매량 '.format(year,area), fontsize=20)
            plt.legend(fontsize=14,loc='upper right')

            plt.show()
visualization_area(gyunggido_area,gyunggido_area_list)

이미지가 20개가 넘어서 생략합니다.

 

시각화 (날짜별)

def visualization(dataframe,full_month,
                  x='korea_cvs.category',
                  y='korea_cvs.adj_qty',
                  category=str('korea_cvs.gen_cd'),
                  title=''):
    plt.rcParams['figure.figsize'] = [24, 10]
    for month, data in zip(full_month,dataframe):
        sns.barplot(x=x, y=y, hue=category, data=data,dodge=True) # default : dodge=True

        plt.ylabel('Count', fontsize=18)
        plt.xlabel('품목', fontsize=18)

        plt.title('{} {} 판매량'.format(title,month), fontsize=20)
        plt.legend(fontsize=14)
        plt.show()

 

경기도, 서울, 인천 구역

X는 품목명, Y는 Count, 나이대로 분류한 시각화 자료입니다.

대부분 시각적으로 보기 편하게 나이대에 맞춰서 판매량을 보고 싶었습니다.

이 시각화 자료도 마찬가지로 경기도, 서울, 인천 지역으로 크게 나누어서 차이점을 확인하고 싶었습니다.

또한 날짜로 for문을 이용함으로써 추세를 확인할 수도 있습니다.

visualization(gyunggido_month_slice,full_month,category='korea_cvs.age_cd',title='경기도')

 

visualization(seoul_month_slice,full_month,category='korea_cvs.age_cd',title='서울')

visualization(incheon_month_slice,full_month,category='korea_cvs.age_cd',title='인천')

 

반응형