반응형
SMALL

# wikidocs.net을 보고 요약 및 정리

머신러닝


사람에게 사진을 보고 고양이와 강아지를 구분하라고 하면 쉽지만 기계는 그렇지 않다. 기계는 이미지를 분류하기 위해 이미지의 shape이나 edge를 판별하고 찾아 알고리즘화를 하려고 하지만 한계는 존재한다. 이럴때 머신러닝이 해결책이 될 수 있다. 머신러닝은 데이터와 해답을 주고 기계에게 비슷한 예제를 학습시켜 규칙성을 만든다.
즉, 머신러닝은 "주어진 데이터로부터 규칙성을 찾는 것"이다.

머신러닝 모델은 일반적으로 훈련용, 검증용, 테스트용으로 분리해서 사용한다. 훈련용으로 모델을 훈련하고, 검증용에서 모델의 성능을 조정한 뒤(과적합 판단, 하이퍼파라미터) 조정 등), 튜닝한 검증용 데이터를 아직 보지못한 데이터, 테스트 데이터로 모델의 진짜 성능을 평가한다. 문제지, 모의고사, 수능시험으로 비유를 들 수 있다.

+ 추가로 데이터가 충분하지 않아 나눌 수 없다면 k-fold 교차검증이라는 방법을 쓰기도 한다.


변수의 속성 : 하이퍼파라미터와 매개변수

하이퍼파라미터는 모델의 성능에 영향을 주는 매개변수이고, 사용자가 직접 정해줄 수 있다. (ex.학습률) 훈련 이후 검증하면서 하이퍼파라미터를 튜닝한다. 
매개변수는 모델이 학습하는 과정에서 얻어지는 값이다. ex)가중치, 편향

 

러닝? 어떤걸 학습할까? : 지도학습, 비지도학습, 강화학습

지도학습은 훈련데이터를 훈련시킬 때 문제지를 주고 답을 암기시키는 방법이다. 문제에 해당하는 답을 학습하고, 새로운 문제를 봤을 때 정답을 예측한다. 여기에 분류와 회귀가 있다. ex)스팸분류기 
비지도학습은 답이 없다. 단, 각각의 데이터의 특징을 분석해서 비슷한 형태를 찾아내는 학습을 한다. 즉, 군집화한다.ex)다리 4개인 동물, 다리가 2개인 동물 군집화 
강화학습은 배우지 않겠지만 상과 벌점 제도가 있어서 벌을 최소화시키는 방식이다. 알파고와 게임의 최적 동작을 찾는 방법. 

 

어떤 문제에 대해 다룰까? : 분류와 회귀

머신러닝은 많은 문제에서 분류 또는 회귀에 해당한다. 선형회귀는 회귀문제에 대해 학습하고, 로지스틱 회귀는 이름은 회귀이지만 분류문제를 학습한다. 분류는 이진분류와 다중클래스분류로 나뉜다. 
(추가로 다중레이블 분류도 있으나 이건 어려우니 패스.) 
회귀는 분류처럼 0 또는 1, 분리된 카테고리 이런 답이 결과가 아니라 연속된 값이 결과다. 시간에 따른 주가 예측, 생산량예측, 결과 예측 등등이 있다.
분류는 답을 정한다. 이진분류는 주어진 입력에 대해서 둘 중 하나의 답을 정한다.(ex. 합격/불합격, 스팸/정상메일) 
다중클래스분류는 주어진 입력에 대해서 두개 이상의 정해진 선택지 중에서 답을 정하는 것. 입력값이 들어오면 카테고리를 판단해서 적절한 곳에 판단된다. 

 

어떤 데이터를 다룰까? : 샘플과 특성

많은 머신 러닝 문제가 1개 이상의 독립 변수 xx를 가지고 종속 변수 yy를 예측하는 문제이다. 신경망에서 우리는 훈련데이터를 행렬로 표현을 많이하게 되는데, 독립변수 x의 행렬을 그 갯수만큼 나열한다. 여기서 가로줄은 샘플(DB에서는 레코드), 세로줄은 종속변수 y를 예측하기 위한 특성이라한다.

 

데이터 분석 이후 결과 : 정확도, 혼동행렬, 정밀도, 재현률

우리는 학습을 시키기 때문에 테스트 데이터에서 정확도(맞춘거/전체)가 높을수록 좋다. 근데 우리가 학습시키는 대답이 긍정이었는지, 부정이었는지를 알 수 없다. 그냥 정확도만 확인한다고 좋은게 아니기 때문에... 그래서 혼동행렬이라는 행렬을 만들어서, 각 대답에 대한 긍부정, 결과, 그리고 정밀도와 재현률을 알 수 있다.

 

 

머신러닝에서 고려해야할 점 : 과적합, 과소적합

여기까지 테스트 데이터에 대한 결과를 보는 방법과, 답변의 방향성까지 보게 되었다. 근데 여기서 예상치 못한 에러가 날 수 있지 않을까? 그걸 방지하는 두가지 방법.
과적합은 지금 이 모델이 이 훈련데이터에 딱 맞게 만들어진 모델이라 생기는 오류이다. 그럼 훈련은 겁나 좋게 나왔는데 테스트에서는 원하는만큼의 결과치가 나오지 않는다. 이건 훈련데이터를 지나치게 일반화한 것. 에포크(훈련횟수)가 많아질수록 비슷한 데이터로 학습시킨 것이기 때문에 과적합이 생긴다. 반대로 너무 훈련을 덜하면 배울 수 있는 여지가 있는데도 기회를 안준 것이므로  과소적합이라고 부른다. 적합(fit)이라는 단어는 모델이 주어진 데이터에 대해서 적합해져가는 과정이기 때문에 붙여졌다. 케라스에서는 학습시키는 도구 이름을 fit이라고 부르기도 한다.

 


 

회귀분석

회귀부터 하자. 선형회귀는 ~할수록 ~하다 라는 말이 딱이다. 한 변수값(x)의 변화에 따라 특정 변수의 값(y)이 영향을 받는다. x가 하나면 단순선형회귀다. 다중선형회귀는 여기서 wx가 여러개 있는것이다. 집가격은 집 평수 뿐만 아니라, 방의 갯수, 역세권 등 여러 영향이 있다. 독립변수가 여러개면 다중선형회귀이다.

단순선형회귀는 1차함수 수식을 쓴다.( y=Wx+b )여기서 기울기에 해당하는 w와 절편을 의미하는 b는 각각 가중치편향을 뜻한다. 어차피 변수값은 뭘 넣느냐에 따라 y값이 그거에 맞게 나오기 때문에, 그 변화의 폭, 또는 변화의 질을 바꾸는 것은 가중치와 편향이다. 따라서 적절한 w와 b의 값을 찾아내야 x와 y의 관계를 적절히 모델링한 것이라 볼 수 있다.

일단 비용함수(=손실함수, 목적함수)를 구해야 한다. 이건 함수의 값을 최소화하거나 최대화하는 목적을 가진 함수이다. 여기서 우리가 최소화 하는 것은 예측값의 오차이다. 즉, 회귀식인 예측값과 실제값(점)의 거리를 최소화해야 한다. 여기서는 MSE(평균 제곱 오차)라는 것을 쓰고, 이것은 임의로 그린 회귀선을 서서히 w와 b값을 바꿔가면서 최소화하는 값들을 찾는다. 각각 점과 선 사이의 거리를 절댓값 처리를 위해 제곱해주고 그걸 갯수로 나눠서 평균을 냈다.

MSE(평균제곱오차)

이게 최소가 되어야하는데 그때 최적의 알고리즘을 옵티마이저(Optimizer)라고 한다. 가장 기본적인 옵티마이저 알고리즘인 경사하강법을 써보자.

경사하강법(Gradient Descent)

따로 절편 상관 없이 가장 극단적인 양 극단을 그려보면 가운데로 올 수록 오차가 줄어드는 2차함수 형태로 그려진다. (x: w(기울기) y:오차율 => MSE) 이 오차가 최소인 지점을 우리는 극점으로 배웠다. 편미분 써서 값 찾고 등등... 접선의 기울기가 =0 인 지점을 찾는다. 컴퓨터에서는 임의의 w,b값에서 학습률(learning rate)이라는 하이퍼파라미터(개발자가 설정하는 값)를 정해서 조금씩 극단으로 다가간다. 여기서 학습률이 너무 크면 최소값을 넘어 반대편으로 넘어가니(=발산) 조심해야한다. 

최소값으로 가는 법
발산할 경우

선형회귀에서 가장 적합한 비용함수와 옵티마이저는 MSE와 경사하강법이다.

