이항검정

 : 결과가 두 가지 값을 가지는 확률변수의 분포를 판단하는데 효과적
 : 이산변량을 대상으로 한다.

형식 : stats.binom_test() : 명목척도의 비율을 바탕으로 이항분포 검정

 

 귀무가설 : 직원을 대상으로 고객 대응 교육 후 고객 안내 서비스 만족율이 80%다.
 대립가설 : 직원을 대상으로 고객 대응 교육 후 고객 안내 서비스 만족율이 80%가 아니다.

 

 * binom.py

import pandas as pd
import scipy.stats as stats
from pandas.core.reshape.pivot import crosstab

data = pd.read_csv("../testdata/one_sample.csv")
print(data.head(3))
print()
'''
   no    gender  survey time
0   1         2       1  5.1
1   2         2       0  5.2
2   3         2       1  4.7
'''

ctab = crosstab(index=data['survey'], columns = 'count')
ctab.index = ['불만족', '만족']
print(ctab)
'''
col_0  count
불만족       14
만족       136
'''
print('양측 검정(기존 80% 만족율 기준 검증을 실시) : 방향성이 없다.')
x = stats.binom_test([136, 14], p = 0.8, alternative="two-sided")
print(x)

stats.binom_test(x, p = , alternative="two-sided") : 양측 검정

 p-value : 0.00067 < 0.05 이므로 귀무가설 기각.
 대립가설 : 직원을 대상으로 고객 대응 교육 후 고객 안내 서비스 만족율이 80%가 아니다.
 양측검정에서는 크다, 작다로 방향성으로 제시 하지않는다.

 

print('\n양측 검정(기존 80% 불만족율 기준 검증을 실시) : 방향성이 없다.')
x = stats.binom_test([14, 136], p = 0.2, alternative="two-sided")
print(x)

stats.binom_test(x, p = , alternative="two-sided") : 양측 검정(조건 반전)

 p-value : 0.00067 < 0.05 이므로 귀무가설 기각.

 

print('\n단측 검정(기존 80% 만족율 기준 검증을 실시) : 방향성이 있다.')
x = stats.binom_test([136, 14], p = 0.8, alternative="greater")
print(x)# p-value : 0.000317 < 0.05 이므로 귀무가설 기각.

stats.binom_test(x, p = , alternative="greater") : 단측검정

p-value : 0.000317 < 0.05 이므로 귀무가설 기각.

 

print('\n단측 검정(기존 80% 불만족율 기준 검증을 실시) : 방향성이 있다.')
x = stats.binom_test([14, 136], p = 0.2, alternative="less")
print(x)# p-value : 0.000317 < 0.05 이므로 귀무가설 기각.

stats.binom_test(x, p = , alternative="less") : 단측검정(조건 반전)

 p-value : 0.000317 < 0.05 이므로 귀무가설 기각.

 


비율 검정

: 집단의 비율이 어떤 특정한 값과 같은지를 검정

 

 * one-sample
 a회사에는 100명 중 45명이 흡연을 한다. 국가통계에서는 국민 흡연율은 35%라고 한다. 비율의 동일여부를 검정하라.


 귀무가설 : a회사의 흡연율과 국민 흡연율의 비율은 같다.
 대립가설 : a회사의 흡연율과 국민 흡연율의 비율은 다르다.

import numpy as np
from statsmodels.stats.proportion import proportions_ztest

count = np.array([45])
nobs = np.array([100])
val = 0.35

z, p = proportions_ztest(count=count, nobs=nobs, value=val)
print('z : {}, p : {}'.format(z, p)) # z : [2.01007563], p : [0.04442318]

proportions_ztest(count=count, nobs=nobs, value=val) : 비율 검정.

p-value : 0.04442318 < 0.05 이므로 귀무가설 기각.
대립가설 : a회사의 흡연율과 국민 흡연율의 비율은 다르다.

 

 

 * two-sample
a회사 직원 300명중 100명이 햄버거를 취식, b회사 직원 400명중 170명이 햄버거를 취식시 두 집단의 햄버거 취식비율의 차이 검정.


 귀무 가설 : 차이가 없다.
 대립 가설 : 차이가 있다.

