귀무가설(영가설, 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

11. Ajax

12. Ajax + DB

13. Join

 


11. Ajax

 : ajax 송부한 데이터에 문자열 더하여 수신 받기.

 : ajax 요청하여 수신 받은 데이터 출력하기.

 

 = django_test10_ajax

 * settings

INSTALLED_APPS = [
    
    ...
    
    'myajaxapp',
]

 => application 연결

 

 * urls

from django.contrib import admin
from django.urls import path
from myajaxapp import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.indexFunc),
    path('startajax', views.func1),
    path('goajax', views.func2),
]

 => url -> function 연결

     url '' -> indexFunc

     url 'startajax' -> func1

     url 'goajax' -> func2

 

 

 * views

from django.shortcuts import render
import json
from django.http.response import HttpResponse

lan = {
    'id':111,
    'name':'파이썬',
    'history':[
        {'date':'2021-2-12','exam':'basic'},
        {'date':'2021-2-22','exam':'django'},
    ]
}

def test(): # json encoding/decoding
    print(type(lan)) # dict
    jsonString  = json.dumps(lan)
    jsonString  = json.dumps(lan, indent = 4) # 들어쓰기
    print(jsonString)
    #{"id": 111, "name": "\ud30c\uc774\uc36c", 
    #"history": [{"date": "2021-2-12", "exam": "basic"}, {"date": "2021-2-22", "exam": "django"}]}
    print(type(jsonString)) # str
    
    print('----------------------------------------------------------')
    
    dic = json.loads(jsonString)
    print(dic)
    print(type(dic)) # dict
    print(dic['name'])
    for h in dic['history']:
        print(h['date'], h['exam'])
    #2021-2-12 basic
    #2021-2-22 django
    
def indexFunc(request):
    test()
    return render(request,'abc.html')
	
    ...

 => import jason

 => json.dumps(data, indent = 들여쓰기) : json encoding. python object(Dict, List, Tuple..)를 문자열로 변경하는 작업

 => json.loads(data) : json decoding. 문자열을 python object(Dict, List, Tuple..)로 변경하는 작업

 => indexFunc() -> abc.html

 

 * abc.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
$(document).ready(function(){
	$("#btn1").click(function(){
		let msg = $("#txtMsg").val()
		$("#showData").empty();
		$.ajax({
			url:'startajax',
			type:'get',
			data:{'msg':msg}, /* msg=msg */
			dataType:'json',
			success:function(data){
				let str = '';
				for(let k in data){
					let str = k + '<br>' + data[k];
				}
				str += "<br><b>"+data['key']+"</b>";
				$("#showData").html(str);
			},
			error:function(){
				$("#showData").text("에러");
			}
		});
	});
	
	$("#btn2").click(function(){
		//$("#showData2").text("<i>1</i>"); // <i> 그대로 출력
		$("#showData2").html("<i>1</i>");
		$.ajax({
			url:'goajax',
			type:'get',
			dataType:'json',
			success:function(data){
				//alert(data);
				let str = '';
				$.each(data, function(ind, entry){ //jquery 반복문
					str += entry['name'] + ', ' + entry['age'] + '<br>';
				});
				$("#showData2").html(str);
			},
			error:function(){
				$("#showData2").text("에러");
			}
		});
	});
});
</script>
</head>
<body>
<h2>Ajax test</h2>
자료입력 : <input type="text" id="txtMsg" value="홍길동">
<button id="btn1">버튼1 클릭</button>
<br>
<div id="showData">실습결과1</div>
<hr>
<button id="btn2">버튼2 클릭</button>
<br>
<div id="showData2">실습결과2</div>
</body>
</html>

$.ajax({

    url:'요청명',

    type:'get/post',

    dataType:'json',

    success:function(x){

        // 성공 시 실행문

    }

    error:function(){

        // 에러 발생 시 실행문

    }

});

=> ajax 처리

 

