잇연

[sesac LLM] day28-240208 판다스 활용 방법: 타입 변환부터 데이터 전처리까지 본문

SESAC LLM 개발자 강의/ML 머신러닝

[sesac LLM] day28-240208 판다스 활용 방법: 타입 변환부터 데이터 전처리까지

잇연 2024. 2. 8. 13:32

학습내용/목표

  • 학습내용/목표
    • Pandas, Numpy, Seaborn, Matplotlib 라이브러리를 활용한 데이터 시각화 및 통계 분석
    • 데이터 읽기 및 시각화된 자료 분석 방법 습득
    • 수치형 자료와 범주형 자료 분석 방법 학습
    • 다양한 Plot 활용 방법 학습 (snsplot 등)
    • 코로나 데이터 분석을 통한 수치형 자료, 시계열 자료 분석 실습

Mpg Dataset을 바탕으로 pandas, numpy, seaborn, matplotlib 실습

1. 데이터 불러오고 확인하기

1.1임포트하기

#import
import pandas as pd
# pandas 라이브러리를 pd라는 이름으로 임포트한다. 
#pandas는 데이터 분석을 위한 핵심 라이브러리로, 데이터프레임이라는 효율적인 데이터 구조를 제공한다.

import seaborn as sns
# seaborn 라이브러리를 sns라는 이름으로 임포트한다. 
#seaborn은 matplotlib 기반의 데이터 시각화 라이브러리로, 
#그래픽과 통계 플롯을 쉽게 만들 수 있다.

import numpy as np
# numpy 라이브러리를 np라는 이름으로 임포트한다. 
#numpy는 고성능의 수치 계산을 위한 라이브러리로, 다차원 배열 처리와 다양한 수학 함수를 제공한다.

import matplotlib.pyplot as plt
# matplotlib의 pyplot 모듈을 plt라는 이름으로 임포트한다. 
# matplotlib은 파이썬에서 데이터를 차트나 플롯으로 시각화하는 데 사용되는 기본 라이브러리이다.

위와같은 라이브러리 import를 해줘야한다.

 

1.2 데이터 셋 불러오기

df = sns.load_dataset("mpg")
df

mpg는 seaborn에 내장되어있는 샘플파일이다. 이 데이터를 활용할 수 있다.

mpg 데이터는 미국 EPA에서 1999년과 2008년에 조사하여 발표한 자동차 주요 모델별 연비 데이터입니다. mpg 데이터에는 cty(도시 연비), hwy(고속도로 연비)라는 두 가지 기준의 데이터가 존재합니다. 이 둘의 평균을 내서 '통합연비변수'를 생성할 수도 있습니다.

1.3 구조 파악하기

df.shape
(398, 9) #와 같이 컬럼과 행의 수를 알 수 있다.

데이터프레임.shape을 통해 컬럼과 행의 수를 알 수 있다. (행의수, 컬럼수)

1.4 데이터셋 일부만 가져오기

# 상위 5개 데이터만 불러오기
df.head()
# 하위 5개 데이터만 불러오기
df.tail()

.head()와 tail()은 데이터 순서상으로 상위 5개, 하위 5개를 추출해서 볼 수 있다.

1.5 요약하기