코딩 방법)
케라스에서 구현한다. activation을 선형으로 설정하고, 컴파일 loss를 mse로 한다. 모델을  학습률 0.01로 해서 fit한다. 그러면 주어진 x와 y에 대해서 오차를 최소화하는 작업을 epochs만큼 시도한다.
어느순간 하다가 MSE가 정해져서 오차가 줄어들지 않는다. predict 하면 그 모델의 예측값이 나온다.


이진분류

둘 중 하나 선택하고 분류하는 것. 대표적으로 0과 1만 출력하는 계단함수, 또는 시그모이드 함수 같은 것이 있다. 이 그래프들은 극단적으로 둘중에 하나만 선택하기 때문에 s자 형태를 띈다. 실험을 하려고 해도 직선으로는 안되고 s자 그래프가 필요하다는 소리. 선형회귀는 둘 중 하나이기 때문에 선형회귀분석처럼 직선의 방정식으로 표현하기 힘들다.

시그모이드 함수

이런 문제들을 풀기 위해 s자 형태인 시그모이드 함수를 사용한다. σ(Wx+b) 대충 이런 형태를 갖는데, 시그모이드는 출력값을 0과 1 사이의 값으로 조정해서 반환하고, x가 0일 때 0.5인 중간값을 가진다. 굴곡지지 않게 부드럽게 이어준 그래프라는 소리. 그래서 그 기준을 0.5로 두고 0.5 이상이면 1로 판단하고 그 이하면 0으로 판단한다. 확률로 따지면 50%라는 소리.

왜 얘는 경사하강법 못해?

그래프의 저점이 여러 개다. 이떄 크로스 엔트로피(Cross Entropy)함수를 사용하는데, 이 함수는 데이터의 개수와 범주 개수, 실제값(0과1)과 실제 값에 대한 확률로 계산하는 비용함수이다. 이거는 말 그대로 엔트로피, 불확실성에 대한 척도를 나타내는 수식이다. 1이나 0인경우 말고, 그 중간의 지점을 어느쪽에 치우쳐져있나 판단하는 것.

즉 로지스틱 회귀는 비용함수로 크로스 엔트로피 함수를 사용하며, 가중치를 찾기 위해서 크로스 엔트로피 함수의 평균을 취한 함수를 사용한다. 크로스 엔트로피 함수는 소프트맥스 회귀 비용 함수이기도 하다.

 

반응형
LIST
반응형
SMALL

# 오늘은 전처리 맛보기만 해보자.

ANOVA (ANalysis Of VAriance; 분산 분석)

3개 이상 다수의 그룹간의 평균의 차이가 통계적으로 유의미 한지를 판단하기 위한 시험법. F분포를 이용한다.

▼ 카이제곱검정 vs T검정 vs ANOVA(분산검정)

더보기

연속형자료와 범주형 자료

  • 연속형 : 키, 몸무게 등 수량화 가능한 자료.
  • 범주형 : 성별, 혈액형, 치료반응 유무 등 수향화 할 수 없는 자료.

연속형 변수를 검정하는데에는 T검정ANOVA(분산분석) 이 사용되고, 범주형 변수를 검정할 경우 카이제곱검정피셔의 정확검정법을 사용할 수 있다.

  • 상관분석 : 두 변수 간에 얼마나 상관이 있는가?선형관계인가?
  • 회귀분석 : y=a+bx 관계식 구하기
카이제곱검정 T검정 ANOVA(분산검정)
범주형 변수 연속형 변수
두 변수간의 상관관계 측정할 때 두 그룹의 평균 차이를 볼 때 세 그룹 이상의 평균값 분석할 때
기대빈도를 두고, 관찰빈도가 통계적으로 유의미한지 측정 두 표본이 있는데 그 차이를 표본 오차로 한다. 표본 오차가 발생할 확률이 a<0.05로 유의미하면 대립가설 채택 세개 이상 표본이 있는데 각각의 평균이 동일하다는 가설을 검정. 분산이 모두 같다는 가정 하에 오차가 크면 대립가설 채택
- 적합도 검정 : 관측된 데이터가 예측한 분포를 따르는지 검정
- 독립성 검정 : 관측값들이 다수의 인자들에 의해 분할되어 있는 경우, 그 인자들이 서로 독립적인지 또는 관련이 있는지 검정
- 단일표본 t검정 : 하나의 모집단의 평균값을 기준값과 비교
- 독립표본 t검정 : 서로 다른 두개의 그룹간의 평균 비교
- 대응표본 t검정 : 동일한 집단의 사전, 사후 평균 비교
- 일원분산분석 : 하나의 독립변수를 이용한 분산분석(수준 2개) 두 평균이 같은가 다른가?
- 이원분산분석 : 두개의 독립변수를 이용한 분산분석(수준 여러개) 여러 요인들이 종속변수와 얼마만큼 관련이 있는가?
- 다변량분산분석 : 종속변수가 여러개
- 주사위 프로그램을 만들었다. 프로그램 관측한 값과 기대한 값(나올 수 없는 값)이 서로 상관관계가 있는가?(적합)
- 완두콩 잡종을 분류하려고 한다. 이 관측데이터로 보아 이 데이터는 유전이론모형에 적합한가?(적합)
- 학년별 인원에 대한 관측값으로 보아 학년 분포가 균일한가?(독립)
- 교육수준과 성적이 연관관계가 있나?(독립)

- 평균키가 175다, 아니다(단일)
- 남자와 여자간의 소득 차이 비교(독립)
- A그룹과 B그룹 학생들의 평균키가 같은지 비교(독립)
- 임상실험에서 복용전과 복용후 결과 비교(대응)
- 신입사원에게 4가지 각기 다른 교육 훈련 방법을 사용해서 가르치고 표준 시험을 치룬 결과가 다음과 같다. 기법간 차이가 있나?(일원)
- 당뇨병과 관련된 정보와 당뇨병에 걸렸는지(1), 안걸렸는지(0)에 대한 환자데이터가 있다. 어떤 정보가 당뇨병이 걸릴 확률과 관련이 높은가?(이원)
- 교과서의 차이가 학생들의 수학과 과학점수에 미치는 영향(다변량)

 

1) 일원분산분석(One-way ANOVA)

[ 문제 ] 김부장이 4개의 각기 다른 신입사원 교육훈련 기법의 효과성을 평가하고자 한다. 새로 입사한 32명의 신입사원에게 4가지 기법을 임의로 적용시켜 교육을 시켰다. 한 달간의 훈련기간이 끝난 후 표준 시험을 쳤는데 그 점수는 아래와 같다. 4개의 교육훈련 기법간 차이가 있는가? 만약 있다면 어떻게 다른가?

-> 3개 이상의 대응표본을 비교해야 하므로 일원배치 분산분석 기법을 사용해야 한다. 

  • 귀무가설 : 4개의 교육훈련 기법간의 차이가 없다.
  • 대립가설 : 4개의 교육훈련 기법간이 차이가 있다.

4개의 그룹으로 변수를 나누어 각각 그룹의 평균을 보자.


  
a = [66,74,82,75,73,97,87,78]
b = [72,51,59,62,74,64,78,63]
c = [61,60,57,60,81,55,70,71]
d = [63,61,76,84,58,65,69,80]
print("a 평균 : ",np.mean(a))
print("b 평균 : ",np.mean(b))
print("c 평균 : ",np.mean(c))
print("d 평균 : ",np.mean(d))

평균이 각각 다르다. 더 정확한 판단을 위해 박스플롯을 그려보자.


  
plot_data = [a,b,c,d]
plt.boxplot(plot_data)
plt.xticks([1,2,3,4],['a','b','c','d'])
plt.grid(True)
plt.show()

각 그룹의 박스플롯이 만들어졌다.

▼박스플롯 보는 법

더보기

박스플롯 보는 법

분산분석은 F분포를 따른다. F 분포와 귀무가설 또는 대립가설 채택을 위한 Pvalue를 보자.


  
F_statistic, pVal = stats.f_oneway(a,b,c,d)
print('F={0:.1f},p={1:.3f}'.format(F_statistic, pVal))

p-value값이 0.05보다 작다. 따라서,


  
if pVal <0.05:
print("대립가설 채택")
else:
print("귀무가설 채택")

대립가설이 채택된다.

 

2) 이원분산분석(Two-Way ANOVA)

[ 문제 ] 다음 데이터는 당뇨병 환자와 아닌 사람들의 다양한 정보를 모은 데이터셋이다. 각 정보에 대해 당뇨병 발병과 관련이 있는지 분석해라.

▼ csv 파일

-> 두개 이상의 독립변수가 있으며, 다양한 요인들과 종속변수와의 연관성을 찾아야 한다. 따라서 이원분산분석을 사용한다.

우선 각각 요인들에 대한 정보를 파악하자.

컬럼명 부여

각각의 컬럼 정보