count = np.array([100, 170])
nobs = np.array([300, 400])

z, p = proportions_ztest(count=count, nobs=nobs, value=0)
print('z : {}, p : {}'.format(z, p)) # z : -2.4656701201792273, p : 0.013675721698622408

proportions_ztest(count=count, nobs=nobs, value=0) : 비율 검정.

 p-value : 0.013675 < 0.05 이므로 귀무가설 기각.
 대립 가설 : 차이가 있다.

'BACK END > Deep Learning' 카테고리의 다른 글

[딥러닝] 선형회귀  (0) 2021.03.10
[딥러닝] 공분산, 상관계수  (0) 2021.03.10
[딥러닝] ANOVA  (0) 2021.03.08
[딥러닝] T 검정  (0) 2021.03.05
[딥러닝] 카이제곱  (0) 2021.03.04

 

귀무가설(영가설, H0) : 변함없는 생각.
대립가설(연구가설, H1) : 귀무가설에 반대하는 새로운 의견. 연구가설.

 

점추정 : 단일값을 모집단에서 샘플링 
구간추정 : 범위를 모집단에서 샘플링. 신뢰도 상승.

 

가설검증

① 분포표 사용 -> 임계값 산출
임계값이 critical value 왼쪽에 있을 경우 귀무가설 채택/기각.


② p-value 사용(tool에서 산출). 유의확률. (경험적 수치)
p-value > 0.05(a)  : 귀무가설 채택. 우연히 발생할 확률이 0.05보다 낮아 연구가설 기각.
p-value < 0.05(a)  : 귀무가설 기각. 좋다
p-value < 0.01(a)  : 귀무가설 기각. 더 좋다
p-value < 0.001(a) : 귀무가설 기각. 더 더 좋다 => 신뢰 할 수 있다.

 

척도에 따른 데이터 분석방법

독립변수 x 종속변수 y 분석 방법
범주형 범주형 카이제곱 검정(교차분석)
범주형 연속형 T 검정(범주형 값 2개 : 집단 2개 이하),
ANOVA(범주형 값 3개 : 집단 2개 이상)
연속형 범주형 로지스틱 회귀 분석
연속형 연속형 회귀분석, 구조 방정식

 

 

1종 오류 : 귀무가설이 채택(참)인데, 이를 기각.
2종 오류 : 귀무가설이 기각(거짓)인데, 이를 채택.

 

 

분산(표준편차)의 중요도 - 데이터의 분포

 * temp.py

import scipy.stats as stats
import numpy as np
import matplotlib.pyplot as plt

centers = [1, 1.5, 2] # 3개 집단
col = 'rgb'
data = []
std = 0.01 # 표준편차 - 작으면 작을 수록 응집도가 높다.

for i in range(len(centers)):
    data.append(stats.norm(centers[i], std).rvs(100)) # norm() : 가우시안 정규분포. rvs(100) : 랜덤값 생성.
    plt.plot(np.arange(100) + i * 100, data[i], color=col[i])   # 그래프
    plt.scatter(np.arange(100) + i * 100, data[i], color=col[i]) # 산포도
plt.show()
print(data)

import scipy.stats as stats

stats.norm(평균, 표준편차).rvs(size=크기, random_state=seed) : 가우시안 정규 분포 랜덤 값 생성.

import matplotlib.pyplot as plt

plt.plot(x, y) : 그래프 출력.

plot - std : 0.01

 

plot - std : 0.1
scatter - std : 0.01

 

scatter - std : 0.1

 

교차분석 (카이제곱) 가설 검정

  • 데이터나 집단의 분산을 추정하고 검정할때 사용
  • 독립변수, 종속변수 : 범주형
  • 일원 카이제곱 : 변수 단수. 적합성(선호도) 검정. 교차분할표 사용하지않음.
  • 이원 카이제곱 : 변수 복수. 독립성(동질성) 검정. 교차분할표 사용.
  • 절차 : 가설 설정 -> 유의 수준 결정 -> 검정통계량 계산 -> 귀무가설 채택여부 판단 -> 검정결과 진술
  • 수식 : sum((관찰빈도 - 기대빈도)^2 / 기대빈도)

 

