촉촉한초코칩

파이썬으로 시작하는 데이터 사이언스 - 4강 본문

Study/Big Data

파이썬으로 시작하는 데이터 사이언스 - 4강

햄친구베이컨 2023. 11. 9. 00:53
1. 라이브러리 로드하고 한글폰트 설정하기

 

라이브러리 로드

import pandas as pd              #데이터 분석용 라이브러리
import numpy as np               #수치 계산 라이브러리
import seaborn as sns            #matplotlib을 사용하기 쉽게 만든 시각화 라이브러리 
import matplotlib.pyplot as plt  #그래프 폰트, 스타일, 사이즈 변경, 서브 플롯 사용 라이브러리

%matplotlib inline #구버전 노트북에서는 이 설정을 해줘야 노트북 상에서 그래프가 표시된다.

 

한글폰트 설정

#jupyter notebook
import os
if os.name == 'poxis':
   plt.rc("font, family="AppleGothic")
else
   plt.rc("font, family="Malgun Gothic")
plt.rc("axes", unicode_minus=False) #마이너스 폰트가 깨지는 문제를 대처하기 위해 작성

!pip install koreanize-matplotlib

import koreanize_matplotlib

%config inlineBackend.figure_format='retina'

국민건강정보데이터 건강검진정보 사용자 매뉴얼_20171027.pdf
1.08MB

 

2. 데이터셋 소개와 로드하기 - 가설세우기

 

  • 공공데이터포털에서 건강검진정보를 다운받는다.
  • pd.read_까지 입력하여 tab 키를 누르면 불러올 수 있는 다양한 형태의 데이터를 확인할 수 있다.
  • shift+tab을 하면 라이브러리 옵션을 볼 수 있다.
  • ?을 사용하면 더 자세한 설명을 볼 수 있다.
pd.read_csv("파일명", encoding="cp949")

#데이터 크기 확인하기
df.shape  

#데이터 미리보기 
df.head()
df.tail() #뒤에서 가져오기 

#1개의 데이터만 예시로 가져오기
df.sample()

#기본 정보 보기 - 행/열개수, 결측치 등
df.info()

#column 이름만 보기
df.columns

#데이터 타입 출력
df.dtypes

 

3. 로드한 데이터의 결측치를 보고 요약, 집계하기 - info, isnull, value_counts

 

#결측치 보기 - 결측치를 bool 값으로 표시하고 sum()으로 결측치의 수를 세어준다.
df.isnull()
df.isna().sum() #isna()로도 결측치 수를 집계할 수 있다.

#판다스에 내장 된 plot을 통해 시각화한다.
#barh로 글씨를 y축에 두고, figsize로 사이즈를 조절한다.
df.isnull().sum().plot.barh(figsize=(10,9))

#일부 데이터 요약하기
#1개의 열을 가져오면 series 형태의 데이터 구조로 결과가 나타난다.
df["(혈청치오티)ALT"]
#2개 이상을 가져올 때는 리스트로 감싸준다.
#2개의 열을 가져오면 dataframe 형태의 데이터 구조로 결과가 나타난다.
df[["(혈청지오티)ALT","(혈청지오티)AST"]]

#5개의 행을 series 형태로 불러온다.
df["(혈청지오티)ALT"].head()
#5개의 행을 dataframe 형태로 불러온다.
df["(혈청지오티)ALT", "(혈청지오티)AST"]].head()

#수치 데이터 요약보기
#결측치를 제외한 count, mean(평균), std(표준편차), min, max, 50%, 25%, 75%
df["(혈청지오티)ALT", "(혈청지오티)AST"]].describe()

#값 집계하기
#value_counts()로 카테고리나 text 형태 데이터의 빈도수를 체크한다. 
df["성별코드"].value_counts()

 

4. groupBy와 pivot_table로 다양한 집계 연산 하기

 

2개 이상의 데이터를 보기 위해서는 groupby와 pivot_table을 사용한다. 

 

groupby

#groupby
#성별코드 값에 따라 모든 열에 대한 평균을 구한다. 
df.groupby(["성별코드"]).mean()
df.groupby(["성별코드"]).count()

#남성, 여성이 얼마나 되는지 알아본다. 
#여러 개의 column, 값들을 알아볼 수 있다.
df.groupby(["성별코드"])["가입자일련번호"].count()