- 정보1 (pregnant) : 과거 임신 횟수
- 정보2 (plasma) : 포도당 부하 검사 2시간 후 공복 혈당 농도 (mm Hg)
- 정보3 (pressure) : 혈압(mm Hg)
- 정보4 (thickness) :삼두근 피부 주름 두께(mm)
- 정보5 (insulin) : 혈청 인슐린 (2hour, mu U/ml)
- 정보6 (BMI) : 체질량지수 weight(kg)/(height(m)*height(m))
- 정보7 (pedigree) : 당뇨병 가족력
- 정보8 (age) : 나이
- 정보9 (class, diabetes(당뇨병), output) : 당뇨1, 당뇨0(당뇨가 아님)

데이터의 정보를 살펴보자.

총 768개씩 분포
NaN 값은 없다.
BMI와 가족력을 제외하고 int형이다.
당뇨병에 걸린 사람 =1, 걸리지 않은 사람 =0

 

단순히 정보를 봐서는 특별한 점이 없다. 한 변수를 정해서 당뇨병 발병과 비교해보자.

임신 횟수와 비교해보자.


  
#임신횟수 당 당뇨병 발생확률
temp = df[['pregnant','diabetes']]
temp.head(3)

횟수가 다양하다.

임신 횟수당 당뇨병 발생 확률에 대한 평균을 구해보자.(group by)


  
temp1 =temp.groupby(by=['pregnant']).mean()
temp1.head()
# as_index=False 가 있으면 pregnant 변수가 살아있게 된다. 따라서 완벽한 선형을 이루게 됨.
#그래프 그리기
%matplotlib inline
temp1.plot(grid=True)

그래프를 그려보니 임신횟수가 많을수록 당뇨 확률이 높아지는 우상향 그래프를 볼 수 있다. 근데 14회 이상이 좀 이상하다. 자세히 살펴보자.

14회 이상인 사람들 모두 당뇨병에 걸렸다,

임신횟수는 우상향 그래프를 그리는 선형관계에 있으나 14회 이상인 데이터가 모두 1에 해당한다.

명확히 관련이 있다고 보기에는 근거가 부족하다.

이러한 분석을 일일히 할 수도 없기 때문에 다변량 데이터를 분석할 수 있는 라이브러리가 있다.


seaborn

 matplotlib을 기반으로 좀 더 정교하게 그래프를 그릴 때 사용한다.


▼seaborn 장점

더보기

seaborn은 matplotlib 처럼 그래프를 그리는 기능이다.

matplotlip으로도 대부분의 시각화는 가능하지만 아래와 같은 이유들로 seaborn을 더 선호하는 추세이다.

1. seaborn에서만 제공되는 통계 기반 plot
2. 특별하게 꾸미지 않아도 깔끔하게 구현되는 기본 color
3. 더 아름답게 그래프 구현이 가능한 palette 기능
4. pandas 데이터프레임과 높은 호환성
: hue 옵션으로 bar 구분이 가능하며, xtick, ytick, xlabel, ylabel, legend 등이 추가적인 코딩 작업없이 자동으로 세팅된다.

출처 : growthj.link/tag/colab/


각 데이터간의 상관관계를 그래프로 표시해보자.


df.corr()

상관분석 : 상관관계의 값을 파악할 수 있는 정도의 값을 상관 계수 (-1~1 사이)

 0 < p ≤ 1 : 양의 상관관계 / p=0 : 상관관계가 선형적이지 않다. / -1 p < 0 : 음의 상관관계 



  
import matplotlib.pyplot as plt
import seaborn as sns
# 1. 색상구성 결정
colmap = plt.cm.gist_heat
# 2. 크기 설정
plt.figure(figsize=(14,14))
# 3. 상관계수 출력
df.corr()

1에 가까울수록 양의 상관관계 -1에 가까울수록 음의 상관관계. 0은 상관관계 없음.

이것을 그래프가 아닌 그림으로 시각화 할 수도 있다. 히트맵(heatmap)이라고 한다.


  
# 히트맵 그래프 속성 결정 : vmax의 값을 0.5로 지정해서 0.5에 가까울수록 밝은색으로 표시한다.
sns.heatmap(df.corr(),linewidths=0.1,vmax=0.5,cmap=colmap,linecolor='white',annot=True)
plt.show()

당뇨병과 가장 연관이 깊은(밝은) 수치는 plasma 이다.

 

그래프를 통해서 plasma 항목(공복혈당농도)가 diabetes 항목과 가장 상관관계가 높다는 것을 알 수 있다. 따라서 plasma가 결론을 만드는 가장 중요한 역할을 한다는 것을 예측할 수 있다.

당뇨병과 공복혈당농도 간의 상관관계를 좀 더 자세히 분석해보자.

- FacetGrid : 다중 플랏을 출력할 수 있다. 예를들면 그래프를 그려도 성별별로 나온다던지 등. 상관관계를 기반으로 map을 다양하게 그려보자.


  
grid = sns.FacetGrid(df,col='diabetes')
grid.map(plt.hist,'plasma',bins=10) #히스토그램으로 보자.
plt.show()

당뇨병과 가장 상관관계가 높은 것이 diabetes 인 것을 히트맵에서 확인했으니 이걸 자세히 FacetGrid로 각각 본 것.

당뇨병에 걸린 사람(=1)의 경우 plasma가 100 이상일 때 발병률이 높다.

당뇨병에 걸리지 않은 사람(=0)의 경우 plasma가 100 가까이에 데이터가 몰려있다.(정규분포?)

 

 

[ 문제 ] seaborn에 내장된 tips 데이터를 이용해서 시간별 총 팁의 가격을 산점도로 그려보자.

산점도는 각 데이터의 관련도를 점으로 표시한다. 점의 분포도로 모양을 볼 수 있고, 이상치를 한눈에 볼 수 있으므로, 두개의 다른 변수의 연관성을 파악하는데 효과적이다.


  
grid = sns.FacetGrid(data=df, col='time') #row는 세로로 나온다.
grid.map(sns.scatterplot,'total_bill','tip') # 이번엔 산점도로 보자.

저녁때가 팁의 횟수도 많고 큰 금액도 더 분포되어있다. 

hue를 쓰면 색깔을 부여해서 3가지의 요인을 비교할 수 있다. 성별을 추가적으로 부여해보자.


  
g =sns.FacetGrid(data=df, row='time') #세로로
#hue : 설정된 변수의 값에 따라서 색상이 구별된다.
g.map_dataframe(sns.scatterplot,x='total_bill', y='tip',hue='sex')
g.set_axis_labels("Total bill","Tip") # 라벨
g.add_legend()

저녁때의 경우 여성의 팁보다 남성의 팁이 훨씬 많다.

 

 


 

회귀 분석(Regression analysis)

한 개 이상의 변수를 다룰 때 특정 변수가 다른 변수와 어떤 관계를 맺는지 분석하고, 이를 바탕으로 모델을 정의해 값을 예측하는 기법. 통계적으로 데이터를 분석하는 방법 중 하나로, 입력에 대해서 연속적인 값을 대응시키는 문제이다. 

회귀분석은 독립변수 X에 대해 종속변수 Y의 사이의 관계를 수학적인 모형을 이용해서 규명한다. 규명된 함수식을 이용해서 독립변수 X의 변화로부터 종속변수의 Y값의 변화를 예측한다.

회귀분석은 기본적으로 회귀모델 직선과 실제 값의 차이를 뜻하는 잔차(residual error)를 최소화 시키는 것을 기본 원리로 한다. 

회귀분석은 1. 두 변수가 선형관계를 가지는 지 산점도를 작성 2. 최소자승법으로 최적의 직선식 구함 3. '선형관계가 없다'는 귀무가설을 기각할 것인지 결정하기 위한 분산분석 을 진행한다.

 

1) 단순선형회귀분석(simple linear regression analysis)

하나의 종속변수(y)와 하나의 독립변수(x) 사이의 관계를 분석할 경우 사용. 둘 사이의 관계를 가장 잘 설명해주는 선형함수를 찾으면, 우상향 또는 우하향하는 직선을 찾게 된다. 사실 완벽하게 들어맞는 선형함수를 찾아내는 것은 거의 불가능하지만, 최대한 x와 y의 관계를 가장 잘 설명해줄 수 있는 일차함수식을 찾아내는 것이 단순선형회귀의 목적이다.

y = wx +b -> 이 직선은 최소제곱법을 이용한 예측치와 관측치 차이의 제곱의 합이 최소가 되는 직선이다.

보통 y는 예측값(=라벨값, 구하려는 값), x는 특성이며, w는 가중치 또는 계수(coefficient),  b는 편향(offset)이라 부른다. 우리는 여러 개의 샘플들의 특성값들과 라벨값들을 이용해서 가장 적합한 w와 b를 찾아야 한다. 이럴 때 사용되는 방법이 바로 경사하강법(gradient descent)이다.

경사하강법(gradient descent)