# info
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 398 entries, 0 to 397
Data columns (total 9 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   mpg           398 non-null    float64
 1   cylinders     398 non-null    int64  
 2   displacement  398 non-null    float64
 3   horsepower    392 non-null    float64
 4   weight        398 non-null    int64  
 5   acceleration  398 non-null    float64
 6   model_year    398 non-null    int64  
 7   origin        398 non-null    object 
 8   name          398 non-null    object 
dtypes: float64(4), int64(3), object(2)
memory usage: 28.1+ KB

 

info()는 각 컬럼과 데이터 타입, null값이 있는지 등을 알 수 있다.

 

1.6 결측치 보기

df.isnull()

isnull()은 데이터 널값여부를 True, False로 알려주는데, null이면 True로 나타낸다.

df.isnull().sum()

각행에 null값있는지 확인하는 방법으로 이걸 많이 쓴다.

특정 열에서 null값나오는 행을 추출해줄 수 도 있다.

df[df['horsepower'].isnull()]

 

결측치를 그래프로 확인하는 방법은 다음과 같다.

# 그래프 크기 설정
plt.figure(figsize=(12,8))
# 결측치 시각화
sns.heatmap(df.isnull(), cmap="Blues")

 

, 'horsepower' 변수에 소수의 결측치가 있는 것을 확인할 수 있다. 나머지 변수들은 결측치가 없는 것으로 보인다.

1.7 기술통계 보기

# 데이터 기술 통계값
df.describe()
#describe()는 데이터를 요약하고 분석할 때 유용하다.
mpg	cylinders	displacement	horsepower	weight	acceleration	model_year
count	398.000000	398.000000	398.000000	392.000000	398.000000	398.000000	398.000000
mean	23.514573	5.454774	193.425879	104.469388	2970.424623	15.568090	76.010050
std	7.815984	1.701004	104.269838	38.491160	846.841774	2.757689	3.697627
min	9.000000	3.000000	68.000000	46.000000	1613.000000	8.000000	70.000000
25%	17.500000	4.000000	104.250000	75.000000	2223.750000	13.825000	73.000000
50%	23.000000	4.000000	148.500000	93.500000	2803.500000	15.500000	76.000000
75%	29.000000	8.000000	262.000000	126.000000	3608.000000	17.175000	79.000000
max	46.600000	8.000000	455.000000	230.000000	5140.000000	24.800000	82.000000

 

1.8 nunique값 확인

nunique()는 각 컬럼 당 고유값들의 수를 출력해주는 함수이다.

# 데이터 unique 개수
df.nunique()
# 중복이 없는 것의 개수
mpg             129
cylinders         5
displacement     82
horsepower       93
weight          351
acceleration     95
model_year       13
origin            3
name            305
dtype: int64

예를 들면 apple, apple, banana 가 한 열에 있으면 2를 출력

 

2. 수치형 변수 분석하는 법

2.1. 수치형 변수 히스토그램

# hist()를 통해 전체 수치변수에 대한 히스토그램 그리기
# 막대 개수 50개로 설정
df.hist(figsize=(12,10),bins=50)
plt.show()

 

 

 

2.2 왜도와 첨도

비대칭도(왜도)

실수 값 확률 변수의 확률 분포 비대칭성을 나타내는 지표
왜도의 값은 양수나 음수가 될 수 있으며 정의되지 않을 수도 있음
왜도가 음수일 경우에는 확률밀도함수의 왼쪽 부분에 긴 꼬리를 가지며 중앙값을 포함한 자료가 오른쪽에 더 많이 분포
왜도가 양수일 때는 확률밀도함수의 오른쪽 부분에 긴 꼬리를 가지며 자료가 왼쪽에 더 많이 분포
평균과 중앙값이 같으면 왜도는 0 이다.

https://ko.wikipedia.org/wiki/%EB%B9%84%EB%8C%80%EC%B9%AD%EB%8F%84

df.skew()
mpg             0.457066
cylinders       0.526922
displacement    0.719645
horsepower      1.087326
weight          0.531063
acceleration    0.278777
model_year      0.011535
dtype: float64

 

  • mpg: 0.457066 - 약간 오른쪽으로 치우친 분포
  • cylinders: 0.526922 - 오른쪽으로 치우친 분포
  • displacement: 0.719645 - 상당히 오른쪽으로 치우친 분포
  • horsepower: 1.087326 - 매우 오른쪽으로 치우친 분포
  • weight: 0.531063 - 오른쪽으로 치우친 분포
  • acceleration: 0.278777 - 약간 오른쪽으로 치우친 분포
  • model_year: 0.011535 - 거의 정규 분포에 가까운 형태 (비대칭이 거의 없음)

첨도

  • 확률분포의 뾰족한 정도를 나타내는 척도
  • 관측치들이 어느 정도 집중적으로 중심에 몰려 있는가를 측정할 때 사용
  • 첨도값(K)이 3에 가까우면 산포도가 정규분포에 가까움
  • 3보다 작을 경우에는(K<3) 산포는 정규분포보다 더 뾰족한 분포(꼬리가 얇은 분포)
  • 첨도값이 3보다 큰 양수이면(K>3) 정규분포보다 더 완만한 납작한 분포(꼬리가 두꺼운 분포)

https://ko.wikipedia.org/wiki/%EC%B2%A8%EB%8F%84

2.3 Plot

2.3.1. 1개의 수치변수인 경우

displot을 통해 히스토그램과 kdeplot 같이 그리기

didsplot()은 여러 plot을 한번에 그릴 수 있는 기능이 있다.

# displot을 통해 히스토그램과 kdeplot 그리기
# hist, kde 그래프를 한번에 그리기
 #data가 어떻게 쏠려 있는지 볼 수 있다.

sns.displot(data=df,x="mpg",kde=True, rug=True)

kdeplot은 커널 밀도(kernel density)는 커널이라는 함수를 겹치는 방법으로 히스토그램보다 부드러운 형태의 분포 곡선을 보여주는 방법이다.

 

 

 

# kdeplot, rugplot으로 밀도함수 표현하기
# kde + rug plot
sns.kdeplot(data=df,x="mpg",shade=True)
sns.rugplot(data=df,x="mpg")

 

 

 

 

 

# boxplot 으로 mpg 의 사분위 수 표현하기
sns.boxplot(data=df,x="mpg")

# O 는 이상치를 의미한다.
#박스 안의 분포 보기 어려움

# describe 로 mpg의 기술통계 값 구하기
df["mpg"].describe()
count    398.000000
mean      23.514573
std        7.815984
min        9.000000
25%       17.500000
50%       23.000000
75%       29.000000
max       46.600000
Name: mpg, dtype: float64

 

# violinplot 으로 mpg 값 좀 더 자세히 보기
sns.violinplot(data=df,x="mpg")

 

boxplot과 kdeplot

# boxplot 으로 전체 변수 시각화하기
sns.boxplot(data=df)
# 전체 볌수의 표준편차 구하기
sns.violinplot(data=df)
#전체 분포는 보기 쉽지만 개별은 어렵다. 이럴 때는 개별 변수를 찍어서 보면 된다.

2.3.2  2개 이상의 수치변수

scatterplot을 통해 2개 이상의 수치변수 비교하기

# scatterplot 을 통해 2개의 수치변수 비교하기
sns.scatterplot(data=df,x="weight",y="mpg",hue="origin")
#일본 차는 비교적 무겁고 미국차는 비교적 가볍다

회귀 시각화

regplot

# regplot 으로 회귀선 그리기
sns.regplot(data=df, x="weight", y="mpg")

 

자동차의 무게(weight)와 연비(mpg) 사이의 관계를 분석하기 위한 선형 회귀 그래프를 생성한다.

sns.regplot은 데이터 포인트를 산점도로 표시하고, 데이터 포인트들 사이의 선형 추세선(회귀선)을 자동으로 그려준다.. 이를 통해 두 변수 사이의 상관관계와 선형 관계의 강도를 한눈에 파악할 수 있다.

 

잔차 시각화

# 회귀선의 잔차를 시각화 하기
sns.residplot(data=df,x="weight",y="mpg")

 

sns.residplot 함수는 선형 회귀선이 데이터를 얼마나 잘 표현하는지를 보여주기 위해, 각 데이터 포인트에서 실제 값과 회귀선에 의한 예측 값 사이의 차이(잔차)를 그래프로 그린다. 이 그래프를 통해 잔차의 패턴을 분석함으로써, 회귀 모델이 데이터의 특성을 적절히 포착했는지 확인할 수 있다. 잔차가 무작위로 분포하고 있으면 모델이 적합하다고 볼 수 있다. 반면에 명확한 패턴이 보인다면, 모델이 데이터의 구조를 완전히 포착하지 못했거나 비선형 관계가 있을 가능성이 있다.

 

서브플롯그리기

# lmplot 을 통해 범주값에 따라 색상, 서브플롯 그리기
sns.lmplot(data=df,x="weight",y="mpg",hue="origin",col="origin",truncate=False)

sns.jointplot은 두 변수 간의 관계와 개별 변수의 분포를 동시에 보여주는 시각화 도구이다. kind="hex" 옵션은 육각형 모양의 그래프를 사용하여 데이터 포인트들이 많이 몰려있는 영역을 진한 색으로 표현하고, 데이터 포인트들이 적게 분포한 영역을 연한 색으로 표현한다. 이 방식은 데이터의 밀도를 한눈에 파악하기 쉽게 해주며, 특히 많은 데이터 포인트를 포함하는 대규모 데이터셋에 유용하다.

 

 

pairplot

# pairplot 은 시간이 오래 걸리기 때문에 일부 샘플을 추출해 그려보고(100개)
# 샘플의 수를 늘려가며 그리는 걸 추천
# df_sample
df_sample = df.sample(100)
df_sample.shape

# origin 값에 따라 다른 색상으로 그리기
sns.pairplot(data=df_sample, hue="origin")

 

 

 

joinplot

# jointplot 2개의 수치변수 표현하기
sns.jointplot(data=df, x="weight", y="mpg", kind="hex")

sns.jointplot 함수를 사용한 코드는 데이터셋에서 'weight'과 'mpg' 두 수치형 변수 간의 관계를 헥사고날 빈(hex bin) 형태로 시각화하는 그래프를 생성한다. 여기서 kind="hex" 옵션은 플롯 안에 육각형 모양의 빈(bin)을 만들어 데이터 포인트의 밀도를 표현한다. 즉, 육각형 내부에 포함된 데이터 포인트가 많을수록 그 육각형은 더 진한 색으로 표시되고, 데이터 포인트가 적을수록 더 연한 색으로 표시된다.

lineplot

# lineplot으로 model_year, mpg를 시각화 합니다.
sns.lineplot(data=df, x="model_year", y="mpg", errorbar=None)

 

 

relplot

# relplot 으로 전체 수치 변수에 대한 시각화
sns.relplot(data=df)

2.4 상관관계

'상관관계' 또는 '상관'은 확률론과 통계학에서 두 변수간에 어떤 선형적 또는 비선형적 관계를 갖고 있는지를 분석하는 방법이다. 상관분석에서는 상관관계의 정도를 나타내는 단위로 모상관계수로 ρ를 사용하며 표본 상관 계수로 r 을 사용한다.

상관계수는 두 변수간의 연관된 정도를 나타낼 뿐 인과관계를 설명하는 것은 아니다.

 

# 데이터프레임 전체의 수치변수에 대해 상관계수를 구합니다.
corr = df.corr()
corr

가운데를 기준으로 양 값들이 대칭성을 보이고 있다. 둘중 하나는 필요없는 정보이다. 그래서 둘중 하나를 지우려면 상삼각행렬을 만들어서 시각화해주기도한다.'

# np.triu : matrix를 상삼각행렬로 만드는 numpy math
# [1 2 3]   np.triu  [1 2 3]
# [4 5 6]   -------> [0 5 6]
# [2 3 4]            [0 0 4]
# np.ones_like(x) : x와 크기만 같은 1로 이루어진 array를 생성

# 수식적으로 어려워 보일수도 있지만 간단함
# 자기상관계수는 대각행렬을 기준으로 대칭되어 같은 값이 출력되므로,
# 이대로 전체를 heatmap을 plot하면 오히려 가독성이 떨어질 수 있음
# 이에, 가독성을 높이기 위해 대각행렬 기준으로 한쪽의 데이터들만 masking 기법을 통해 plot하여
# 가독성을 높이는 효과를 가질수 있음
# np.ones_like로 heatmap의 마스크값 구하기
# mask
mask = np.triu(np.ones_like(corr))
mask

print(plt.colormaps())
# heatmap 을 통해 상관계수를 시각화한다.

sns.heatmap(corr, mask=mask, annot=True, vmax=1, vmin=-1, cmap="coolwarm")

 

 

 


3.범주형 변수 분석하는법

df = sns.load_dataset("mpg")
df.shape

빈도수 시각화

# countplot 으로 origin 빈도수 시각화 하기
sns.countplot(data=df, x="origin")

 

1개 변수 빈도수 구하기

# origin 의 빈도수 구하기
df['origin'].value_counts()

 

2개 이상의 변수에 대한 빈도수 구하기

# countplot 으로 origin 의 빈도수를 시각화 하고 cylinders 로 다른 색상으로 표현하기
sns.countplot(data=df, x="origin", hue="cylinders")

 

# countplot 으로 cylinders 의 빈도수를 시각화 하고 origin 으로 다른 색상으로 표현하기
sns.countplot(data=df, x="cylinders", hue="origin")

hue의 cylinders는 3,4,5,6,8수치형 변수로 취급되어 연속된 색상 그라데이션으로 표현되고, 

hue의 origin은 japan, europe, usa로 범주형 변수이므로 구분이 명확한 별개의 색상으로 표현되었음.

 

 

범주형 별 수치형 값 시각화

# barplot 으로 origin 별 mpg 값 구하기
sns.barplot(data=df, x="origin", y="mpg", hue="origin", errorbar=None)

groupby를 통한 연산

# groupby를 통해 origin 별로 그룹화 하고 mpg 의 평균 구하기
df.groupby("origin")["mpg"].mean()
origin
europe    27.891429
japan     30.450633
usa       20.083534
Name: mpg, dtype: float64

 

barplot으로 합계값 구하기

# barplot 으로 합계 값 구하기
sns.barplot(data=df, x="origin", y="mpg", estimator=np.sum, hue="origin", errorbar=None)

 

box 플롯과 4분위수

# boxplot 으로 origin 별 mpg 의 기술통계 값 구하기
sns.boxplot(data=df, x="origin", y="mpg", hue="origin")


 

서울시에서 공개한 코로나19 발생동향 분석 실습

데이터 출처 : https://news.seoul.go.kr/welfare/archives/540843

-전체 순서를 우선 훑어보자.

파일 불러오기

to_csv("파일명", index=False) : csv 파일로 저장하기
read_csv("파일명") : csv 파일 불러오기
Pandas를 통한 파일 저장과 불러오기

shape를 통한 행과 열의 수 보기
head, tail, sample 을 통한 일부 데이터 가져오기
DataFrame의 info(), describe() 등을 통한 요약과 기술통계 값 구하기

info()
describe()
nunique()
index
columns
values
Pandas의 DataFrame과 Series의 이해

Series : 1차원 벡터구조
DataFrame : 2차원 행렬구조
색인하기

[컬럼]
.loc[행]
.loc[행, 열]
.loc[조건식, 열]
DataFrame의 데이터 타입 이해하기

날짜 데이터의 변환
DataFrame 다루기

열(column) 인덱싱
행(index) 인덱싱
행, 열 인덱싱
정렬하기 : sort_values 사용하기
조건식 사용하기
빈도수 구하기

한 개의 변수 : series.value_counts()
두 개의 변수 : pd.crosstab()
groupby 와 pivot_table

다양한 연산식의 사용

 

 

글씨체 폰트설정

# 윈도우 : "Malgun Gothic"
# 맥 : "AppleGothic"
def get_font_family():
    """
    시스템 환경에 따른 기본 폰트명을 반환하는 함수
    """
    import platform
    system_name = platform.system()
    # colab 사용자는 system_name이 'Linux'로 확인

    if system_name == "Darwin" :
        font_family = "AppleGothic"
    elif system_name == "Windows":
        font_family = "Malgun Gothic"
    else:
        !apt-get install fonts-nanum -qq  > /dev/null
        !fc-cache -fv
        !rm ~/.cache/matplotlib -rf

        import matplotlib as mpl
        import matplotlib.font_manager as fm

        fe = fm.FontEntry(fname=r'/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf', name='NanumGothic')
        fm.fontManager.ttflist.insert(0, fe)  # Matplotlib에 폰트 추가

        font_family = "NanumBarunGothic"
    return font_family


plt.style.use("seaborn-v0_8-whitegrid")

# 폰트설정
plt.rc("font", family=get_font_family())
# 마이너스폰트 설정
# plt.rc("axes", unicode_minus=False)
plt.rcParams['axes.unicode_minus'] = False

# 그래프에 retina display 적용
%config InlineBackend.figure_format = 'retina'

데이터 불러오기

import glob

glob.glob("/content/drive/MyDrive/경로/파일명.csv")
df= pd.read_csv("/content/drive/MyDrive/경로/파일명.csv")

 

이 데이터는 두개의 csv 파일로 나눠져있었어서 각각의 파일을 df_01, df_02로 불러온 뒤 df = pd.concat([df_01, df_02]) 를 해서 합쳐준다. 

 

기술 통계나 unique값 찾기 등은 위에 있으므로 생략....아니 간략하게 정리하고 넘어감

df.shape-> 행열확인, df.types-> 컬럼들 타입 확인, df.columns -> 컬럼 나열, df.info-> 데이터 요약(컬럼별 nonnull개수, dtype), df.isnull().sum() -> 결측치의 합계 구하기, df.isnull().mean()-> 결측치 비율 구하기, df.describe()-> 기술통계

 

중복 제거하기

df = df.drop_duplicates()
df.shape

 

날짜 데이터 타입 변경하기

# pd.to_datetime 을 통한 데이터 타입 변경하기
df["확진일"] = pd.to_datetime(df["확진일"])
df["연도"] = df["확진일"].dt.year
df["월"] = df["확진일"].dt.month
df["일"] = df["확진일"].dt.day
df["요일"] = df["확진일"].dt.dayofweek
# head 로 일부만 가져와 파생변수가 잘 생성되었는지 확인하기
df.head(1)
218646	611159	2021-12-26	노원구	-	감염경로 조사중	NaN	2021	12	26	6

 

"연도 - 월 " 컬럼 만들기

# 연도-월 파생변수 만들기
# astype(str) 을 통해 수치 데이터를 문자 데이터로 변환하고 문자열 연결하기
df["연도"].astype(str) + "-" + df["월"].astype(str)
# 문자열 슬라이싱으로도 만들 수 있습니다.
# df["연도월"]

df["연도월"] = df["확진일"].astype(str).str[:7]

 

 

 

숫자로 입력된 요일을 한글로 만들기

dayofweek = "월화수목금토일"
dayofweek[0]
#find_dayofweek 함수로 요일 숫자를 넘겨주면 요일명을 반환하는 함수

def find_dayofweek(day_no):
    dayofweek = "월화수목금토일"
    return dayofweek[day_no]
# 함수가 잘 만들어졌는지 확인하기
find_dayofweek(1)
# map을 사용해서 요일 컬럼을 요일명으로 변환하고 "요일명"이라는 새로운 컬럼에 저장하기
# map 은 시리즈에만 사용 가능하다.
df["요일명"] = df["요일"].map(find_dayofweek)

 

전체 수치변수 히스토그램 그리기

# df.hist로 히스토그램 그리기
df.hist(figsize=(12, 10), bins=100)
plt.show()

 

연도- 월에 대한 빈도수 구하고 시각화하기

year_month = df["연도월"].value_counts().sort_index()
year_month.head(3)
# 연도월을 시각화 합니다.
year_month.plot(title='연도월별 확진 수', figsize=(12, 4))

 

확진일 빈도수구하기

# 선 그래프로 시각화 하기
day_count.plot(figsize=(12, 4), title="일자별 확진 수")
plt.axhline(1000, c="r", linestyle=":")
# 선 그래프로 시각화 하기
day_count.plot(figsize=(12, 4), title="일자별 확진 수")
plt.axhline(1000, c="r", linestyle=":")

 

 

거주지 전처리

# 텍스트 앞뒤 공백 제거하기
df["거주구"] = df["거주구"].str.strip()
# "거주구" 빈도수 구하기
gu_count = df["거주구"].value_counts()
gu_count
# gu_count 변수에 담긴 값 시각화 하기
gu_count.plot(kind="bar", figsize=(15, 4), rot=60, title="구별 확진 수")

연도, 월 두 개의 변수에 대한 빈도수 구하기

# pd.crosstab 으로 연도, 월 두 개의 변수에 대한 빈도수 구하기
ym = pd.crosstab(df["연도"], df["월"])
ym

 

시각화하기

# 시각화 하기
ym.plot.bar(rot=0, figsize=(12,3))