$.each(x, function(idx, entry){

    // for entry in x: 과 동일

    // 반복문

});

 => json 반복문

 * views

...

import time
def func1(request):
    msg = request.GET['msg']
    #print(msg) # 홍길동
    time.sleep(1);
    context = {'key':msg + ' ajax 요청 처리'} # dict - 홍길동 ajax 요청 처리
    return HttpResponse(json.dumps(context), content_type="application/json") # dict -> str

def func2(request):
    datas = [
        {'name' : '고길동', 'age':25},
        {'name' : '김길동', 'age':27},
        {'name' : '나길동', 'age':28},
    ]
    return HttpResponse(json.dumps(datas), content_type="application/json")

 => request.GET['msg'] : 요청의 'msg' key의 값을 get.

 => HttpResponse(json.dumps(context), content_type="application/json") : context를 dict 타입에서 str로 변환 후

       json형식의 str을 send.


12. Ajax + DB

 : ajax 요청 시 DB의 직원 테이블 data 조회하여 출력하기.

 

 = django_test11_ajax

 => create application - myajax

 

 * settings

...

INSTALLED_APPS = [
    
    ...
    
    'myajax',
]

...

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

...

 => application 연결.

 => DB 설정

 

 

 * anaconda prompt

cd C:\work\psou\django_test11_ajax
python manage.py inspectdb > aaa.py

 

 

 * models

from django.db import models

# Create your models here.
class Sangdata(models.Model):
    code = models.IntegerField(primary_key=True)
    sang = models.CharField(max_length=20, blank=True, null=True)
    su = models.IntegerField(blank=True, null=True)
    dan = models.IntegerField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'sangdata'

 => aaa.py의 사용할 table을 models.py에 복사 붙여넣기. (제작된 Table을 Django 형식으로 자동 생성)

 

 Make migrations - myajax

 Migrate

 

 

 * urls

from django.contrib import admin
from django.urls import path
from myajax import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.MainFunc),
    path('list', views.ListFunc),
    path('calldb', views.ListDbFunc),
]

 => url -> function 연결.

 => url '' -> MainFunc()

 => url 'list' -> ListFunc()

 => url 'calldb' -> ListDbFunc()

 

 

 * views

from django.shortcuts import render
from myajax.models import Sangdata
from django.http.response import HttpResponse
import json

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

def ListFunc(request):
    return render(request, 'list.html')

def ListDbFunc(request):
    sdata = Sangdata.objects.all() # db sangdata 전체 읽기
    datas = []
    for s in sdata:
        #print(s.code)
        dict ={'code':s.code, 'sang':s.sang, 'su':s.su,'dan':s.dan}
        datas.append(dict)
    #print(datas)
    #[{'code': 1, 'sang': '장갑', 'su': 3, 'dan': 10000},
    # {'code': 2, 'sang': '벙어리장갑', 'su': 2, 'dan': 12000},
    # {'code': 3, 'sang': '가죽장갑', 'su': 10, 'dan': 50000}, 
    # {'code': 4, 'sang': '가죽점퍼', 'su': 5, 'dan': 650000}, 
    # {'code': 6, 'sang': '신상', 'su': 11, 'dan': 3000}, 
    # {'code': 7, 'sang': '아메리카노', 'su': 2, 'dan': 1}, 
    # {'code': 8, 'sang': '가방', 'su': 22, 'dan': 300}]
    return HttpResponse(json.dumps(datas), content_type='application/json')

 => MainFunc() -> main.html

 => ListFunc() -> list.html

 => ListDbFunc() : db data 읽은 후 json data send.(dict -> list -> str로 변환)

 

 

 * main.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>메인</h2>
<a href="/list">상품 보기</a>
</body>
</html>

 

 * list.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="https://code.jquery.com/jquery-latest.js"></script>