1. 임의로 설정한 일차함수와 데이터 사이의 평균제곱오차(MSE, mean squared error)를 구한다.

평균제곱오차(MSE)

n은 샘플의 갯수이고,

 

 

 

[ 문제1 ] 윌별로 전기 생산금액(억원)에 대해 전기사용량(백만 Kw)은 어떠한 관계를 보이는가?


  
from scipy import stats
# 월별 전기생산 금액(억원)을 변수 x,
x = [3.52, 2.58, 3.31, 4.07, 4.62, 3.98, 4.29, 4.83, 3.71, 4.61, 3.90, 3.20]
# 이 때 전기 사용량(백만 Kw) 을 y로 한다
y = [2.48, 2.27, 2.47, 2.77, 2.98, 3.05, 3.18, 3.46, 3.03, 3.25, 2.67, 2.53]

생산 금액에 대비 전기사용량을 구하고자 한다. 종속변수가 생산량에 대한 kw가 y 값이므로, y값은 연속형 변수이다.


scipy.stats.linregress(x,y)

두 세트의 측정에 대한 선형회귀분석을 호출하는 함수

단, x와 y 배열의 길이가 같아야한다.

x만 있는 경우, 한 차원의 길이가 2인 2차원 배열이어야한다.

[반환 가능한 값]

slope : 회귀선의 기울기

intercept : 회귀선의 절편

rvalue : 상관계수

pvalue : 예측기준(0.05)

stderr : 추정된 기울기의 표준 오차(표준편차)



  
# 반환값 -> slope : 기울기, intercept : 절편,
# rvalue : 상관계수, pvalue : 예측기준(0.05), stderr : 에러 표준편차
slope, intercept, rvalue, p_value, stderr = stats.linregress(x,y)

x,y 값에 대한 정보를 변수에 부여한다.

하나씩 꺼내볼 수도 있다.


  
#에러 표준편차 출력
print('stderr : ',stderr)
#상관계수 출력
print('rvalue : ', rvalue)

상관계수가 0.89로 상당히 높다. 두 변수간에는 강한 양의 상관관계가 있음을 알 수 있다. (통계적으로 상관관계가 있고 유의미하다.)

pvalue 값으로 귀무가설을 확인해보자.


  
print('p_value : ', p_value) #0.05보다 적으면 유의미하다라고 판정

독립변수(전기생산량), 종속변수(전기소비량)

독립변수가 1개이므로 단순회귀분석(선형회귀분석)을 사용한다.

- 귀무가설 : 전기생산량과 전기 소비량간의 상관관계가 없다.
- 대립가설 : 전기생산량과 전기 소비량간의 상관관계가 있다.

높은 상관관계로, 대립가설 채택

 

선형회귀분석은 각 값에 대해 점을 찍고 회귀선(가장 손실이 적은 선)과의 거리인 '잔차'를 통해 데이터가 많아질수록 회귀선으로 회귀하는 것을 이용해서 두 변수간의 관계를 분석한다.

이를 그래프로 표시하면 명확하게 알 수 있다.


  
%matplotlib inline
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.set_xlim([2.5,5.0]) #x축의 시작좌표, 마지막좌표
ax.set_ylim([2.0,3.7])
#산점도 그리기
plt.grid(True)
plt.scatter(x,y)
#회귀선 그리기
#회귀선을 그리기 위해서는 numpy 배열로 변환해야한다(*****)
#회귀선 : 가장 [손실이 적은선]을 그어서 그것을 분석하는 것을 의미한다.
# 1차함수 : y=w(기울기)x + b(절편)
x1 = np.array(x)
#플롯 그리기
plt.plot(x1,slope*x1+intercept, c='red')
plt.title('단순선형회귀곡선 예제')
plt.xlabel('전기생산량')
plt.ylabel('전기사용량')
plt.show()

각 값들이 산점도로 나타나며 최소지점의 선이 선형관계임을 알려준다.

회귀선에 따른 값들을 계산도 해볼 수 있다.

기울기를 임의로 정해서 계산해보면 다음과 같은 결과가 나온다.

y값이 잘 나온다.

 

[ 문제2 ] 다음은 오존과 관련된 데이터셋이다. 온도에 따른 오존량을 예측해보고, 둘의 상관관계를 출력(시각화) 해라.

우선 데이터부터 읽어오자.


  
# 데이터 읽기
df = pd.read_csv('./dataset/ozone.csv')
df.head()

일단 NaN값이 보이니 지우고 시작하자.


  
#NaN 있는 행 삭제
df = df.dropna(axis=0)

 

온도에 따른 오존량을 예측하는 것이 목적이기 때문에, 독립변수는 온도, 종속변수는 오존량이 된다.

각각 x와 y 값에 넣어준다.


  
x = df['Temp']
y = df['Ozone']

앞선 예제처럼 정보를 변수에 부여하고 산점도를 그린다.


  
slope, intercept, rvalue, p_value, stderr = stats.linregress(x,y)
%matplotlib inline
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.set_xlim([57,100]) #x축의 시작좌표, 마지막좌표
ax.set_ylim([1.0,100])
#산점도 그리기
plt.grid(True)
plt.scatter(x,y)
#회귀선 그리기
#회귀선을 그리기 위해서는 numpy 배열로 변환해야한다(*****)
#회귀선 : 가장 [손실이 적은선]을 그어서 그것을 분석하는 것을 의미한다.
# 1차함수 : y=w(기울기)x + b(절편)
x1 = np.array(x)
#플롯 그리기
plt.plot(x1,slope*x1+intercept, c='red')
plt.title('단순선형회귀곡선 예제')
plt.xlabel('온도')
plt.ylabel('오존량')
plt.show()

선형인 관계를 보인다. P-value 값을 확인하고 가설을 검증하면,


  
print('p_value (상관계수) :', p_value) # 0.05보다 적으면 유의미하다라고 판정
if p_value < 0.05:
print("대립가설")
else:
print("귀무가설")

-> 온도가 올라갈수록 오존량이 증가하는 선형관계를 가진다.


사이킷런(scikit-learn)

분류, 회귀, 군집화, 의사결정트리 등 다양한 머신러닝 알고리즘을 적용할 수 있는 라이브러리. 기본적인 샘플데이터를 포함하고 이어 데이터셋 모듈을 읽어들여 로드가 가능하다.

print(데이터셋이름.DESCR) 을 하면 데이터셋의 정보를 볼 수 있다.

데이터를 다루기 쉽게 하기 위해 pandas의 데이터프레임으로 변환시켜서 많이 사용한다.

▼사이킷런 라이브러리 설치


  
!pip install mglearn

 

[ 문제3 ] 사이킷런의 Boston 데이터셋을 받아서 데이터 셋 나눠서 훈련시켜보기

설치한 사이킷런에서 데이터셋을 로드하고 회귀분석을 준비한다.


  
#사이킷런
import mglearn
#사이킷런에서 제공해주는 보스턴 집값에 대한 데이터셋을 제공
from sklearn.datasets import load_boston
#회귀분석을 하기 위한 패키지
from sklearn.linear_model import LinearRegression
# 학습용 검증용 데이터 셋을 나누기 위한 패키지
from sklearn.model_selection import train_test_split

편의성을 위해 boston이라는 이름의 변수로 사용한다,.


  
#변수에 저장
boston = load_boston()
#레이블 이름 출력
boston.feature_names
#보스턴 데이터셋 설명 보기
print(boston.DESCR)

데이터셋 불러오기
데이터셋 설명

이미지 출처: http://dator.co.kr/?vid=ctg258&mid=textyle&document_srl=1721307

 

보스턴 데이터셋을 pandas의 dataframe으로 변환한다.

 

반응형
LIST
반응형
SMALL

검정(test)

특정 분포를 기준으로 했을 때 유의성이 있는가 판별하는 것.

1. 카이제곱검정(Chi-squares)

그룹간 관찰빈도와 기대빈도를 통해 두 집단간의 차이가 유의한가를 판별하는 방법. 카이검정은 범주형 변수일 경우 두 독립군간의 비교를 할 때 쓰인다.(연속형 변수인 두 독립군 간의 비교는 t-test 사용)

귀무가설(H0)과 대립가설(H1)

이 가설들은 기본적으로 통계학에서 처음부터 버릴 것을 예상하는 가설이다.

귀무가설은 앞으로 내가 검정해야 하는 것이다. (내가 궁금한 것/관찰한 것 ex-주사위 프로그램 검정 (기댓값과 달리 랜덤하게 나오는가?) 기댓값과 같이 유사한 구조로 나오는가? 등) 일단 귀무가설이 옳다는 가정하에 시작하나, 예상이기 때문에 진실일 가능성이 적다.

대립가설은 귀무가설이 기각될 때 받아들여지는 가설이다.

유의확률(pvalue)