#성별코드에 따라 음주 상태를 알아본다.
df.groupby(["성별코드", "음주여부"])["가입자일련번호"].count()
df.groupby(["성별코드", "음주여부"])["감마지티피"].mean()
df.groupby(["성별코드", 음주여부"])["감마지티피"].agg(["count","mean","median"])

 

pivot_table

#pivot은 연산을 하지 않고 데이터의 구조를 바꾸고자 할 때 사용한다. 
df.pivot

#나머지 수치 데이터를 불러온다.
#기본적으로 dataframe 형태로 결과가 출력된다.
df.pivot_table(index="성별코드", values="가입자일련번호", aggfunc="count")
df.pivot_table(index="음주여부", values="가입자일련번호", aggfunc="count")

pd.pivot_table(df, index="음주여부", values="감마지티피")
pd.pivot_table(df, index="음주여부", values="감마지티피", aggfunc=["mean", "median"])
pd.pivot_table(df, index=["음주여부", "성별코드"], values="감마지티피", aggfunc="describe")

감마지피티 데이터를 성별코드와 음주여부를 기준으로 불러온다. 

 

5. 히스토그램으로 전체 수치 데이터를 한번에 시각화 하기

 

100만개가 넘는 데이터를 시각화할 때는 속도가 느리기 때문에 groupby 또는 pivot_table로 연산하는 것이 좋다.

 

히스토그램

#df.hist()를 변수에 넣으면 출력값 없이 바로 시각화를 출력해준다.
h = df.hist(figsize=(12,12))

#iloc[]를 통해 몇 번째에 있는 특정한 행, 열을 사용할 것인지 지정할 수 있다. 
#슬라이싱하면 속도가 빨라진다. 
#0부터 11번째 행까지 그려본다.
h = df.iloc[;, ;12].hist(figsize=(12,12))
#12~23번째 행
h = df.iloc[:, 12:24].hist(figsize(12,12))

#bins 옵션으로 막대의 개수를 잘게 그린다.
h = df.iloc[:, 12:24].hist(figsize(12,12), bins=100)

#히스토그램은 연속된 데이터를 카테고리형으로 만든다.
h = df.iloc[:, 24:].hist(figsize(12,12), bins=100)

 

6. 데이터의 빈도수 시각화 하기(막대그래프1) - countplot

 

  • seaborn은 matplotlib을 쉽게 쓸 수 있는 highlevel interface고, 통계 지식 없이 고급 통계 그래프를 구현할 수 있다.
  • 범주형 데이터, 수치형 데이터에 따라 시각화에 접근하는 방식이 달라진다.

 

#random_state=1을 사용하면 1,000,000개 중 랜덤으로 정해준 개수만큼 가져온다.
df.sample(1000, random_state=1)

 

countplot

df["음주여부"].value_counts().plot.bar()

#sns.countplot()은 x, y, data를 지정한다. 
sns.countplot(x="음주여부", data=df)

#hue : 성별코드로 색상을 구분하여 그려본다.
sns.countplot(x="음주여부", data=df, hue="성별코드")

sns.set(font_scale=1.5, font="AppleGothic")

#특정 범위로 연속형 데이터를 묶으면 범주형 데이터로 볼 수 있다.
sns.countplot(data=df, x="연령대코드(5세단위)", hue="음주여부")

#레이블 값이 잘 안 보인다면 plt.figure으로 크기를 조절 할 수 있다.
plt.figure(figsize=(15,4))
sns.countplot(data=df, x="신장(5cm단위)")

#성별코드에 따라서 신장을 알 수 있다. 
plt.figure(figsize=(15,4))
sns.countplot(data=df, x="체중(5kg단위)", hue="성별코드")

 

7. 수치형 vs 범주형 데이터의 시각화(막대그래프2) - barplot

 

sns.barplot(data=df, x="연령대코드(5세단위)", y="총콜레스테롤")

#속도가 오래 걸리므로 sample을 먼저 그려본다.
sns.barplot(data=df_sample, x="연령대코드(5세단위)", y="총콜레스테롤", hue="음주여부")

plt.figure(figsize=(15,4))
sns.barplot(data=df_sample, x="연령대코드(5세단위)", y="총콜레스테롤", hue="흡연상태")

#신뢰구간 (ci)
#95%의 신로구간을 지정한다.
sns.barplot(data=df_sample, x="연령대코드(5세단위)", y="트리글리세라이드", hue="음주여부", ci=95)

#신뢰구간을 표준편차로 지정한다. 
sns.barplot(data=df_sample, x="연령대코드(5세단위)", y="트리글리세라이드", hue="음주여부", ci=sd)
# > 음주를 하는 사람이 트리글리세라이드(중성지방수치)가 높은 경향이 있다.

#신뢰구간을 표시하고 싶지 않다면 None을 설정한다.
sns.barplot(data=df_sample, x="연령대코드(5세단위)", y="체중(5kg 단위)", hue="성별코드", ci=None)

sns.barplot(data=df_sample, x="연령대코드(5세단위)", y="체중(5kg 단위)", hue="음주여부", ci=None)

 

8. 수치형 vs 범주형 데이터 선그래프로 그리기 - lineplot, pointplot

 

  • barplot : 막대로 개별값을 표현한다.
  • lineplot, pointplot : 선으로 기울기까지 표현할 수 있다. 
    가격, 매출/제고 데이터는 대체로 lineplot, pointplot으로 그리는 것이 좋다. 

 

#lineplot
plt.figure(figsize=(15,4))
#y축은 평균값이다.
#lineplot은 편차와 신뢰구간을 그림자로 표현한다. 그래프 뒤쪽에 그림자가 없는 이유는 모수가 적어서 편차를 그릴 게 없기 떄문이다.
sns.lineplot(data=df, x="연령대코드(5세단위)", y="체중(5kg 단위)", hue="성별코드")

plt.figure(figsize=(15,4))
sns.lineplot(data=df, x="연령대코드(5세단위)", y="신장(5cm 단위)", hue="성별코드", ci="sd")

plt.figure(figsize=(15,4))
sns.lineplot(data=df, x="연령대코드(5세단위)", y="신장(5cm 단위)", hue="음주여부", ci="sd")

#pointplot : 막대를 통해 편차와 신뢰구간을 표현한다. 
plt.figure(figsize=(15,4))
sns.pointplot(data=df, x="연령대코드(5세단위)", y="신장(5cm 단위)", hue="음주여부", ci="sd")

plt.figure(figsize=(15,4))
sns.lineplot(data=df, x="연령대코드(5세단위)", y="신장(5cm 단위)", hue="음주여부", ci="sd")
sns.pointplot(data=df, x="연령대코드(5세단위)", y="신장(5cm 단위)", hue="음주여부", ci="sd")

plt.figure(figsize=(15,4))
sns.pointplot(data=df, x="연령대코드(5세단위)", y="신장(5cm 단위)", hue="성별코드", ci="sd")

plt.figure(figsize=(15,4))
sns.pointplot(data=df, x="연령대코드(5세단위)", y="혈색소", ci=None)

sns.pointplot(data=df, x="연령대코드(5세단위)", y="혈색소", hue="음주여부", ci=None)

 

9. 데이터를 좀 더 자세히 표현하기 - boxplot, violinplot 그리기

 

https://pandas.pydata.org/pandas-docs/stable/user_guide/visualization.html

boxplot

  • 박스와 수염이 있는 모양이어서 box and whisker plot으로 불린다. 
  • 특정 column 값들을 boxplot으로 그릴 수 있다.
  • 박스의 밑은 1사분위수, 중간은 2사분위수, 위는 3사분위수이다. 

 

plt.figure(figsize=(15,4))
sns.boxplot(data=df, x="신장(5cm 단위)", y="체중(5kg 단위)")

plt.figure(figsize=(15, 4))
sns.boxplot(data=df, x="신장(5Cm단위)", y="체중(5Kg 단위)", hue="성별코드")

#사분위수 범위(IQR)은 3사분위수 - 1사분위수이다.
#3사분위수보다 1.5 x IQR 이상을 초과하는 값과 Q1보다 1.5 x IQR 이상 미달하는 값은 이상치이다. 
#점, 원, 별표 모양으로 표현합니다.
plt.figure(figsize=(15, 4))
sns.boxplot(data=df, x="신장(5Cm단위)", y="체중(5Kg 단위)", hue="음주여부")

 

violinplot

  • boxpot의 단점을 보완하여 더 자세하게 보여주는 그래프이다.

 

plt.figure(figsize=(15, 4))
sns.violinplot(data=df, x="신장(5Cm단위)", y="체중(5Kg 단위)")

plt.figure(figsize=(15, 4))
sns.violinplot(data=df_sample, x="신장(5Cm단위)", y="체중(5Kg 단위)", hue="음주여부")

#split 옵션을 사용하면 두 개의 데이터를 붙여서 볼 수 있다.
plt.figure(figsize=(15, 4))
sns.violinplot(data=df_sample, x="신장(5Cm단위)", y="체중(5Kg 단위)", hue="음주여부", split=True)

plt.figure(figsize=(15, 4))
sns.violinplot(data=df_sample, x="연령대코드(5세단위)", y="혈색소", hue="음주여부", split=True)
# > x축의 16에서 보면 음주하는 사람들의 값이 확연히 높고, 전체적으로 더 위에 분포하는 것을 볼 수 있다.

 

swarm plot

#산점도를 통해 데이터를 찍어볼 수 있다.
plt.figure(figsize=(15, 4))
sns.swarmplot(data=df_sample, x="신장(5Cm단위)", y="체중(5Kg 단위)", hue="음주여부")

plt.figure(figsize=(15, 4))
sns.swarmplot(data=df_sample, x="신장(5Cm단위)", y="체중(5Kg 단위)", hue="음주여부")
sns.violinplot(data=df_sample, x="신장(5Cm단위)", y="체중(5Kg 단위)")

plt.figure(figsize=(15, 4))
sns.swarmplot(data=df_sample, x="연령대코드(5세단위)", y="혈색소", hue="음주여부")

 

implot

  • scatterplot과는 다르게 회귀선을 확인해볼 수 있다.
sns.lmplot(data=df_sample, x="연령대코드(5세단위)", y="혈색소", hue="음주여부")

#col이라는 옵션으로 색상을 다르게 하여 데이터를 분류해볼 수 있다.
sns.lmplot(data=df_sample, x="연령대코드(5세단위)", y="혈색소", hue="음주여부", col="성별코드")

 

  • 값들이 겹쳐서 보이는데 분포를 보고 싶다면 swarmplot을 사용하는 게 좋다. 회귀선을 그리거나 다변수 시각화를 할 때 좋다.
  • x축에도 수치형 데이터를 넣어도 되지만 막대가 너무 많으면 보기에 불편합니다. barplot을 기울기로 보고 싶다면 lineplot이 좋다.
  • boxplot을 그리면 이상치를 확인하기 좋습니다. violinplot은 분포를 더 자세히 볼 수 있다.

 

10. 산점도(산포도)와 회귀선 상관관계 보기 - scatterplot, lmplot

 

scatterplot

  • tab 키를 활용해서 자동완성을 활용할 수 있다.
  • option을 보면 다른 그래프와 사용 방법이 비슷하다.
  • 수치형 데이터, 그래프의 이상치를 파악할 때 사용하기 좋다.
sns.scatterplot(data=df, x="(혈청지오티)AST", y="(혈청지오티)ALT")

sns.scatterplot(data=df_sample, x="(혈청지오티)AST", y="(혈청지오티)ALT", hue="음주여부")

#연속형 데이터도 넣을 수 있다.
sns.scatterplot(data=df_sample, x="(혈청지오티)AST", y="(혈청지오티)ALT", hue="허리둘레")

#size 옵션을 사용해서 체중에 따라 크기를 다르게 지정할 수 있다.
plt.figure(figsize=(8, 7))
sns.scatterplot(data=df_sample, x="(혈청지오티)AST", y="(혈청지오티)ALT", hue="음주여부", size="체중(5Kg 단위)")

 

implot

  • 상관관계를 더 잘 파악할 수 있다.
  • 그리드처럼 격자로 나온다. categorical 데이터로 인식하기 때문이다.
  • 여러 카테고리 값에 따라 subplot을 그릴 수 있다.
sns.lmplot(data=df_sample, x="신장(5Cm단위)", y="체중(5Kg 단위)", hue="음주여부")

#왼쪽 아래에서 오른쪽 위로 선이 그려지면 양의 상관관계가 있다고 표현한다.
sns.lmplot(data=df_sample, x="신장(5Cm단위)", y="체중(5Kg 단위)", hue="성별코드", col="음주여부")

sns.lmplot(data=df_sample, x="신장(5Cm단위)", y="체중(5Kg 단위)", hue="음주여부", col="성별코드")

sns.lmplot(data=df_sample, x="신장(5Cm단위)", y="체중(5Kg 단위)", hue="흡연여부", col="음주여부")

sns.lmplot(data=df_sample, x="수축기혈압", y="이완기혈압", hue="음주여부")

sns.lmplot(data=df_sample, x="(혈청지오티)AST", y="(혈청지오티)ALT")

sns.lmplot(data=df_sample, x="(혈청지오티)AST", y="음주여부")

#robust 옵션을 활용하면 이상치를 빼고 그린다. 
#seaborn의 장점은 값만 넣어주면 그래프를 자동으로 그려준다.
#이상치가 있으면 회귀선이 영향을 많이 받으므로 robust 옵션을 사용해주는 것이 좋다.
sns.lmplot(data=df_sample, x="(혈청지오티)AST", y="음주여부", robust=True)

 

이상치 다루기

#범위를 지정하여 데이터셋을 만들어준다.
df_ASLT = df_sample[(df_sample["(혈청지오티)AST"] < 400) & (df_sample["(혈청지오티)ALT"] < 400)]

#범위를 지정하여 변수로 만들어주면 그래프를 그리는 데에 시간이 더 짧게 걸린다.
sns.lmplot(data=df_ASLT, x="(혈청지오티)AST", y="(혈청지오티)ALT", hue="음주여부", ci=None)

df_ASLT_high = df_sample[(df["(혈청지오티)AST"] > 400) | (df["(혈청지오티)ALT"] > 400)]

sns.lmplot(data=df_ASLT_high, x="(혈청지오티)AST", y="(혈청지오티)ALT", hue="음주여부", ci=None)

#특정 칼럼들에 따라 이상치를 따로 확인해볼 수 있다.
df_ASLT_high_8000 = df_ASLT_high[df_ASLT_high["(혈청지오티)AST"] > 8000]
df_ASLT_high_8000.iloc[:, 10:27]

 

11. 수치형 데이터의 분포를 표현하기 - distplot

 

scatterplot : x, y가 모두 수치형 데이터일 때 그릴 수 있다.

distplot

  • 히스토그램(도수분포표에 따라 그림을 그리는 것)을 그려준다.
  • 계급에 따라 데이터의 개수를 세어준다.
  • 결측치가 있으면 그릴 수 없다.
df_chol = df.loc[df["총콜레스테롤"].notnull(), "총콜레스테롤"]
df_chol.head()

#총콜레스테롤을 부드러운 곡선과 막대로 표현할 수 있다.
#히스토그램은 막대를 나타내고, 히스토그램을 부드러운 곡선으로 처리해주는 것이 확률밀도함수이다.
#왜도와 첨도도 확인할 수 있다.
sns.distplot(df_chol)

#bin으로 데이터를 몇 개로 나눠 담을 것인지 설정한다.
#이상치 때문에 그래프가 한쪽으로 몰리는 것을 볼 수 있다. max 값이 지나치게 크기 때문이다.
sns.distplot(df_chol, bins=10)

df[df["총콜레스테롤"].notnull() & (df["음주여부"] == 1)]

#displot은 series데이터를 넣어줘야 한다.
sns.distplot(df.loc[(df["총콜레스테롤"].notnull()) & (df["음주여부"] == 1), "총콜레스테롤"])

sns.distplot(df.loc[(df["총콜레스테롤"].notnull()) & (df["음주여부"] == 0), "총콜레스테롤"])

#hist=False로 설정해주면 선만 나온다.
sns.distplot(df.loc[(df["총콜레스테롤"].notnull()) & (df["음주여부"] == 1), "총콜레스테롤"], hist=False)
sns.distplot(df.loc[(df["총콜레스테롤"].notnull()) & (df["음주여부"] == 0), "총콜레스테롤"])

#확률밀도함수만 그리기 위해 kdeplot을 그린다.
sns.kdeplot(df.loc[(df["총콜레스테롤"].notnull()) & (df["음주여부"] == 1), "총콜레스테롤"])
sns.kdeplot(df.loc[(df["총콜레스테롤"].notnull()) & (df["음주여부"] == 0), "총콜레스테롤"])

#label을 넣어서 각 데이터를 설명해준다.
sns.kdeplot(df.loc[(df["총콜레스테롤"].notnull()) & (df["음주여부"] == 1), "총콜레스테롤"], label="음주 중")
sns.kdeplot(df.loc[(df["총콜레스테롤"].notnull()) & (df["음주여부"] == 0), "총콜레스테롤"], label="음주 안 함")

#plt.axvline()을 사용하여 그래프에 평균값과 중앙값 선을 그린다.
plt.axvline(df_sample["총콜레스테롤"].mean(), linestyle=":")
plt.axvline(df_sample["총콜레스테롤"].median(), linestyle="--")
sns.kdeplot(df_sample.loc[(df_sample["총콜레스테롤"].notnull()) & (df["음주여부"] == 1), "총콜레스테롤"], label="음주 중")
sns.kdeplot(df_sample.loc[(df_sample["총콜레스테롤"].notnull()) & (df["음주여부"] == 0), "총콜레스테롤"], label="음주 안 함")

#음주 여부에 따른 감마지피티를 확인한다. 
s_1 = df_sample.loc["음주여부"] == 1, "감마지티피"]
s_0 = df_sample.loc["음주여부"] == 0, "감마지티피"]
sns.distplot(s_1, label="음주 중")
sns.distplot(s_0, label="음주 중")

 

