ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Python 데이터분석 기초 38 - 어느 음식점 매출 자료와 날씨 자료를 활용하여 온도(추움, 보통, 더움)에 따른 매출액 평균에 차이를 검정 + 웹
    Python 데이터 분석 2022. 11. 9. 13:12

     

     

    # 어느 음식점 매출 자료와 날씨 자료를 활용하여 온도(추움, 보통, 더움)에 따른 매출액 평균에 차이를 검정
    
    # 귀무 : 음식점 매출액의 평균은 온도에 영향이 없다.
    # 대립 : 음식점 매출액의 평균은 온도에 영향이 있다.
    
    import numpy as np
    import scipy.stats as stats
    import pandas as pd
    import matplotlib.pyplot as plt
    
    # 데이터는 data.go.kr을 참조
    # 매출 자료
    sales_data = pd.read_csv("https://raw.githubusercontent.com/pykwon/python/master/testdata_utf8/tsales.csv", dtype={'YMD':'object'}) # 데이터 타입 바꾸기
    print(sales_data.head(3))
    print(sales_data.info()) # 328 * 3
    
    # 날씨 자료
    wt_data = pd.read_csv("https://raw.githubusercontent.com/pykwon/python/master/testdata_utf8/tweather.csv")
    print(wt_data.head(3))
    print(wt_data.info()) # 702 * 9
    
    # 두 데이터를 병합 : 날짜를 사용.  그래서 wt_data의 tm을 2018-06-01 ==> 20180601 형태로 변환
    wt_data.tm = wt_data.tm.map(lambda x:x.replace('-','')) # 데이터를 하나만 꺼냈기 때문에 시리즈 데이터이다. 그래서 map함수 사용
    print(wt_data.head(3))
    print(wt_data.tail(3))
    
    print('merge --------')
    frame = sales_data.merge(wt_data, how = 'left', left_on = 'YMD', right_on = 'tm')
    print(frame.head(5))
    print(frame.tail(5))
    print(len(frame))   # 328행
    
    print()
    # 분석에 사용할 열만 추출
    print(frame.columns) # ['YMD', 'AMT', 'CNT', 'stnId', 'tm', 'avgTa', 'minTa', 'maxTa', 'sumRn', 'maxWs', 'avgWs', 'ddMes']
    data = frame.iloc[:, [0, 1, 7, 8]] # 'YMD', 'AMT' 'maxTa', 'sumRn'
    print(data.head(3))
    
    # 일별 최고온도(maxTa)를 구간설정을 해서 범주형 변수를 추가
    print(data.maxTa.describe())
    
    data['Ta_gubun'] = pd.cut(data.maxTa, bins = [-5, 8, 24, 37], labels = [0,1,2]) # 3개의 구간으로 나눴다.
    print(data.isnull().sum()) # 결측치 확인
    print(data['Ta_gubun'].unique()) # 어떤 값이 있는지 호출
    
    # 세 그룹의 매출액으로 정규성, 등분산성 확인
    x1 = np.array(data[data.Ta_gubun == 0].AMT)
    x2 = np.array(data[data.Ta_gubun == 1].AMT)
    x3 = np.array(data[data.Ta_gubun == 2].AMT)
    print(x1[:5])
    print(x2[:5])
    print(x3[:5])
    
    # 정규성
    print(stats.ks_2samp(x1, x2).pvalue) # 만족 못함
    print(stats.ks_2samp(x1, x3).pvalue) # 만족 못함
    print(stats.ks_2samp(x2, x3).pvalue) # 만족 못함
    
    # 등분산성
    print(stats.levene(x1, x2, x3).pvalue) # 표본수가 클 때 사용하는 levene 사용. 0.0390023 < 0.05 만족 못함
    
    print('온도별 매출액 평균')
    # pd.options.display.float_format = '{:.5f}'.format  # 과학적 표기법 해제
    spp = data.loc[:,['AMT','Ta_gubun']]
    print(spp.head(2))
    print(spp.groupby('Ta_gubun').mean())
    
    print(pd.pivot_table(spp, index = ['Ta_gubun'], aggfunc = 'mean')) # groupby 함수와 같은 방법
    # 1032362 vs 818106 vs 553710 차이?
    
    # anova 진행
    sp = np.array(spp) # DataFrame을 np.array로 바꾸기
    print(sp[:3])
    group1 = sp[sp[:, 1] == 0, 0] # 1열이 0인 거의 0번째 열
    group2 = sp[sp[:, 1] == 1, 0]
    group3 = sp[sp[:, 1] == 2, 0]
    
    # 데이터 분포 시각화
    # plt.boxplot([group1, group2, group3], showmeans = True)
    # plt.show()
    
    print() # 요인이 하나 데이터가 여러개일때 사용
    print(stats.f_oneway(group1, group2, group3))
    # statistic=99.1908012029983, pvalue=2.360737101089604e-34
    # 해석 : pvalue=2.360737101089604e-34 < 0.05 이므로 귀무 기각.
    # 음식점 매출액의 평균은 온도에 영향이 있다.
    
    # 정규성을 만족하지 않으므로
    print(stats.kruskal(group1, group2, group3))
    # KruskalResult(statistic=132.7022591443371, pvalue=1.5278142583114522e-29)
    # 여전히 기각
    
    # 등분산성을 마족하지 않으므로
    # pip install pingouin
    from pingouin import welch_anova
    print(welch_anova(data=data, dv='AMT', between='Ta_gubun'))
    #      Source  ddof1     ddof2           F         p-unc       np2
    # 0  Ta_gubun      2  189.6514  122.221242  7.907874e-35  0.379038
    # 여전히 기각
    
    
    # 각 매출액의 평균차이가 궁금. 사후검정 수행
    # post hoc test
    from statsmodels.stats.multicomp import pairwise_tukeyhsd
    turkeyResult = pairwise_tukeyhsd(endog = spp.AMT, groups = spp.Ta_gubun, alpha = 0.05)
    print(turkeyResult)  # 차이가 없으면 reject가 False가 나오고, 차이가 크면 True가 나온다.
    
    # 시각화
    turkeyResult.plot_simultaneous(xlabel = 'mean', ylabel = 'group')
    plt.show()
    
    
    <console>
            YMD    AMT  CNT
    0  20190514      0    1
    1  20190519  18000    1
    2  20190521  50000    4
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 328 entries, 0 to 327
    Data columns (total 3 columns):
     #   Column  Non-Null Count  Dtype 
    ---  ------  --------------  ----- 
     0   YMD     328 non-null    object
     1   AMT     328 non-null    int64 
     2   CNT     328 non-null    int64 
    dtypes: int64(2), object(1)
    memory usage: 7.8+ KB
    None
       stnId          tm  avgTa  minTa  maxTa  sumRn  maxWs  avgWs  ddMes
    0    108  2018-06-01   23.8   17.5   30.2    0.0    4.3    1.9    0.0
    1    108  2018-06-02   23.4   17.6   30.1    0.0    4.5    2.0    0.0
    2    108  2018-06-03   24.0   16.9   30.8    0.0    4.2    1.6    0.0
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 702 entries, 0 to 701
    Data columns (total 9 columns):
     #   Column  Non-Null Count  Dtype  
    ---  ------  --------------  -----  
     0   stnId   702 non-null    int64  
     1   tm      702 non-null    object 
     2   avgTa   702 non-null    float64
     3   minTa   702 non-null    float64
     4   maxTa   702 non-null    float64
     5   sumRn   702 non-null    float64
     6   maxWs   702 non-null    float64
     7   avgWs   702 non-null    float64
     8   ddMes   702 non-null    float64
    dtypes: float64(7), int64(1), object(1)
    memory usage: 49.5+ KB
    None
       stnId        tm  avgTa  minTa  maxTa  sumRn  maxWs  avgWs  ddMes
    0    108  20180601   23.8   17.5   30.2    0.0    4.3    1.9    0.0
    1    108  20180602   23.4   17.6   30.1    0.0    4.5    2.0    0.0
    2    108  20180603   24.0   16.9   30.8    0.0    4.2    1.6    0.0
         stnId        tm  avgTa  minTa  maxTa  sumRn  maxWs  avgWs  ddMes
    699    108  20200430   17.1    9.3   23.4    0.0    5.9    2.7    0.0
    700    108  20200501   20.2   16.4   26.2    0.0    5.5    2.7    0.0
    701    108  20200502   20.3   18.0   23.9    0.0    4.6    2.3    0.0
    merge --------
            YMD     AMT  CNT  stnId        tm  ...  maxTa  sumRn  maxWs  avgWs  ddMes
    0  20190514       0    1    108  20190514  ...   26.9    0.0    4.1    1.6    0.0
    1  20190519   18000    1    108  20190519  ...   21.6   22.0    2.7    1.2    0.0
    2  20190521   50000    4    108  20190521  ...   23.8    0.0    5.9    2.9    0.0
    3  20190522  125000    7    108  20190522  ...   26.5    0.0    5.4    2.4    0.0
    4  20190523  222500   13    108  20190523  ...   29.2    0.0    3.5    1.7    0.0
    
    [5 rows x 12 columns]
              YMD      AMT  CNT  stnId        tm  ...  maxTa  sumRn  maxWs  avgWs  ddMes
    323  20200424  1092500   51    108  20200424  ...   14.3    0.0    8.2    3.9    0.0
    324  20200425   672500   34    108  20200425  ...   17.1    0.0    7.8    3.9    0.0
    325  20200426  1123500   55    108  20200426  ...   19.0    0.0    6.5    3.2    0.0
    326  20200427   819500   45    108  20200427  ...   18.3    0.0    5.5    2.8    0.0
    327  20200428   950500   45    108  20200428  ...   19.9    0.0    5.5    3.0    0.0
    
    [5 rows x 12 columns]
    328
    
    Index(['YMD', 'AMT', 'CNT', 'stnId', 'tm', 'avgTa', 'minTa', 'maxTa', 'sumRn',
           'maxWs', 'avgWs', 'ddMes'],
          dtype='object')
            YMD    AMT  maxTa  sumRn
    0  20190514      0   26.9    0.0
    1  20190519  18000   21.6   22.0
    2  20190521  50000   23.8    0.0
    count    328.000000
    mean      18.597866
    std       10.163039
    min       -4.900000
    25%        9.375000
    50%       19.350000
    75%       27.800000
    max       36.800000
    Name: maxTa, dtype: float64
    C:\Users\JEONGYEON\Desktop\Python\Python\pro1\pack8anal2\anova3.py:42: SettingWithCopyWarning: 
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead
    
    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      data['Ta_gubun'] = pd.cut(data.maxTa, bins = [-5, 8, 24, 37], labels = [0,1,2]) # 3개의 구간으로 나눴다.
    YMD         0
    AMT         0
    maxTa       0
    sumRn       0
    Ta_gubun    0
    dtype: int64
    [2, 1, 0]
    Categories (3, int64): [0 < 1 < 2]
    [1050500  770000 1054500  969000 1061500]
    [ 18000  50000 274000 203000 381500]
    [     0 125000 222500 209000 302000]
    9.28938415079017e-09
    1.198570472122961e-28
    1.4133139103478243e-13
    0.039002396565063324
    온도별 매출액 평균
         AMT Ta_gubun
    0      0        2
    1  18000        1
                       AMT
    Ta_gubun              
    0         1.032362e+06
    1         8.181069e+05
    2         5.537109e+05
                       AMT
    Ta_gubun              
    0         1.032362e+06
    1         8.181069e+05
    2         5.537109e+05
    [[    0     2]
     [18000     1]
     [50000     1]]
    
    F_onewayResult(statistic=99.1908012029983, pvalue=2.360737101089604e-34)
    KruskalResult(statistic=132.7022591443371, pvalue=1.5278142583114522e-29)
         Source  ddof1     ddof2           F         p-unc       np2
    0  Ta_gubun      2  189.6514  122.221242  7.907874e-35  0.379038
           Multiple Comparison of Means - Tukey HSD, FWER=0.05       
    =================================================================
    group1 group2   meandiff   p-adj    lower        upper     reject
    -----------------------------------------------------------------
         0      1 -214255.4486   0.0  -296755.647 -131755.2503   True
         0      2 -478651.3813  -0.0 -561484.4539 -395818.3088   True
         1      2 -264395.9327  -0.0 -333326.1167 -195465.7488   True
    -----------------------------------------------------------------

    정규성, 등분산성을 만족하지 못 할때 사용할 함수도 내용에 들어있다.

     

     

     

    데이터 분포 시각화

     

    사후검정 시각화

     

     

    댓글

Designed by Tistory.