통계적으로 유의하다면 우연이 아닌 의미가 있다는 뜻으로, 유의확률(pvalue)가 작을수록 좋다. 유의확률은 기본적으로 귀무가설이 맞다고 가정할 때, 귀무가설이 실제로 옮음에도 기각할 오류(기각할 때 따르는 위험부담)이다. 위험부담이 클수록 귀무가설이 맞다는 소리. 따라서,

pvalue< 0.05 라면, 신뢰수준하에서 유의한 관계로, 대립가설 채택한다.
pvalue< 0.05 라면, 신뢰수준하에서 무의미한 관계로, 귀무가설 채택한다.

코드는 관측값(입력값) data1과 기댓값(예상값)data2를 두고 chisquare를 한다.

카이제곱검정(Chi-squares)은 적합도 검정과 독립 검정으로 나뉜다.

 

1) 적합도 검정(Goodness of fit test)

관측된 데이터가 예측한 분포를 따르는지 검정하는 방법 ex) 게임이 공정한지 여러 게임으로 검정

chisquare : 카이제곱 검정은 이산형과 이산형 변수가 서로 상관관계가 있는지 없는지를 확인한다.

 stats.chisquare 검정통계량과 pvalue를 얻을 수 있다.


  
#관측값
data1 = [86,36,30,19]
#기대값
data2 = [42.75,42.75,42.75,42.75]
chis = stats.chisquare(data1,data2)
chis
#결과 출력
statistic,pvalue = chis #zip 형태처럼 두개의 변수에 값을 각각 할당
print("static : {}, p-value : {}".format(statistic,pvalue))
if pvalue < 0.05:
print("신뢰수준하에서 유의한 관계. 대립가설 채택")
else:
print("신뢰수준하에서 무의미한 관계. 귀무가설 채택")

▼연습문제

더보기

문제1. 주사위를 n번 던졌을 때 나오는 데이터의 차이가 있는지 없는지 알아보기


귀무가설 : 두 변수는 연관성이 없다, 차이가 없다. => 주사위 프로그램은 제대로 만들어졌다. 
대립가설 : 두 변수는 연관성이 있다, 차이가 있다. => 주사위 프로그램은 문제가 있다.


  
#scipy 통계 라이브러리
from scipy import stats
#임의의 데이터 생성
data1 = [4,6,17,16,8,9]
print('주사위 던진 횟수 : ',sum(data1)) #60회

chisquare : 카이제곱 검정은 이산형과 이산형 변수가 서로 상관관계가 있는지 없는지를 확인한다.


  
#관측값
data1 = [4,6,17,16,8,9]
#기대값
data2 = [10,10,10,10,10,10]

data1은 내가 던진 주사위의 데이터다. 주사위 프로그램 실험을 위해 귀무가설로 "(확률상 나오기 힘든)임의의 기댓값이 내가 만들어낸 프로그램의 관픅값과 연관성이 있는가?" 를 판단해보자. 만약 관련이 있으면 주사위 프로그램에 문제가 있는 것이다. 동일한게 6번 나오는건 극히 드물기 때문에....

수식으로는 겁나 복잡하지만 코딩으로는 한줄.


  
#검정통계량과 p-value
chis = stats.chisquare(data1,data2)
chis

깔끔하게 보기 위해 if문으로 결과값을 내보자.


  
#결과 출력
statistic,pvalue = chis #zip 형태처럼 두개의 변수에 값을 각각 할당
print("static : {}, p-value : {}".format(statistic,pvalue))
if pvalue < 0.05:
print("신뢰수준하에서 유의한 관계. 대립가설 채택")
else:
print("신뢰수준하에서 무의미한 관계. 귀무가설 채택")
p-value가 0.05보다 작으므로 신뢰수준 하에서 유의한 관계가 있다. 
귀무가설 기각, 대립가설 채택 
따라서 data1과 data2는 차이가 있다.

문제2. 다음표는 완두콩의 잡종의 분류에 대한 관측도수와 기대치이다. 이 데이터는 유전의 이론적으로 모형에 부합된다고 할 수 있는가? (유의수준 : 0.05)


  
#관측값
data1 = [322,108,98,32]
#기대값
data2 = [315,105,105,35]

  
chis = stats.chisquare(data1,data2)
chis
#결과 출력
statistic,pvalue = chis #zip 형태처럼 두개의 변수에 값을 각각 할당
print("static : {}, p-value : {}".format(statistic,pvalue))
if pvalue < 0.05:
print("신뢰수준하에서 유의한 관계. 대립가설 채택")
else:
print("신뢰수준하에서 무의미한 관계. 귀무가설 채택")

  
#관측값
data1 = [86,36,30,19]
#기대값
data2 = [42.75,42.75,42.75,42.75]
chis = stats.chisquare(data1,data2)
chis
#결과 출력
statistic,pvalue = chis #zip 형태처럼 두개의 변수에 값을 각각 할당
print("static : {}, p-value : {}".format(statistic,pvalue))
if pvalue < 0.05:
print("신뢰수준하에서 유의한 관계. 대립가설 채택")
else:
print("신뢰수준하에서 무의미한 관계. 귀무가설 채택")

 

- 귀무가설 : 동남아지역 항공권 구매자의 연령분포가 유럽지역의 경우와 같다. 
- 대립가설 : 동남아지역 항공권 구매자의 연령분포가 유럽지역의 경우와 다르다.


  
chis = stats.chisquare(data1,data2)
chis
#결과 출력
statistic,pvalue = chis #zip 형태처럼 두개의 변수에 값을 각각 할당
print("static : {}, p-value : {}".format(statistic,pvalue))
if pvalue < 0.05:
print("신뢰수준하에서 유의한 관계. 대립가설 채택")
else:
print("신뢰수준하에서 무의미한 관계. 귀무가설 채택")

전체표본의수: 207 
기대값: [16.56 97.29 70.38 22.77]


  
import numpy as np
#관측값
data1 = np.array([21,109,62,15])
#전체표본수
total = np.sum(data1)
print('전체표본의수:',total)
#기대비율
e_per = np.array([0.08,0.47,0.34,0.11])
#기대값구하기
#기대값 :기대치 = 전체표본의수*기대비율
data2 = total*e_per
print('기대값:',data2)

static : 6.249083587686194, p-value : 0.10010099872459155 
신뢰수준하에서 무의미한 관계. 귀무가설 채택


2) 독립성 검정(Test of independence) 

관측값들이 다수의 인자들에 의해 분할 되어 있는 경우 그 인자들의 관찰 값에 영향을 주고 있는지 아닌지를 검정하는 방법. 여러 범주를 가지는 두 개의 변수가 서로 독립적인지 또는 관련이 있는지를 분석한다. ex) 선호하는 음식의 종류와 연령이 서로 관령성이 있는지를 알고 싶을 때

독립성 검정은 귀무가설 : 독립이다. / 대립가설 : 독립이 아니다. 를 의미한다. 여기서 독립이라는 의미는 인과관계 혹은 연관이 없다는 말이 될 수 있다. (교육수준 과 수업이 연관관계가 있는지 없는지,나이와 정당선호도가 연관이 되는지 없는지)


  
obs = np.array([[5,15],[10,20]])

numpy와 아주 밀접한 관계가 있다. 

chi2_contingency(독립성 검정) : 카이제곱 통계량, p-value, 자유도 등을 return


  
#독립성검정
statistic,pvalue,_,_ = stats.chi2_contingency(obs)
print("static : {}, p-value : {}".format(statistic,pvalue))
if pvalue < 0.05:
print("신뢰수준하에서 유의한 관계. 대립가설 채택")
else:
print("신뢰수준하에서 무의미한 관계. 귀무가설 채택")

,_,_는 굳이 넣지 않은 자유도나 타 조건들을 의미한다.

▼연습문제

더보기

 문제1. 두 개의 광고 서비스를 통해 각각 유입된 사용자들의 이용률을 독립성 검정을 이용해 분석해라.

- 귀무가설 : 모집단 sample A와 모집단 sample B의 지속 이용 전환율은 다르지 않다.
- 대립가설 : 모집단 sample A와 모집단 sample B의 지속 이용 전환율은 다르다.


  
data1 = np.array([40,165]) # 지속이용사용자수 #해지한 사용자 수
data2 = np.array([62,228])
print("유입사용자수 A : {}, 지속사용자수 : {}, 지속이용전환율(mean)={:.3f}".format(
np.sum(data1), #전체 유입
data1[0],
data1[0]/np.sum(data1) #전체유입 대비 남은사람 비율
))
print("유입사용자수 B : {}, 지속사용자수 : {}, 지속이용전환율(mean)={:.3f}".format(
np.sum(data2),
data2[0],
data2[0]/np.sum(data2)
))

  
#카이제곱검정 : 독립성 검정
statistic,pvalue,_,_ = stats.chi2_contingency(obs)
print("static : {}, p-value : {}".format(statistic,pvalue))
if pvalue < 0.05:
print("신뢰수준하에서 유의한 관계. 대립가설 채택")
else:
print("신뢰수준하에서 무의미한 관계. 귀무가설 채택")