<script type="text/javascript">
$(document).ready(function(){
	$("#btnOk").click(function(){
		$("#showData").empty();
		
		$.ajax({
			url:'calldb',
			type:'get',
			dataType:'json',
			success:function(data){
				//alert(data);
				let str = "<table border='1'>";
				str += "<tr><th>코드</th><th>상품명</th><th>수량</th><th>단가</th></tr>";
				let count = 0;
				$.each(data, function(ind, entry){
					str += "<tr>";
					str += "<td>" + entry['code'] + "</td>";
					str += "<td>" + entry['sang'] + "</td>";
					str += "<td>" + entry['su'] + "</td>";
					str += "<td>" + entry['dan'] + "</td>";
					str += "</tr>";
					count += 1;
				});
				
				str += "</table>";
				$("#showData").append(str);
				$("#showData").append("건수 : "+count);
			},
			errorLfunction(){
				$("#showData").text("로딩 실패");
			}
		});
	});
});
</script>

</head>
<body>
<h2>상품 목록</h2>
<button id="btnOk">상품자료 출력(Ajax)</button><br><br>
<div id="showData"></div>
<hr>
</body>
</html>

 => button click 시 ajax로 'calldb' 요청명 send 후 성공 시 table 형태로 조회된 DB 데이터 출력.


13. Join

 * views

SearchJikwonFunc(request):
    jikwon_jik = request.GET["jikwon_jik"]
    jikwonList = Jikwon.objects.extra(select={'buser_name':'buser_name'}, tables=['Buser'],
    where =['Buser.buser_no=Jikwon.buser_num']).filter(jikwon_jik = jikwon_jik)
    data = []
    for j in jikwonList:
        dict ={}
        dict['jikwon_no'] = j.jikwon_no
        dict['jikwon_name'] = j.jikwon_name
        dict['buser_name'] = j.buser_name
        data.append(dict)
    print(data)
    return HttpResponse(json.dumps(data), content_type = "application/json")

0. Django

1. 환경구축

2. 외부파일 사용하기

3. url 연결

4. session


0. Django : 파이썬 웹 제작 프레임워크

model, template, view Pattern의 프로그램 작성

(model, view, controller과 대응)

 

1. 환경구축

Django 설치

 anaconda prompt 접속 후 명령어 입력

pip install Django==3.1.6

 

Django 프로젝트 생성

① 명령어 창 사용

anaconda prompt 접속 후 명령어 입력

cd C:\work\psou
django-admin startproject django_ex

explorer창 - import - General - Existing Projects into Workspace - [Brows] 경로 설정, [Copy projects into workspace] Check

 

서버 실행

cd C:\work\psou\django_ex
python manage.py migrate
type db.sqlite3
python manage.py runserver

서버실행(ip, port설정)

cd C:\work\psou\django_test1
python manage.py runserver 7777
python manage.py runserver 192.168.0.3:7777

 

server port 변경

C:\anaconda3\Lib\site-packages\django\core\management\commands\runserver.py

default_port = '80'
=> port 번호 변경

서버 종료 : ctrl + c 두번

 

 

② 이클립스 사용

 - [File] - [New] - [other] - [PyDev Project] - name입력, 3.8 선택, python 선택 - finish
 - explorer창 - project 오른쪽 클릭 - Django - Migrate

 - explorer창 - project 오른쪽 클릭 - Django - Create application - myapp
 - explorer창 - project 오른쪽 클릭 - Run as - PyDev
 - http://127.0.0.1:8000/ 접속


2. 외부파일 사용하기

 = django_test1

 * settings.py : 설정

...

ALLOWED_HOSTS = ['*']

...

INSTALLED_APPS = [
	...
    
    'myapp',
]

...

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

STATICFILES_DIRS = (   os.path.join(BASE_DIR, 'static'), ) : base경로의 static folder의 외부파일 불러올 수 있도록 연결.

 

 * urls.py : 모든 클라이언트의 요청을 받음

from django.contrib import admin
from django.urls import path
from myapp import views