수식에 따른 카이제곱 검정

 * chi1.py

import pandas as pd

data = pd.read_csv('../testdata/pass_cross.csv', encoding='euc-kr') # csv 파일 읽기
print(data.head(3))
'''
   공부함  공부안함  합격  불합격
0    1     0   1    0
1    1     0   1    0
2    0     1   0    1
'''
print(data.shape) # (행, 열) : (50, 4)

귀무가설 : 벼락치기와 합격여부는 관계가 없다.
대립가설 : 벼락치기와 합격여부는 관계가 있다.

print(data[(data['공부함'] == 1) & (data['합격'] == 1)].shape[0]) # 18 - 공부하고 합격
print(data[(data['공부함'] == 1) & (data['불합격'] == 1)].shape[0]) # 7 - 공부하고 불합격

빈도표

data2 = pd.crosstab(index=data['공부안함'], columns=data['불합격'], margins=True)
'''
불합격     0   1
공부안함        
0     18   7
1     12  13
'''
data2.columns = ['합격', '불합격', '행 합']
data2.index = ['공부함', '공부안함', '열 합']
print(data2)
'''
             합격  불합격  행 합
공부함    18    7   25
공부안함  12   13   25
열 합      30   20   50
'''

 

기대도수  = 각 행 합 * 각 열 합 / 총합

'''
        합격  불합격  행 합
공부함    15    10   25
공부안함  15   10   25
열 합      30   20   50
'''

카이제곱

ch2 = ((18 - 15) ** 2 / 15) + ((7 - 10) ** 2 / 10) + ((12 - 15) ** 2 / 15) + ((13 - 10) ** 2 / 10)
print('카이제곱 :', ch2) # 3.0

 

자유도(df) = (행 개수 - 1) * (열 개수 - 1) = (2-1) * (2-1) = 1

 

카이제곱 분포표에서 확인한 임계치 : 3.84

math100.tistory.com/45

 

카이제곱분포표 보는 법

카이제곱분포는 t분포와 마찬가지로 확률을 구할 때 사용하는 분포가 아니라, 나중에 신뢰구간이랑 가설검정에서 사용하는 분포다. 그래서 카이제곱분포표는 “t분포표 보는 법”과 얼추 비슷

math100.tistory.com

 

# 결론1 : 카이제곱  3 < 유의수준 3.84 => 귀무가설 채택 내에서 존재하여 귀무가설 채택.
( 귀무가설 : 벼락치기와 합격여부는 관계가 없다. )

 

전문가 제공 모듈 사용(chi2_contingency())

import scipy.stats as stats
chi2, p, ddof, expected = stats.chi2_contingency(data2)
print('chi2\t:', chi2)
print('p\t:', p)
print('ddof\t:', ddof)
print('expected :\n', expected)
'''
chi2    : 3.0
p    : 0.5578254003710748
ddof    : 4
expected :
 [[15. 10. 25.]
 [15. 10. 25.]
 [30. 20. 50.]]
'''

# 결론2 : 유의확률(p-value) 0.5578 > 유의수준 0.05 => 귀무가설 채택.
( 귀무가설 : 벼락치기와 합격여부는 관계가 없다. )

 

stats.chi2_contigency(데이터) : 이원카이제곱 함수


일원카이제곱(chisquare())

: 관찰도수가 기대도수와 일치하는 지를 검정하는 방법
: 종류 적합도 선호도 검정 - 범주형 변수가 한 가지로 관찰도수가 기대도수에 일치하는지 검정한다

 

적합도검정

: 자연현상이나 각종 실험을 통해 관찰되는 도수들이 귀무가설 하의 분포 범주형 자료의 각 수준별 비율 에 얼마나 일치하는 가에 대한 분석을 적합도 검정이라 한다
: 관측값들이 어떤 이론적 분포를 따르고 있는지를 검정으로 한 개의 요인을 대상으로 함

 

<실습 : 적합도 검정>

주사위를 60 회 던져서 나온 관측도수 기대도수가 아래와 같이 나온 경우에 이 주사위는 적합한 주사위가 맞는가를 일원카이제곱 검정
으로 분석하자