가설 ) 성별과 학력이 서로 관계가 있다고 말할 수 있는가? (유의수준 0.05)

- 귀무가설 : 두 변수는 독립적인 관계이다. 학력에 따른 성별 비율의 차이는 없다
- 대립가설 : 두 변수는 독립적인 관계가 아니다. 학력에 따른 성별 비율의 차이는 있다.


  
data1 = np.array([12,13,65,41])
data2 = np.array([11,6,47,5])
statistic,pvalue,df,e =stats.chi2_contingency([data1,data2])
print(statistic)
print(pvalue)# 대립가설 채택


t검정 : 두 집단간의 평균을 비교할 때 사용하는 방법

1) 단일표본 t-test : 한 집단 평균 검정

- 하나의 데이터 집단의 평균과 비교하고자 하는 관측치를 통해 차이를 검정하는 방법
- 데이터 집단의 평균과 거리가 멀 수록 p-value 유의수준의 값이 떨어진다.
- stats.ttest_1samp() 이용

ttest_1samp : 모집단 M와 x_1

표본의 평균이 모집단의 평균과 일치한다”라는 귀무가설을 확인하는 방법
ex) 키 : 표본 1개랑 모집단 평균이랑 같은지? 키가 175인가?


  
one_sample = [177.3, 182.7, 169.6, 176.3, 180.3, 179.4, 178.5, 177.2, 181.8, 176.5]
print(mean(one_sample)) # 177.96
result = stats.ttest_1samp(one_sample, 175.6) # 비교집단, 관측치
print('t검정 통계량 = %.3f, pvalue = %.3f'%(one_sample_result))
# t검정 통계량 = 2.296, pvalue = 0.072

3f는 셋째자리에서 반올림

2) 독립표본 t-test : 두개의 집단 평균 검정

 - 두 데이터 집단간의 평균을 서로 비교해서 그 차이를 검정ㅎ는 방법
 - stats.ttest_ind(x,y) 이용

ttest_ind : x_1 과 x_2

2개 집단에서 표본을 수집했을 때, 두 집단의 평균이 서로 일치한다”라는 귀무가설을 확인하는 방법
ex) 신발사이즈, 두집단의 평균(남자 평균, 여자평균)


  
female = [63.8, 56.4, 55.2, 58.5, 64.0, 51.6, 54.6, 71.0]
male = [75.5, 83.9, 75.7, 72.5, 56.2, 73.4, 67.7, 87.9]
result = stats.ttest_ind(male, female)
print("t검정 통계량: %.3f, pvalue=%.3f"%(result))
# t검정 통계량 = 3.588, pvalue = 0.003

3) 대응표본 t-test : 같은 집단의 대응되는 두 변수를 비교

 

- before 와 after의 변화가 얼마나 대응 되는지(국어점수, 수학점수 또는 사전점수 사후점수 등)
- stats.ttest_rel(x,y) 이용

ttest_rel : A -> B 


  
baseline = [67.2, 67.4, 71.5, 77.6, 86.0, 89.1, 59.5, 81.9, 105.5]
follow_up = [62.4, 64.6, 70.4, 62.6, 80.1, 73.2, 58.2, 71.0, 101.0]
paried_sample = stats.ttest_rel(baseline, follow_up)
print('t검정 통계량 = %.3f, pvalue = %.3f'%paired_sample)
# t검정 통계량 = 3.668, pvalue = 0.006

출처 : blog.naver.com/nonamed0000/220908890568

▼연습문제

더보기

문제1) 귀무가설 : 학생들의 평균키는 175cm이다.  대립가설 : 학생들의 평균키는 175cm가 아니다.


  
np.random.seed(1) # 재현률 난수값을 고정할 때 사용
# np.random.normal(평균,표준편차)
heights = [180 + np.random.normal(0,5) for a in range(20)]
heights
#ttest_1samp : 독립표본 T검정 (이산형과 연속형 변수의 상관관계를 알고 싶을 때 )
# 175인지 아닌지 - 이산형 변수, 175는 늘어나는 수 즉 연속형 변수 라 할 수 있다.
result = stats.ttest_1samp(heights, 175)
print(result)
print("단일표본 T-검정 검정통계량: %.3f, pvalue: %.3f" % result)
if pvalue < 0.05:
print("대립가설 채택")
else:
print("귀무가설 채택")
생성된 난수가 175와 연관성이 떨어지기 때문에 대립가설을 채택한다.
생성된 난수

 문제2) 다음 데이터의 표본이 모집단 평균과 비슷할까?

- 귀무가설 "표본의 평균이 모집단의 평균과 일치한다"  대립가설 "표본의 평균이 모집단의 평균과 일치하지 않는다"


  
#귀무가설 "표본의 평균이 모집단의 평균과 일치한다"
data = [32,34,29,29,22,40,38,37,38,36,30,26,22,22]
data = sorted(data) #정렬
print("median:",np.median(data))
print("mean:",np.mean(data))
expected_mean = np.median(data)
from scipy.stats import ttest_1samp
result = ttest_1samp(data,expected_mean)
print("단일표본 T-검정 검정통계량 : %.3f, pvalue:%.3f" % result)
statistic,pvalue = result
if pvalue < 0.05:
print("신뢰수준하에서 유의한 관계. 대립가설 채택")
else:
print("신뢰수준하에서 무의미한 관계. 귀무가설 채택")

 뭐 당연히... 데이터는 똑같고 그걸로 평균내냐, 중간값내냐 차이라... 당연히 일치한다.


문제3)  그룹1과 그룹2에서 각각 학생들을 선택해서 평균키가 같은지 알고싶다.

#귀무가설 : 학생들의 평균키가 같지 않다.(상과관계가 없다.)
#대립가설 : 학생들의 평균키가 같지 않다.(내가 주장하고 싶은 것, 상관관계가 있다.)


  
np.random.seed(1)
group1=[170+np.random.normal(0,5) for a in range(20)] #170 근처의 값이 나오도록 설정한다.
group2=[175+np.random.normal(0,10) for a in range(20)] #175 근처의 값이 나오도록 설정한다.
print("group1의 평균 :",np.mean(group1))
print("group2의 평균 :",np.mean(group2))
result1 = stats.ttest_ind(group1,group2)
statistic,pvalue = result1
print("독립표본 T-검정 검정통계량 : %.3f, pvalue:%.3f" % result1)
if pvalue < 0.05:
print("신뢰수준하에서 유의한 관계. 대립가설 채택")
else:
print("신뢰수준하에서 무의미한 관계. 귀무가설 채택")
170 근처와 175 근처로 난수를 설정했기 때문에 다르게 나온다.

문제4) 남자와 여자의 신발사이즈의 평균이 같은지 다른지 선별하시오. -> 귀무가설 : 두집단의 평균이 같다


  
import pandas as pd
df = pd.read_excel('dataset/exam24.xlsx')
#남자가 1, 여자가2
df.head(5)
#번호 컬럼 삭제
df=df.drop(df.columns[0],axis=1)
#data1과 data2에 각각 성별별로 발사이즈 넣기
data1 = df[df['성별']== 1]['foot_length'].to_list()
data2 = df[df['성별']== 2]['foot_length'].to_list()
result1 = stats.ttest_ind(data1, data2)
statistic,pvalue = result1
print("단일표본 T-검정 검정통계량 : %.3f, pvalue:%.3f" % result1)
if pvalue < 0.05:
print("신뢰수준하에서 유의한 관계. 대립가설 채택")
else:
print("신뢰수준하에서 무의미한 관계. 귀무가설 채택")

문제5) 어떤 회사에서 탈모약을 개발해서 임상실험을 하는 상황이다. 50명을 모집해서 6개월간 탈모약을 복용하게 했고, 복용 전과 후의 모발 수를 비교했다.

-  귀무가설 : 복용 후 모발 수가 복용 전보다 크지 않다

-  대립가설 : 복용 후 모발 수가 복용 전보다 크다.


  
import pandas as pd
df = pd.read_excel('dataset/탈모.xlsx')
df.head(5)
# 컬럼명이 있는 첫줄과 데이터를 제외한 모든값 잘라냄
df = df.loc[1:,['모발 수','Unnamed: 2']]
#컬럼명 맞게 바꿔주기
df.rename(columns = {'모발 수' : '복용전'}, inplace = True)
df.rename(columns = {'Unnamed: 2' : '복용후'}, inplace = True)
df.head(1)
data1 = df['복용전'].to_list()
data2 = df['복용후'].to_list()
result3 = stats.ttest_ind(data1, data2)
statistic,pvalue = result3
print("단일표본 T-검정 검정통계량 : %.3f, pvalue:%.3f" % result3)
if pvalue < 0.05:
print("신뢰수준하에서 유의한 관계. 대립가설 채택")
else:
print("신뢰수준하에서 무의미한 관계. 귀무가설 채택")