urlpatterns = [
    path('admin/', admin.site.urls),
    
    path('', views.index),
    path('hello', views.hello_func),
    path('hello_tem', views.hello_template),
    path('world', views.world_func)
]

 path('url명', views.메소드명) : 요청명 연결

 

 * views.py : 요청에 대한 기능 구현

from django.shortcuts import render
from django.http.response import HttpResponse

# Create your views here.
def index(request):
    return HttpResponse("기본요청 처리")

def hello_func(request):
    msg = '장고 '
    ss = "<html><body>장고프로젝트 작성 메세지 : %s</body></html>"%msg
    return HttpResponse(ss)

def hello_template(request):
    mymsg = '홍길동'
    return render(request, 'show.html',{'msg':mymsg})

def world_func(request):
    return render(request, 'disp.html')

HttpResponse(응답 메시지) : Http 응답 메시지 send.

render(request, '연결페이지.html', {'key':value, ... }, ... ) : 연결페이지에 dict타입 정보 send

 * show.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
hi {{msg}} &lt;- 장고의 template 변수 태그
<br>
<a href="world">world 문서</a>
</body>
</html>

 {{key}} : dict타입 key의 value 값 출력

 * disp.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel='stylesheet' type='text/css' href='/static/css/test.css'>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="/static/js/test.js"></script>
<script type="text/javascript">
/*
window.onload = function(){
	alert("good");
}
 */
$(document).ready(function(){
	//alert("nice");
	$("#myImg").click(function(){
		abc();
	});
});

 
</script>
</head>
<body>
<span style="color: #ff0000; font-size: 24px;">성공</span>
<br>
<b>자원관리는 static</b><strong>폴더 </strong>사용
<br>
<img src = "/static/images/pic.png" id="myImg" />
</body>
</html>

 * test.js

function abc(){
	alert("test");
	history.back();
}

history.back() : 뒤로가기 수행


3. url 연결

 - Function views 방법
 - Class-base views 방법
 - Including another URL conf 방법

 

 = django_test2

 * settings.py

INSTALLED_APPS = [
    'gpapp',
]

 

 * urls.py(django_test2)

from django.contrib import admin
from django.urls import path
from gpapp import views
from gpapp.views import CallView
from django.urls.conf import include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.MainFunc, name='MainFunc'), # Function views 방법
    path('gpapp/callget', CallView.as_view()), # Class-base views 방법
    path('sangpum/', include('gpapp.urls')),   # Including another URLconf 방법
    
]

path('url명', views.메소드명) : 해당 url이 수신 시 view.py의 해당 메소드 실행.

path('url명', 클래스명.as_view()) : 해당 url 수신 시 해당 클래스 실행.

path('url명', include('application명.urls')) : 해당 url이 포함됨 url 수신 시 해당 application의 urls 파일에서 나머지 url 연결하여 실행. 

 

 * views

from django.shortcuts import render
from django.views.generic.base import TemplateView

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

class CallView(TemplateView):
    template_name = "callget.html"
    
def InsertFunc(request):
    #return render(request, "insert.html") # get/post 모두 처리
    if request.method == 'GET':
        print('GET 요청')
        return render(request, "insert.html")
    elif request.method == 'POST':
        print('POST 요청')
        name = request.POST.get("name")
        name = request.POST.["name"]
        return render(request,"list.html", {"name":name})
    else:
        print('요청 에러')

def SelectFunc(request):
    pass

def UpdateFunc(request):
    pass

request.method : 요청의 method를 get한다. ('GET', 'POST', ... )

request.GET.get('key값') : GET 요청에서 key의 value를 get한다.

request.POST.get('key값') : POST 요청에서 key의 value를 get한다.

 

 * index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
두번째 프로젝트 메인화면
<p/>
GET/POST 연습<br>
<a href="/gpapp/callget">callget 파일 요청 (get 방식)</a>
</body>
</html>

 

 * callget.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
GET/POST 연습<br>
<a href="/sangpum/insert">자료입력</a><br>
<a href="/sangpum/select">자료보기</a><br>
<a href="/sangpum/update">자료수정</a><br>
</body>
</html>

 

 * urls.py(gpapp)