주사위 눈금 1 2 3 4 5 6
관측도수 4 6 17 16 8 9
기대도수 10 10 10 10 10 10

 

귀무가설(영가설,  H0) : 기대빈도와 관찰빈도는 차이가 없다. 현재 주사위는 평범한 주사위다.
대립가설(연구가설, H1) : 기대빈도와 관찰빈도는 차이가 있다. 현재 주사위는 평범하지않은 주사위다.

 

변수 1개 : 주사위를 던진 횟수. 기대빈도와 관찰빈도의 차이를 확인. stats.chisquare(관찰빈도, 기대빈도)

 

 * chi2.py

import pandas as pd
import scipy.stats as stats

data = [4, 6, 17, 16, 8, 9] # 관찰빈도
result = stats.chisquare(data)
print(result)
# Power_divergenceResult(statistic=14.200000000000001, pvalue=0.014387678176921308)

data2 = [10, 10, 10, 10, 10, 10] # 기대빈도
result2 = stats.chisquare(data, data2)
print(result2)

print('통계량(x2) : %.5f, p-value : %.5f'%result)
# 통계량(x2) : 14.20000, p-value : 0.01439
# 통계량과 p-value는 반비례 관계.

 

# 결론 1 : p-value 0.01439 < 0.05 이므로 유의미한 수준(a=0.05)에서 귀무 가설 기각. 연구가설 채택.
( 대립가설 : 기대빈도와 관찰빈도는 차이가 있다. 현재 주사위는 평범하지않은 주사위다. )

 

# 결론 2 : df 5(N-1), 임계값 : 카이제곱 분포표를 참고시 11.07
statistic(x2) 14.200 > 임계값 11.07 이므로 귀무 가설 기각. 연구가설 채택.
( 대립가설 : 기대빈도와 관찰빈도는 차이가 있다. 현재 주사위는 평범하지않은 주사위다. )

관찰빈도와 기대빈도 사이에 유의한 차이가 있는 지 일원 카이제곱을 사용하여 검정

 

stats.chisquare(데이터) : 일원카이제곱 함수


<실습 : 선호도 분석>

5개의 스포츠 음료에 대한 선호도에 차이가 있는지 검정하기

 

귀무 가설 : 스포츠 음료에 대한 선호도 차이가 없다.
대립 가설 : 스포츠 음료에 대한 선호도 차이가 있다.

import numpy as np
data3 = pd.read_csv('../testdata/drinkdata.csv')
print(data3, ' ', sum(data3['관측도수']))
'''
  음료종류  관측도수
0   s1    41
1   s2    30
2   s3    51
3   s4    71
4   s5    61   254
'''
print(stats.chisquare(data3['관측도수']))
# Power_divergenceResult(statistic=20.488188976377952, pvalue=0.00039991784008227264)

# 결론 : pvalue 0.00039 < 유의수준 0.05 이기 때문에 귀무가설 기각. 대립가설 채택. 
( 대립 가설 : 스포츠 음료에 대한 선호도 차이가 있다. 향후 작업에 대한 참조자료로 이용. )


이원카이제곱 - 교차분할표 이용

: 두 개 이상의 변인 집단 또는 범주 을 대상으로 검정을 수행한다
분석대상의 집단 수에 의해서 독립성 검정과 동질성 검정으로 나뉜다

독립성 검정 : 두 변인의 관계가 독립인지 검정
동질성 검정 : 두 변인 간의 비율이 서로 동일한지를 검정

 

독립성 (관련성) 검정

- 동일 집단의 두 변인 학력수준과 대학진학 여부 을 대상으로 관련성이 있는가 없는가
- 독립성 검정은 두 변수 사이의 연관성을 검정한다

 

<실습 : 교육수준과 흡연율 간의 관련성 분석>

집단 2개 : 교육수준, 흡연율
귀무가설 : 교육수준과 흡연율 간에 관련이 없다. (독립이다)
대립가설 : 교육수준과 흡연율 간에 관련이 있다. (독립이 아니다)

 

 *chi3.py