빠트린 것! index가 0부터 안하니까 다시 reset 해줘야한다.
df.reset_index(drop=True)


np.random.seed()는 난수를 예측 가능하게 만든다.

원래 np.random.rand(4)로 4개의 랜덤한 array를 만든다고 했을 때, 4개가 랜덤으로 지정되고 실행을 시킬 때마다 다른 array가 나온다. 하지만 np.random.seed(1)를 하게 되면 고정되어 동일한 세트의 난수가 나타난다. -> seed라는 하나의 파라미터를 생성해서 똑같은 것을 불러오는 것. 괄호의 숫자는 키값과 비슷하다.

 

 

반응형
LIST
반응형
SMALL

1. 외부데이터 수입해서 다루기(복습)


2. Group by : groupby(by=[묶는기준], as_index=False )

한개열 또는 여러열을 기준으로 집계하는 함수.

집계하고자하는 열 이름을 by 파라미터에 입력하고 호출하면 된다.

 as_index=False : 인덱스 손질. 설정하지 않으면 판다스(Pandas) 복합 인덱스로 올라가서 변환하거나 사용하기 어렵다.

 

1) 한개 열을 기준으로 집계하기


  
df = pd.DataFrame({
'상품번호':['상품1','상품2','상품3','상품4'],
'수량' : [2,3,5,10]
})
df

기본적으로 groupby만 해도 이미 집계는 되어있는 상태이다.

단, generator 상태이기 때문에 추가적으로 산술통계를 써서 원하는 값을 도출하는 방식으로 쓰인다.


  
#상품번호별로 묶기, 인덱스 손질하는 코드 추가
df.groupby(by=['상품번호'],as_index=False)

다양한 산술통계를 써서 결과를 보자.


  
# min: 상품번호별 판매된 총수량
df.groupby(by=['상품번호'],as_index=False).sum()
# min: 상품번호별 판매된 최소 수량
df.groupby(by=['상품번호'],as_index=False).min()
# min: 상품번호별 판매된 최대 수량
df.groupby(by=['상품번호'],as_index=False).max()
# mean: 상품번호별 판매된 평균 수량
df.groupby(by=['상품번호'],as_index=False).mean()
#count : 상품번호별 판매 수
df.groupby(by=['상품번호'],as_index=False).count()

 

2) 여러 열을 기준으로 집계하기


  
import pandas as pd
df = pd.DataFrame({'고객번호' : ['고객1', '고객2', '고객3', '고객4'],
'상품번호':['상품1','상품2','상품3','상품4'],
'수량' : [2,3,5,10]})

[연습문제] 연도를 그룹으로 해서 지역명이 경기만 그룹화해서 총 갯수를 그룹별로 출력하기

오라클 식으로 풀면 select count(*), 연도 from apt where 지역명=='경기' group by 연도


  
#지역명이 경기인 것만 연도별로 그룹화해서 슬라이스한다.
aptGroupby = aptData.loc[aptData.지역명=='경기'].groupby(['연도'],as_index=False)
#그거 총 갯수 세서 다시 aptGroupby에 넣줌
aptGroupby=aptGroupby.count()
aptGroupby
#거기서 연도와 지역명만 가져오기
aptGroupby[['연도','지역명']]


  
plt.bar(aptGroupby.index,aptGroupby['지역명'],color='#55c8ff',width=0.5,
label='경기지역') #bar(x,y)
plt.legend()
plt.title('시각화 결과')
plt.xlabel('지역명')
plt.ylabel('총 갯수')
plt.grid
plt.show()


3. 데이터를 JSON으로 바꿔서 저장하기 : to_json

궁극적으로 데이터프레임에서 만든 json을 디장고로 보내서 사용하거나 spring MVC를 사용하는 것이 목표다.

파이썬은 기본적으로 읽어들이거나 내보내는 형식이 자바에 비해 훨씬 간단하다. 읽어들이는 경우 import os 를 이용해서 w(write), r(read) 등 간단한 약어를 사용할 수 있다. 내보내기 역시 마찬가지다. 

force_ascii=False : 유니코드 방지

외부에서 저장된 파일을 읽어왔을 때 결과가 잘 나온다.

[참고] 파일명을 쓰지 않으면 저장은 되지 않고 출력만 된다.

json으로 저장할 때 여러가지 옵션을 설정할 수 있다. 각 설정별로 결과값을 비교해보자.

- records : 컬럼에 따른 데이터만 출력(가로로 한줄씩 컬럼명을 key값으로 출력)


  
# records : 데이터만 출력(가로로 한줄씩 컬럼명을 key값으로 출력)
aa.to_json(orient='records', force_ascii=False)

  
# json 데이터
[{"sno":"A001","student":"홍길동","kor":85,"eng":90,"math":85},
{"sno":"B001","student":"이순자","kor":95,"eng":95,"math":75},
{"sno":"A002","student":"왕서방","kor":85,"eng":95,"math":75},
{"sno":"B002","student":"영심이","kor":80,"eng":80,"math":100},
{"sno":"A003","student":"호철이","kor":90,"eng":65,"math":70},
{"sno":"B003","student":"가진이","kor":75,"eng":100,"math":80}]

records

- split : column 데이터, index 데이터, value 데이터를 나눠서 출력. key값에서 특정 칼럼이 필요할 때 사용한다.


  
# split : 특정 칼럼 설정
aa.to_json(orient='split',force_ascii=False)

  
# json 데이터
{"columns":["sno","student","kor","eng","math"],
"index":[0,1,2,3,4,5],
"data":[["A001","홍길동",85,90,85],
["B001","이순자",95,95,75],
["A002","왕서방",85,95,75],
["B002","영심이",80,80,100],
["A003","호철이",90,65,70],
["B003","가진이",75,100,80]]}

split 

- table: 스키마(데이터베이스의 전체적인 논리적 구조 / PK값, pandas 버전 등)를 추가한 데이터. 이 DateFrame과 관련된 모든 정보를 포함한다.


  
# table : DF 정보 포함
aa.to_json(orient='table',force_ascii=False)

  
# json 데이터
{"schema": {"fields":[{"name":"index","type":"integer"},
{"name":"sno","type":"string"},
{"name":"student","type":"string"},
{"name":"kor","type":"integer"},
{"name":"eng","type":"integer"},
{"name":"math","type":"integer"}],
"primaryKey":["index"],
"pandas_version":"0.20.0"
},
"data": [{"index":0,"sno":"A001","student":"홍길동","kor":85,"eng":90,"math":85},
{"index":1,"sno":"B001","student":"이순자","kor":95,"eng":95,"math":75},
{"index":2,"sno":"A002","student":"왕서방","kor":85,"eng":95,"math":75},
{"index":3,"sno":"B002","student":"영심이","kor":80,"eng":80,"math":100},
{"index":4,"sno":"A003","student":"호철이","kor":90,"eng":65,"math":70},
{"index":5,"sno":"B003","student":"가진이","kor":75,"eng":100,"math":80}]
}

table

그냥 처음부터 정보를 제한해서 저장하는 방법도 있다.

- index : 대표 key 값을 인덱스로 준다.(column은 data의 키값이다.)


  
#인덱스
aa.to_json(orient='index',force_ascii=False)

  
# json 데이터
{
"0":{"sno":"A001","student":"홍길동","kor":85,"eng":90,"math":85},
"1":{"sno":"B001","student":"이순자","kor":95,"eng":95,"math":75},
"2":{"sno":"A002","student":"왕서방","kor":85,"eng":95,"math":75},
"3":{"sno":"B002","student":"영심이","kor":80,"eng":80,"math":100},
"4":{"sno":"A003","student":"호철이","kor":90,"eng":65,"math":70},
"5":{"sno":"B003","student":"가진이","kor":75,"eng":100,"math":80}
}

 

- columns: 대표 key 값을 컬럼으로 준다.(index는 data의 키값이다.)


  
#컬럼
aa.to_json(orient='columns',force_ascii=False)

  
# json 데이터
{
"sno":{"0":"A001","1":"B001","2":"A002","3":"B002","4":"A003","5":"B003"},
"student":{"0":"홍길동","1":"이순자","2":"왕서방","3":"영심이","4":"호철이","5":"가진이"},
"kor":{"0":85,"1":95,"2":85,"3":80,"4":90,"5":75},
"eng":{"0":90,"1":95,"2":95,"3":80,"4":65,"5":100},
"math":{"0":85,"1":75,"2":75,"3":100,"4":70,"5":80}
}

 