# 메인 urls가 각 app에 처리 위임
from django.urls import path
from gpapp import views

urlpatterns = [
    path('insert', views.InsertFunc),
    path('select', views.SelectFunc),
    path('update', views.UpdateFunc),
]

 urls.py(django_test2)  ->  urls.py(gpapp)  -> views.py  -> insert.html  -> urls.py(django_test2)  ->  urls.py(gpapp)  -> views.py  ->list.html

 

 * insert.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
자료입력<p/>
<form action="/sangpum/insert" method="post">{% csrf_token %}<!-- 해킹 방지 -->
이름 : <input type="text" name="name">
<input type="submit" value="등록 확인">
</form>
</body>
</html>

{% csrf_token %} : 해킹방지 코드

 

 * list.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
결과 출력 : {{name}} {{123}} {{'문자열'}} {#주석#}
</body>
</html>


4. session

 = django_test3_session

 * settings

INSTALLED_APPS = [
    ...
    'sessionapp'
]

 

 * urls

from django.contrib import admin
from django.urls import path
from sessionapp import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.mainFunc),       # 1
    path('setos', views.setosFunc), # 2
    path('shows', views.showsFunc), # 3
]

 

 * views

from django.shortcuts import render
from django.http.response import HttpResponseRedirect

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

def setosFunc(request): # 2
    if "favorite_os" in request.GET:
        print(request.GET['favorite_os'])
        request.session['f_os'] = request.GET["favorite_os"] # f_os 라는 키로 세션에 저장
        return HttpResponseRedirect('/shows') # 클라이언트를 통해서 shows 요청을 발생
    else:
        print('a')
        return render(request, 'setos.html')
    
def showsFunc(request): # 3
    context = {} # dict type 변수 생성
    
    if "f_os" in request.session:
        context['f_os'] = request.session['f_os'] # request.session.get('f_os')
        context['message'] = "선택된 운영체제 %s"%request.session['f_os']
    else:
        context['f_os'] = None
        context['message'] = "운영체제를 선택하지않았습니다."
        
    request.session.set_expiry(5); # session 유효 기간 5초 설정 
    
    return render(request, 'show.html', context)

 

HttpResponseRedirect('url명') : 클라이언트를 통해서 url요청명을 send.

 => session

request.session['key'] = value : session에 key값에 value값 set.

value = request.session.get('key값') : session에 key값에 value값 get.

value = request.session['key값'] : session에 key값에 value값 get.

request.session.set_expiry(초) : session 유효 시간 초 단위로 설정.

 

 * main.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
메인화면<p/>
session 연습 : 세션이란 일정시간 동안 같은 사용자로 부터 들어오는 여러 가지 요구들을 하나의 상태를 보고 그 상태를 일정하게 유지 시킨 기술.
클라이언트와 서버 사이의 연결이 유지되는 것 처럼 하기 위해 클라이언트의 정보를 서버 컴퓨터의 일정 공간을 확보해 정보를 기억시킬 수 있다.
<br>
<a href="/setos/">운영체제 선택하기</a>
</body>
</html>

 

 * setos.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>2. 세션 이해하기</h2>
<p>운영체제 선택</p>
<a href="/setos?favorite_os=window">윈도우</a><br>
<a href="/setos?favorite_os=mac">mac</a><br>
<a href="/setos?favorite_os=linux">리눅스</a><br>
</body>
</html>

=> url : setos, key : favorite_os, value : window, mac, linux

 

 * show.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>3. 세션 결과보기</h2>
<p>반환된 context의 message : {{message}}</p>
<p>반환된 context의 f_os : {{f_os}}</p>
<p>session의 f_os 값 직접 출력: {{request.session.f_os}}</p>
<a href="/setos">운영체제 다시 선택</a>
<a href="/">main page</a>
</body>
</html>

 

+ Recent posts

1