import pandas as pd
import scipy.stats as stats
data = pd.read_csv('../testdata/smoke.csv')
print(data)
'''
     education  smoking
0            1        1
1            1        1
2            1        1
3            1        1
4            1        1
..         ...      ...
350          3        3
351          3        3
352          3        3
353          3        3
354          3        3
'''
print(data['education'].unique()) # [1 2 3]
print(data['smoking'].unique())   # [1 2 3]

 

교육 수준, 흡연인원를 이용한 교차표 작성

# education : 독립변수, smoking : 종속변수
ctab = pd.crosstab(index = data['education'], columns = data['smoking']) # 빈도수.
ctab = pd.crosstab(index = data['education'], columns = data['smoking'], normalize=True) # normalize : 비율
ctab.index = ['대학원졸', '대졸', '고졸']
ctab.columns = ['골초', '보통', '노담']
print(ctab)
'''
             골초  보통  노담
대학원졸  51  92  68
대졸       22  21   9
고졸       43  28  21
'''

pd.crosstab(index=, columns=) : 교차 테이블

 

이원 카이 제곱을 지원하는 함수

chi_result = [ctab.loc['대학원졸'], ctab.loc['대졸'], ctab.loc['고졸']]
chi, p, _, _ = stats.chi2_contingency(chi_result)
chi, p, _, _ = stats.chi2_contingency(ctab)

print('chi :', chi)    # chi : 18.910915739853955
print('p-value :', p)  # p-value : 0.0008182572832162924

# 결론 : p-value 0.0008 < 0.05 이므로 귀무가설 기각.
( 대립가설 : 교육수준과 흡연율 간에 관련이 있다. (독립이 아니다) )

 

stats.chi2_contigency(데이터) : 이원카이제곱 함수

 

야트보정

분할표의 자유도가 1인 경우는 x^2값이 약간 높게 계산된다. 그러므로 이에 하기 식으로 야트보정이라 한다.
x^2=∑(|O-E|-0.5)^2/E

 => 상기 함수는 자동으로 야트보정이 이루어진다.

 


 

<실습 : 국가전체와 지역에 대한 인종 간 인원수로 독립성 검정 실습>

두 집단 국가전체 national, 특정지역 la) 의 인종 간 인원수의 분포가 관련이 있는가

 

귀무가설 : 국가전체와 지역에 대한 인종 간 인원수는 관련이 없다. 독립적.
대립가설 : 국가전체와 지역에 대한 인종 간 인원수는 관련이 있다. 독립적이지 않다. 

 

national = pd.DataFrame(["white"] * 100000 + ["hispanic"] * 60000 + 
                         ["black"] * 50000 + ["asian"] * 15000 +["other"] * 35000)
la = pd.DataFrame(["white"] * 600 + ["hispanic"] * 300 + ["black"] * 250 + 
                  ["asian"] * 75 + ["other"] * 150)
print(national) # [260000 rows x 1 columns]
print(la)       # [1375 rows x 1 columns]

na_table = pd.crosstab(index = national[0], columns = 'count')
la_table = pd.crosstab(index = la[0], columns = 'count')
print(la_table)
'''
col_0     count
0              
asian        75
black       250
hispanic    300
other       150
white       600
'''
na_table['count_la'] = la_table['count'] # 칼럼 추가
print(na_table)

'''
col_0      count  count_la
0                         
asian      15000        75
black      50000       250
hispanic   60000       300
other      35000       150
white     100000       600
'''
chi, p, _, _ = stats.chi2_contingency(na_table)
print('chi :', chi)    # chi : 18.099524243141698
print('p-value :', p)  # p-value : 0.0011800326671747886

# 결론 : p-value : 0.0011 < 0.05 이므로 귀무가설 기각.
( 대립가설 : 국가전체와 지역에 대한 인종 간 인원수는 관련이 있다. 독립적이지 않다.)

 


이원카이제곱

동질성 검정

- 두 집단의 분포가 동일한가 다른 분포인가 를 검증하는 방법이다 두 집단 이상에서 각 범주 집단 간의 비율이 서로 동일한가를 검정하게 된다 두 개 이상의 범주형 자료가 동일한 분포를 갖는 모집단에서 추출된 것인지 검정하는 방법이다

 

