ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 기상데이터와 GS25 판매량 데이터를 이용한 분석 리포트 - 1
    Data Analysis 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='인천')

     

    반응형
Designed by Tistory.