(1주차) 9월6일
박스플랏, 히스토그램
-
(1/6): 박스플랏: 전북고예제 (평균은 좋은 측정값인가?)
-
(2/6): 박스플랏 기본개념
-
(3/6): plotly
-
(4/6): 히스토그램
-
(5/6): 히스토그램 2개 겹쳐서 비교하기
-
(6/6): 과제안내
import matplotlib.pyplot as plt
import numpy as np
-
전북고등학교에서 통계학을 수업하는 두 선생님이 있다. 편의상 A선생님과 B선생님이라고 하자. A선생님이 강의한 반의 통계학 점수는 79.1점이고, B선생님이 강의한 반의 통계학 점수는 78.3점 이라고 하자.
-
의사결정: A선생님에게 배운 학생들의 실력이 평균적으로 좋을 것이다.
y1=[75,75,76,76,77,77,79,79,79,98] # A선생님에게 통계학을 배운 학생의 점수들
y2=[76,76,77,77,78,78,80,80,80,81] # B선생님에게 통계학을 배운 학생의 점수들
np.mean(y1), np.mean(y2)
-
평균은 A반(=A선생님에게 통계학을 배운 반)이 더 높다. 그런데 98점을 받은 학생때문에 전체평균이 올라간 것이고, 나머지 학생들은 전체적으로 B반 학생들이 점수가 더 높다고 해석할 수 있다.
-
단순한 평균비교보다 분포를 비교해보는 것이 중요하다. 분포를 살펴보는 방법 중 유용한 방법이 박스플랏이다.
plt.boxplot(y1)
- A반의 boxplot
- 뚝 떨어진 하나의 점은 98점
- 붉은 선은 중앙값 (평균이 아니라 중앙값)
- 나머지 점들은 7~80점에 분포되어있다.
plt.boxplot(y2)
- B반의 boxplot
-
아래와 같이 하면 박스플랏을 나란히 그릴 수 있다.
plt.boxplot([y1,y2])
-
미적인 그래프는 아니지만 이정도는 괜찮은것 같다.
np.random.seed(916170)
# connection path is here: https://stackoverflow.com/questions/6146290/plotting-a-line-over-several-graphs
mu, sigma = 0, 1 # mean and standard deviation
s = np.random.normal(mu, sigma, 1000)
fig, axes = plt.subplots(nrows = 1, ncols = 1, figsize=(10, 5))
# rectangular box plot
bplot = axes.boxplot(s,
vert=False,
patch_artist=True,
showfliers=True, # This would show outliers (the remaining .7% of the data)
positions = [0],
boxprops = dict(linestyle='--', linewidth=2, color='Black', facecolor = 'red', alpha = .4),
medianprops = dict(linestyle='-', linewidth=2, color='Yellow'),
whiskerprops = dict(linestyle='-', linewidth=2, color='Blue', alpha = .4),
capprops = dict(linestyle='-', linewidth=2, color='Black'),
flierprops = dict(marker='o', markerfacecolor='green', markersize=10,
linestyle='none', alpha = .4),
widths = .3,
zorder = 1)
axes.set_xlim(-4, 4)
plt.xticks(fontsize = 14)
axes.set_yticks([])
axes.annotate(r'',
xy=(-.73, .205), xycoords='data',
xytext=(.66, .205), textcoords='data',
arrowprops=dict(arrowstyle="|-|",
connectionstyle="arc3")
);
axes.text(0, .25, "Interquartile Range \n(IQR)", horizontalalignment='center', fontsize=18)
axes.text(0, -.21, r"Median", horizontalalignment='center', fontsize=16);
axes.text(2.65, -.15, "\"Maximum\"", horizontalalignment='center', fontsize=18);
axes.text(-2.65, -.15, "\"Minimum\"", horizontalalignment='center', fontsize=18);
axes.text(-.68, -.24, r"Q1", horizontalalignment='center', fontsize=18);
axes.text(-2.65, -.21, r"(Q1 - 1.5*IQR)", horizontalalignment='center', fontsize=16);
axes.text(.6745, -.24, r"Q3", horizontalalignment='center', fontsize=18);
axes.text(.6745, -.30, r"(75th Percentile)", horizontalalignment='center', fontsize=12);
axes.text(-.68, -.30, r"(25th Percentile)", horizontalalignment='center', fontsize=12);
axes.text(2.65, -.21, r"(Q3 + 1.5*IQR)", horizontalalignment='center', fontsize=16);
axes.annotate('Outliers', xy=(2.93,0.015), xytext=(2.52,0.20), fontsize = 18,
arrowprops={'arrowstyle': '->', 'color': 'black', 'lw': 2},
va='center');
axes.annotate('Outliers', xy=(-3.01,0.015), xytext=(-3.41,0.20), fontsize = 18,
arrowprops={'arrowstyle': '->', 'color': 'black', 'lw': 2},
va='center');
fig.tight_layout()
!pip install plotly
!pip install ipywidgets
!pip install jupyter-dash
!pip install dash
!pip install pandas
import plotly.express as px
import pandas as pd
from IPython.display import HTML
A=pd.DataFrame({'score':y1,'class':['A']*len(y1)})
B=pd.DataFrame({'score':y2,'class':['B']*len(y2)})
df=pd.concat([A,B],ignore_index=True)
df
fig=px.box(data_frame=df, x='class',y='score')
HTML(fig.to_html(include_plotlyjs='cdn',include_mathjax=False))
-
X축이 변수의 구간, Y축은 그 구간에 포함된 빈도를 의미하는 그림
-
예를들면 아래와 같음
plt.hist(np.random.normal(loc=0, scale=1, size=1000000))
-
중심경향값, 집중경향치 (Measure of central tendency): 분포의 중심성을 나타내기 위한 값, 예시로는 평균, 중앙값.
-
'평균이 항상 좋은 중심경향값은 아니다.'라는 사실은 이해했음.
-
하지만 특수한 상황을 가정하면 평균이 좋은 중심경향값임
np.random.seed(43052)
y1=np.random.normal(loc=0,scale=1,size=10000) #전북고 A반의 통계학 성적이라 생각하자.
y2=np.random.normal(loc=0.5,scale=1,size=10000) #전북고 B반의 통계학 성적이라 생각하자.
np.mean(y1), np.mean(y2)
(np.mean(y2)-np.mean(y1)).round(3)
plt.boxplot([y1,y2])
- 분포의 모양이 거의 비슷하고, 왼쪽그림을 거의 컨트롤+C,V 오른쪽에 붙인다음 위치조정을 한 느낌
- 이런상황에서는 $B반의 성적 \approx A반의 성적 + 0.51$ 라고 주장해도 큰 무리가 없음.
-
정규분포인것은 어떻게 아는가? $\to$ 히스토그램을 그려보아서 종 모양이 나오는지 살펴보자.
plt.hist(y1,bins=50)
plt.hist(y2,bins=50)
plt.hist([y1,y2],bins=200)
import seaborn as sns
A=pd.DataFrame({'score':y1,'class':['A']*len(y1)})
B=pd.DataFrame({'score':y2,'class':['B']*len(y2)})
df=pd.concat([A,B],ignore_index=True)
sns.histplot(df,x='score',hue='class')
from plotnine import *
ggplot(df)+geom_histogram(aes(x='score',fill='class'),position='identity',alpha=0.5)
-
인터랙티브 그래프를 위해서 plotly 홈페이지를 방문하여 적당한 코드를 가져온다.
import plotly.figure_factory as ff
import numpy as np
hist_data=[y1,y2]
group_labels=['A','B']
fig = ff.create_distplot(hist_data, group_labels,
bin_size=.2, show_rug=False)
HTML(fig.to_html(include_plotlyjs='cdn',include_mathjax=False))
숙제
(1) 자기학번으로 np.random.seed(202043052)를 만들고
(2) y1, y2 // 10만개의 정규분포를 생성해서 저장
- y1: 평균 0, 표준편차=1
- y2: 평균 1, 표준편차=1
(3) plotly 를 활용하여 히스토그램을 겹쳐서 그려보는것.