<실습 1 : 교육방법에 따른 교육생들의 만족도 분석 - 동질성 검정>

 

 귀무가설 : 교육방법에 따른 교육생들의 만족도에 차이가 없다.
 대립가설 : 교육방법에 따른 교육생들의 만족도에 차이가 있다.

 

 * chi4.py

import pandas as pd
import scipy.stats as stats

data = pd.read_csv("../testdata/survey_method.csv")
print(data.head(6))
'''
   no  method  survey
0   1       1       1
1   2       2       2
2   3       3       3
3   4       1       4
4   5       2       5
5   6       3       2
'''
print(data['survey'].unique()) # [1 2 3 4 5] - survey 데이터 종류
print(data['method'].unique()) # [1 2 3]     - method 데이터 종류
# 교차표 작성
ctab = pd.crosstab(index=data['method'], columns=data['survey'])
ctab.columns = ['매우만족', '만족', '보통', '불만족', '매우불만족']
ctab.index = ['방법1', '방법2', '방법3']
print(ctab)
'''
     매우만족  만족  보통  불만족  매우불만족
방법1     5   8  15   16      6
방법2     8  14  11   11      6
방법3     8   7  11   15      9
'''
# 카이제곱
chi, p, df, ex = stats.chi2_contingency(ctab)
msg = "chi2 : {}, p-value:{}, df:{}"
print(msg.format(chi, p, df))
# chi2 : 6.544667820529891, p-value:0.5864574374550608, df:8

# 결론 : p-value 0.586 > 0.05 이므로 귀무가설 채택.
( 귀무가설 : 교육방법에 따른 교육생들의 만족도에 차이가 없다. )

 


<실습  : 연령대별 sns 이용률의 동질성 검정>

20대에서 40 대까지 연령대별로 서로 조금씩 그 특성이 다른 SNS 서비스들에 대해 이용 현황을 조사한 자료를 바탕으로 연령대별로 홍보 전략을 세우고자 한다. 연령대별로 이용 현황이 서로 동일한지 검정해 보도록 하자

 

 귀무가설 : 연령대별로 SNS 서비스 이용 현황에 차이가 없다(동질이다).
 대립가설 : 연령대별로 SNS 서비스 이용 현황에 차이가 있다(동질이 없다).

 

import pandas as pd
import scipy.stats as stats

data2 = pd.read_csv("../testdata/snsbyage.csv")
print(data2.head(), ' ', data2.shape)
'''
   age service
0    1       F
1    1       F
2    1       F
3    1       F
4    1       F   (1439, 2)
'''
print(data2['age'].unique())     # [1 2 3]
print(data2['service'].unique()) # ['F' 'T' 'K' 'C' 'E']

 

# 교차표 작성
ctab2 = pd.crosstab(index = data2['age'], columns = data2['service'])
print(ctab2)
'''
service    C   E    F    K    T
age                            
1         81  16  207  111  117
2        109  15  107  236  104
3         32  17   78  133   76
'''

 

# 카이제곱
chi, p, df, ex = stats.chi2_contingency(ctab2)
msg2 = "chi2 : {}, p-value:{}, df:{}"
print(msg2.format(chi, p, df))
# chi2 : 102.75202494484225, p-value:1.1679064204212775e-18, df:8

# 결론 : p-value 1.1679064204212775e-18 < 0.05 이므로 귀무가설 기각.
( 대립가설 : 연령대별로 SNS 서비스 이용 현황에 차이가 있다(동질이 없다) )

# 참고 : 상기 데이터가 모집단이었다면 샘플링을 진행하여 샘플링 데이터로 작업 진행.
sample_data = data2.sample(500, replace=True)

카이제곱 + Django

 = django_use02_chi(PyDev Django Project)

 

Create application - coffesurvey

 

 * settings

...

INSTALLED_APPS = [
    
    ...
    
    'coffeesurvey',
]