12. 상관계수 - heatmap 으로 표현하기

 

상관계수

  • 변수들 간의 관계를 알아볼 때 유용한 개념이다.
  • 특정 데이터에 대한 상관관계를 볼 수 있다.
  • 상관계수는 -1부터 1사이로 구성되고, 0.3부터 0.7 사이면 뚜렷한 양적 선형관계, 0.7 이상이면 강한 양적 상관관계라 할 수 있다.
  • 상관계수를 계산할 때 대각선이 1인 이유는 자기자신과 가장 관계가 있기 때문이다.
    -는 음의 상관관계이고, +는 양의 상관관계이다.
  • 우선 columns 변수 안에 상관계수에 사용할 컬럼들을 담는다.

 

df_small = df_sample[columns]
df_corr = df_small.corr()
df_corr

#0에 가까우면 상관관계가 없다고 볼 수 있다.
df_corr["신장(5Cm단위"].sort_values()

#신장과의 상관계수가 0.3 이상인 feature만 가져온다.
df_corr.loc[df_corr["신장(5Cm단위"] > 0.3, "신장(5Cm단위)"]

#음주여부와의 상관계수가 0.3 이상인 feature만 가져온다.
df_corr.loc[df_corr["음주여부"] > 0.1, "음주여부"]

df_corr["음주여부"].sort_values()