- values : 값만 묶어서 보내주자.


  
#값만 보내주기(키값은 나중에 설정하자.)
aa.to_json(orient='values',force_ascii=False)

  
# json 데이터
[["A001","홍길동",85,90,85],["B001","이순자",95,95,75],["A002","왕서방",85,95,75],
["B002","영심이",80,80,100],["A003","호철이",90,65,70],["B003","가진이",75,100,80]]

4. Django에서 데이터프레임을 json 데이터로 변환 후 차트 그리기

1. 우선 html 파일을 간단하게 만들자.

버튼을 누르면 json 데이터를 이용한 c3js 차트가 나오도록 하자.


  
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="width:450px;margin:auto">
<div><input type="button" value="click" id="jsonLoad"></div>
<div id="target"></div>
<!-- chart를 출력하기 위한 UI -->
<div id="chart1"></div>
</div>
<!-- C3JS 라이브러리 불러오기 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.js"></script>
</body>
</html>

버튼을 클릭하면 jsonLoad로 이동한다.

 

2. views.py 에서 jsonLoad를 정의해주자.


  
# 제이슨 파일로 바꿀 데이터프레임
def make_dfall():
df_all = pd.DataFrame({'sno': ['A001', 'B001', 'A002', 'B002', 'A003', 'B003'],
'student': ['홍길동', '이순자', '왕서방', '영심이', '호철이', '가진이'],
'kor': [85, 95, 85, 80, 90, 75],
'eng': [90, 95, 95, 80, 65, 100],
'math': [85, 75, 75, 100, 70, 80]
})
return df_all
#위에서 정의한 make_dfall를 split으로 해서 데이터를 보낸다.
def loadJson(request):
df = make_dfall()[['student', 'kor', 'eng', 'math']]
print(df)
df.to_json('test.json', orient='split', force_ascii=False)
f = open('/home/kosmo_03/PycharmProjects/myapps/test.json')
aa = json.load(f)
print(aa)
return JsonResponse(aa, json_dumps_params={'ensure_ascii': False}, safe=False)
#데이터 로드 후 JsonResponse로 로드한 aa를 응답해주자.

 

3. urls.py 에 링크 등록한다.


  
# -------------------------------------------------
path('chart3', views.chart3),
path('loadJson', views.loadJson),

 

4. chart3.html에 script를 추가한다.

버튼을 누르면 차트가 나온다. 차트를 누르는 버튼의 id를 jsonLoad으로 했으므로, 그 기능을 심어주자.

$('#jsonLoad').click(function(){ : html에서 정의한 idjsonLoad인 값을 클릭하면 함수 실행. 

 

ajax를 자세히 보면,

url:'loadJson' :  url.py에 정의한 요청이 들어오면 정의한 뷰를 실행한다.

function(data) : 실행에 성공하면, data(=view에서 응답한 aa) 를 이용해서 차트를 만드는 makeBarChart 함수를 실행한다. 단, data(=aa)의 data 컬럼과, columns컬럼을 키값으로 가진 value 값을 가져온다.

index는 가져오지 않는 것.


  
<script>
$(function(){
$('#jsonLoad').click(function(){
//아이디가 jsonLoad인 값을 클릭하면 함수 실행.
$.ajax({
url:'loadJson',
//url.py에 정의한 요청이 들어오면 정의한 뷰가 실행 .있는것 중 loadJson 가져와
success:function(data){ //여기 데이터는 view에서 response한 aa
makeBarChart(data.data,data.columns); //makeBarChart function 실행해(아래에 있는거)
//제이슨 데이터 안에 있는 data와 columns를 가져온다.
} //end success
});//end ajax
}); //click end
}); //end $(function(){
</script>
</body>
</html>

 

5. 데이터 차트에 맞게 수정

일단 데이터는 가지고 왔다. 하지만 우리가 필요한 데이터를 정제할 필요가 있다.

우리는 이것들만 필요하다.


  
function makeBarChart(jsonData, dcol){
var datas = [];
// [n개의 컬럼들]
var dcolumns = dcol.slice(1, dcol.length);
//첫번째 컬럼 슬라이스
for(var key in jsonData){ //jsonData : 실제 이름, 점수 데이터
datas.push(jsonData[key]); //2. 배열에 저장한다.
}

차트를 만드는 makeBarChart 함수를 정의하자. dcol과 jsonData가 컬럼과 data인가?

우선 jsonDatadcol 이라는 변수를 쓸건데, 각각 차트에 필요한 이름, 점수값을 가진 배열과 컬럼명이다.

컬럼명은 원래 제일 왼쪽에 있는 애가 컬럼명이 되었다. 이걸 잘라주자.

var dcolumns = dcol.slice(1,dcol.length);

컬럼을 슬라이스해주자.

 

for문을 이용해서 남은 파란색 jsonDatadatas에 넣어준다.

c3를 생성한다.

1) data를 설정할 때, 컬럼이 위에서 파란색으로 넣은 데이터다. 맨 왼쪽에 있는 것(이름)이 인덱스가 된다.

2) axis 축을 설정하는데 x축을 남은 노란색 컬럼으로 지정한다.

axis에서 설정한 x축


  
function makeBarChart(jsonData, dcol){
var datas = [];
// [n개의 컬럼들]
var dcolumns = dcol.slice(1, dcol.length);
//첫번째 컬럼 슬라이스
for(var key in jsonData){ //jsonData : 실제 이름, 점수 데이터
datas.push(jsonData[key]); //2. 배열에 저장한다.
}
//c3js.com bar 샘플 코드를 복사
var chart = c3.generate({
bindto : '#chart1',
data: {columns: datas, type: 'bar'},// jsonData를 바인딩한다.
bar: {width: {ratio: 0.5} },
axis: { x: {type: 'category',categories: dcolumns} }
// X축에 읽어온 컬럼의 category 를 지정한다.
});//end var chart
}// end function makeBarChart
}); //end $(function(){
</script>

 

실행 후 버튼을 누르면, 

그래프가 출력된다.

 

▼ 전체 코드

더보기

views.py

urls.py


  
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="width:450px;margin:auto">
<div><input type="button" value="click" id="jsonLoad"></div>
<div id="target"></div>
<!-- chart를 출력하기 위한 UI -->
<div id="chart1"></div>
</div>
<!-- C3JS 라이브러리 불러오기 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.js"></script>
<script>
$(function(){
$('#jsonLoad').click(function(){
//아이디가 jsonLoad인 값을 클릭하면 함수 실행.
$.ajax({
url:'loadJson', //url.py에 정의한 요청이 들어오면 정의한 뷰가 실행 .있는것 중 loadJson 가져와
success:function(data){ //여기 데이터는 view에서 response한 aa
makeBarChart(data.data,data.columns); //makeBarChart function 실행해(아래에 있는거)
//제이슨 데이터 안에 있는 data와 columns를 가져온다.
} //end success
});//end ajax
}); //click end
function makeBarChart(jsonData, dcol){
var datas = [];
// [n개의 컬럼들]
var dcolumns = dcol.slice(1, dcol.length);
//첫번째 컬럼 슬라이스
for(var key in jsonData){ //jsonData : 실제 이름, 점수 데이터
datas.push(jsonData[key]); //2. 배열에 저장한다.
}
//c3js.com bar 샘플 코드를 복사
var chart = c3.generate({
bindto : '#chart1',
data: {columns: datas, type: 'bar'},// jsonData를 바인딩한다.
bar: {width: {ratio: 0.5} },
axis: { x: {type: 'category',categories: dcolumns} }
// X축에 읽어온 컬럼의 category 를 지정한다.
});//end var chart
}// end function makeBarChart
}); //end $(function(){
</script>
</body>
</html>

views.py


  
def chart3(request):
return render(request, "survey/chart3.html")
def loadJson(request):
df = make_dfall()[['student', 'kor', 'eng', 'math']]
print(df)
df.to_json('test.json', orient='split', force_ascii=False)
f = open('/home/kosmo_03/PycharmProjects/myapps/test.json')
aa = json.load(f)
print(aa)
return JsonResponse(aa, json_dumps_params={'ensure_ascii': False}, safe=False)
def make_dfall():
df_all = pd.DataFrame({'sno': ['A001', 'B001', 'A002', 'B002', 'A003', 'B003'],
'student': ['홍길동', '이순자', '왕서방', '영심이', '호철이', '가진이'],
'kor': [85, 95, 85, 80, 90, 75],
'eng': [90, 95, 95, 80, 65, 100],
'math': [85, 75, 75, 100, 70, 80]
})
return df_all

urls.py


  
# -------------------------------------------------
path('chart3', views.chart3),
path('loadJson', views.loadJson),
]

 


반응형
LIST
반응형
SMALL

+ Recent posts

반응형
LIST