...

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', 
        'NAME': 'coffeedb',            # DB명 : db는 미리 작성되어 있어야 함.       
        'USER': 'root',                # 계정명 
        'PASSWORD': '123',             # 계정 암호           
        'HOST': '127.0.0.1',           # DB가 설치된 컴의 ip          
        'PORT': '3306',                # DBMS의 port 번호     
    }
}

 

* MariaDB

create database coffeedb;

use coffeedb;

create table survey(rnum int primary key auto_increment, gender varchar(4),age int(3),co_survey varchar(10));

insert into survey (gender,age,co_survey) values ('남',10,'스타벅스');
insert into survey (gender,age,co_survey) values ('여',20,'스타벅스');

 

 * anaconda prompt

cd C:\work\psou\django_use02_chi

python manage.py inspectdb > aaa.py

 

 * models

from django.db import models

# Create your models here.
class Survey(models.Model):
    rnum = models.AutoField(primary_key=True)
    gender = models.CharField(max_length=4, blank=True, null=True)
    age = models.IntegerField(blank=True, null=True)
    co_survey = models.CharField(max_length=10, blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'survey'

 

Make migrations - coffeesurvey

Migrate 

 

 * urls(django_use02_chi)

from django.contrib import admin
from django.urls import path
from coffeesurvey import views
from django.urls.conf import include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.Main), # url 없을 경우
    path('coffee/', include('coffeesurvey.urls')), # 위임
]

 

 * views

from django.shortcuts import render
from coffeesurvey.models import Survey

# Create your views here.
def Main(request):
    return render(request, 'main.html')

...

 

 * main.html

<body>
<h2>메인</h2>
<ul>
	<li>메뉴</li>
	<li>신제품</li>
	<li><a href="coffee/survey">설문조사</a></li>
</ul>
</body>

 * urls(coffeesurvey)

from django.urls import path
from coffeesurvey import views

urlpatterns = [
    path('survey', views.SurveyView), 
    path('surveyprocess', views.SurveyProcess),
]

 

 * views

...

def SurveyView(request):
    return render(request, 'survey.html')

 

 * survey.html

<body>
<h2>* 커피전문점에 대한 소비자 인식조사 *</h2>
<form action="/coffee/surveyprocess" method="post">{% csrf_token %}
<table>
	<tr>
		<td>귀하의 성별은?</td>
		<td>
			<label for="genM">남</label>
			<input type="radio" id="genM" name="gender" value="남" checked="checked">
			&nbsp
			<label for="genF">여</label>
			<input type="radio" id="genF" name="gender" value="여">
		</td>
	</tr>
	<tr>
		<td>귀하의 나이는?</td>
		<td>
			<label for="age10">10대</label>
			<input type="radio" id="age10" name="age" value="10" checked="checked">
			&nbsp
			<label for="age20">20대</label>
			<input type="radio" id="age20" name="age" value="20">
			&nbsp
			<label for="age10">30대</label>
			<input type="radio" id="age30" name="age" value="30">
			&nbsp
			<label for="age40">40대</label>
			<input type="radio" id="age40" name="age" value="40">
			&nbsp
			<label for="age50">50대</label>
			<input type="radio" id="age50" name="age" value="50">
		</td>
	</tr>
	<tr>
		<td>선호하는 커피전문점은?</td>
		<td>
			<label for="startbucks">스타벅스</label>
			<input type="radio" id="genM" name="co_survey" value="스타벅스" checked="checked">
			&nbsp
			<label for="coffeebean">커피빈</label>
			<input type="radio" id="coffeebean" name="co_survey" value="커피빈">
			&nbsp
			<label for="ediya">이디아</label>
			<input type="radio" id="ediya" name="co_survey" value="이디아">
			&nbsp
			<label for="tomntoms">탐앤탐스</label>
			<input type="radio" id="tomntoms" name="co_survey" value="탐앤탐스">
		</td>
	</tr>
	<tr>
		<td colspan="2">
		<br>
		<input type="submit" value="설문완료">
		<input type="reset" value="초기화">
	</tr>
</table>
</form>
</body>

 

* views

...

import pandas as pd
import scipy.stats as stats
import matplotlib.pyplot as plt

plt.rc('font', family="malgun gothic")