#상관계수는 두 변수 간의 연관된 정도만 나타낼 뿐 인과관계를 설명하는 것은 아니다.
df_corr.loc[df_corr["음주여부"] > 0.25, "음주여부"]

#혈색소와의 상관계수를 내림차순으로 정렬한다.
df_corr["혈색소"].sort_values(ascending=False).head(7)

#간수치와 관련된 값들이 상위로 나온다.
df_corr["감마지티피"].sort_values(ascending=False).head(7)

 

heatmap

  • 바로 data만 넣어준다.
  • 상관관계가 클수록 값의 색이 진해진다.
  • annot 옵션으로 숫자를 나타낼 수 있고, fmt으로 소수점 개수를 지정할 수 있고, cmap으로 색상을 지정할 수 있다.
plt.figure(figsize=(20,7))
sns.heatmap(df_corr, annot=True, fmt=".2f", cmap="Blues")

#공식문서에서 매트릭스의 대각선 아래만 표시하는 mask 설정을 가져온다.
mask = np.triu(np.ones_like(corr, dtype=np.bool))
plt.figure(figsize=(20, 7))
sns.heatmap(df_corr, annot=True, fmt=".2f", cmap="Blues", mask=mask)
#그 외로 vmax, vmin은 색상 농도를 지정하는 옵션이다.