def SurveyProcess(request):
    InsertData(request)
    rdata = list(Survey.objects.all().values())
    # print(rdata) # [{'rnum': 1, 'gender': '남', 'age': 10, 'co_survey': '스타벅스'}, ... 
    
    df, crossTab, results = Analysis(rdata)
    
    # 시각화
    fig = plt.gcf()
    gen_group = df['co_survey'].groupby(df['coNum']).count()
    gen_group.index = ['스타벅스', '커피빈', '이디아', '탐앤탐스']
    gen_group.plot.bar(subplots=True, color=['red', 'blue'], width=0.5)
    plt.xlabel('커피샵')
    plt.ylabel('선호도 건수')
    plt.title('커피샵 별 선호건수')
    fig.savefig('django_use02_chi/coffeesurvey/static/images/co.png')
    
    return render(request, 'list.html', {'df':df.to_html(index=False), \
                                         'crossTab':crossTab.to_html(), 'results':results})
def InsertData(request): # 입력자료 DB에 저장
    if request.method == 'POST':
        Survey(
            gender = request.POST.get('gender'),
            age = request.POST.get('age'),
            co_survey = request.POST.get('co_survey')
            ).save()
            # 또는 SQL문을 직접 사용해도 무관.
def Analysis(rdata): # 분석
    df = pd.DataFrame(rdata)
    
    
    df.dropna() # 결측치 처리가 필요한 경우에는 진행. 이상치도 처리.
    df['genNum'] = df['gender'].apply(lambda g:1 if g =='남' else 2)
    df['coNum'] = df['co_survey'].apply(lambda c:1 if c =='스타벅스' \
        else 2 if c =='커피빈' else 3 if c =='이디아' else 4)
    print(df)
    '''
            rnum gender  age co_survey  genNum  coNum
    0      1      남   10      스타벅스       1      1
    1      2      여   20      스타벅스       2      1
    2      3      남   10      스타벅스       1      1
    3      4      남   10      스타벅스       1      1
    4      5      남   10      탐앤탐스       1      4
    5      6      남   40       커피빈       1      2
    6      7      남   10      스타벅스       1      1
    7      8      남   10      스타벅스       1      1
    8      9      남   10      스타벅스       1      1
    9     10      남   10      스타벅스       1      1
    10    11      남   10      스타벅스       1      1
    11    12      남   10      스타벅스       1      1
    '''
    
    # 교차 빈도표
    crossTab = pd.crosstab(index=df['gender'], columns=df['co_survey'])
    #crossTab = pd.crosstab(index=df['genNum'], columns=df['coNum'])
    print(crossTab)
    
    chi, pv, _, _ = stats.chi2_contingency(crossTab)
    
    if pv > 0.05:
        results = 'p값이 {}이므로 유의수준 0.05 <b>이상</b>의 값을 가지므로 <br> "
        +"성별에 따라 선호하는 커피브랜드에는 <b>차이가 없다.</b> (귀무가설 채택)'.format(pv)
    else:
        results = 'p값이 {}이므로 유의수준 0.05 <b>이하</b>의 값을 가지므로 <br> "
        +"성별에 따라 선호하는 커피브랜드에는 <b>차이가 있다.</b> (연구가설 채택)'.format(pv)
    
    return df, crossTab, results

 

 * list.html

<body>
<h2>* 커피전문점에 대한 소비자 인식 조사 결과 *</h2>

<a href="/">메인화면</a><br>
<a href="/coffee/survey">다시 설문조사 하기</a><br>
{% if df %}
	{{df|safe}}
{% endif %}<br>

{% if crossTab %}
	{{crossTab|safe}}
{% endif %}<br>

{% if results %}
	{{results|safe}}
{% endif %}<br>
<img src="/static/images/co.png" width="400" />
</body>

'BACK END > Deep Learning' 카테고리의 다른 글

[딥러닝] 선형회귀  (0) 2021.03.10
[딥러닝] 공분산, 상관계수  (0) 2021.03.10
[딥러닝] 이항검정  (0) 2021.03.10
[딥러닝] ANOVA  (0) 2021.03.08
[딥러닝] T 검정  (0) 2021.03.05

+ Recent posts

1