본문 바로가기
데이터 분석 및 시각화

[데이터분석] 데이터 정제(전처리), 그래프 종류 확인 및 실습해보기

by 바다의 공간 2024. 8. 5.

Contents

# 데이터 정제

# 그래프 만들기

# 데이터 정제 및 그래프 만들기 실습


 

데이터 정제 결측치, 이상치, 극단치 정제

 

# 결측치(missing value)는 측정되지 않은 값, 또는 누락된 값

# 이상치(anormaly value)는 이상한 값, 또는 범위를 크게 벗어난 값

# 극단치(outlier value)는 극단적으로 크거나 작은 값

# 결측치, 이상치, 극단치가 수집데이터에 있는 경우는 분석결과가 왜곡될 수 있으므로 적절한 기준을 세워 제거하거나 대체하는 전처리 작업이 필요함

 

#실습

#datacleaning.py

def p(str):
    print(str, '\n')

#  결측치 : 값이 측정되지 않았거나 빠져있는 데이터를 의미함

# 결측치 생성할 때 : np.nan
import pandas as pd
import numpy as np

#결측치를 np.nan으로 채움
df = pd.DataFrame({
    "name": ["홍길동", "강감찬", np.nan, "이순신"],
    "score": [100, 90, 80, np.nan]
})
p(df)

# 결측치가 있는 상태에서의 연산 : NaN은 연산이 불가함.
# NaN은 숫자가 아니라는 숫자, 즉 값을 모름
df["compscore"]= df["score"] - 10
p(df)

# 결측치 확인
# 결측치를 True로 표시
p(pd.isnull(df))

# 결측치 개수(빈도) 확인
p(pd.isna(df).sum())

# 결측치 제거
p(df.dropna(subset=["score"])) #1개 뺼대
p(df.dropna(subset=['name', 'score'])) #여러개 뺄 때

# 결측치 대체(impultation)
df.loc[[2], ["name"]] = "유관순"
p(df)
df.loc[[3], ["score"]] = 70
p(df)
df['compscore'] = df['compscore'].fillna(80)
p(df)

# 이상치 : 데이터가 존재하는데, 이상한 데이터, 즉 빼야할 데이터
df2= pd.DataFrame({
    "name": ["홍길동", "강감찬", "에어컨"],
    "score": [100, 120, 80]
})

#이상치 개수 확인
p(df2["name"].value_counts())
p(df2["score"].value_counts())
p(df2)

# 이상치를 결측치로 처리 (score가 100보다 크면 이상치로 본다)
df2["score"] = np.where(df2["score"]>100, np.nan, df2["score"])
p(df2)

#이상치를 결측치 처리 (사람 이름이 아닌 경우 이상치로 본다)
df2["name"] = np.where(df2["name"]=="에어컨", np.nan, df2["name"])
p(df2)

# 극단치 : 정상적으로 측정된 값이 긴 하지만
#        다른값들에 비해서 너무 크거나 너무 작아서 분석이나 통계에
#        지대한 영향을 미치게 되면 이상치로 치부

# seaborn 외부라이브러리를 이용한 그래프
import seaborn as sns
import matplotlib.pyplot as plt
mpg = pd.read_csv('../assets/mpg.csv')
sns.boxplot(data=mpg, y="hwy")
# plt.show()

#극단치 기준값 (Q1, Q3)
pct25 = mpg["hwy"].quantile(.25) #25값이 무엇?
pct75 = mpg["hwy"].quantile(.75) #75%값이 무엇?
p(pct25)
p(pct75)

# IQR(Inter Quantile Range: 사분위 범위)
#   1사분위 값과 3사분위 값간의 거리
iqr = pct75 - pct25
p(iqr) #값이 크면? 범위가 넓다는 뜻

#상한, 하한 기준 정하기 (인간이 세우는 기준)
downlimit = pct25 - (1.5 * iqr) # 4.5
uplimit = pct75 + (1.5 * iqr) # 40.5
p(uplimit)
p(downlimit)

# 정한 극단치 기준(상한, 하한)으로 극단치를 처리
mpg["hwy"] = np.where(
    (mpg["hwy"]< downlimit) | (mpg["hwy"]>uplimit),
    np.nan,
    mpg["hwy"]
)
p(mpg["hwy"])
p(mpg["hwy"].value_counts())

# 결측치 빈도(개수)
p(mpg["hwy"].isnull().sum())

#결측치 제거
# dropna : 결측치 제거
# groupby: drv가 같은 값인 것들을 그룹핑
# agg: hwy의 평균값을 mean_hwy에 저장

p(mpg.dropna(subset=["hwy"]).groupby("drv").agg(mean_hwy=("hwy", "mean")))




 

결측, 이상 극단치에대한 개념을 정확하게 알아야하고 헷갈리지 말아야합니다.

 

위 코드의 포인트

# IQR(Inter Quantile Range: 사분위 범위)
#   1사분위 값과 3사분위 값간의 거리
iqr = pct75 - pct25
p(iqr) #값이 크면? 범위가 넓다는 뜻

#상한, 하한 기준 정하기 (인간이 세우는 기준)
downlimit = pct25 - (1.5 * iqr) # 4.5
uplimit = pct75 + (1.5 * iqr) # 40.5
p(uplimit)
p(downlimit)

상한 하한값을 정하는것.


그래프 만들기

seaborn을 활용한 데이터 visualization

 

# seaborn 외부라이브러리를 이용 seaborn은 matplotlib를 기반으로 하는 data visualization library

 

# 산점도 그래프 (scatter plot)

* 데이터를 X/Y 평면에 점으로 표현

* 연속된 값으로 되어 있는 두 변수관의 관계를 표현

#dayagraph_scatter.py

#산점도 그래프

import pandas as pd
mpg = pd.read_csv("../assets/mpg.csv")
print(mpg)

import seaborn as sns
import matplotlib.pyplot as plt

#그래프 설정
plt.rcParams.update({"figure.dpi": "150"}) #해상도, 기본값 72
plt.rcParams.update({"figure.figsize": [8, 6]}) #가로/세로 크기, 기본값[6, 4]
plt.rcParams.update({"font.size": "30"}) #글자크기, 기본값 10
plt.rcParams.update({"font.family": "Malgun Gothic"}) # 글자체, 기본값 sans-serif
plt.show()

#데이터 x축에 표현할 데이터, y축에 표현할 데이터
sns.scatterplot(data=mpg, x="displ", y="hwy")
plt.show()

# 축 범위 설정
sns.scatterplot(data=mpg, x='displ', y='hwy').set(xlim=[3, 6])
plt.show()

sns.scatterplot(data=mpg, x='displ', y='hwy').set(xlim=[3, 6], ylim=[10, 30])
plt.show()

#종류별 색상 변경
# hue : 범례
sns.scatterplot(data=mpg, x="displ", y='hwy', hue='drv')
plt.show()

 

 

# 막대 그래프 (bar chart)

* 집단 간의 차이를 표현

 

# bargraph_bar.py

import pandas as pd
mpg = pd.read_csv('../assets/mpg.csv')
# print(mpg)

import seaborn as sns
import matplotlib.pyplot as plt

# 그래프용 데이터
# df_mpg = mpg.groupby('drv', as_index=False).agg(mean_hwy=('hwy', 'mean'))
# print(df_mpg)

# sns.barplot(data=df_mpg, x='drv', y='mean_hwy')
# plt.show()

#막대 크기 순서대로 정렬
# df_mpg = df_mpg.sort_values("mean_hwy", ascending=False)
# sns.barplot(data=df_mpg, x='drv', y='mean_hwy')1
# plt.show()

#빈도 막대그래프 1
# df_mpg = mpg.groupby('drv', as_index=False).agg(n=('drv', 'count'))
# sns.barplot(data=df_mpg, x='drv', y='n')
# plt.show()

#빈도 막대그래프2
#카운트 그래프 :  어떤 변수의 값이 몇개 있는지 그려주는 그래프
# sns.countplot(data=mpg, x='drv', order=["4", "f", "r"])
# plt.show()

#빈도수 높은 순으로 정렬
sns.barplot(data=mpg, x='drv', order=mpg['drv'].value_counts().index)
plt.show()

 

# 선 그래프 (line chart)

* 시간에 따른 데이터의 변화를 표현

* 시계열데이터(time series data) : 일정 시간 간격을 두고 나열된 데이터

(시간 단위로 나열된것) 

* 시계열그래프(time series graph) : 시계열데이터를 시각화한 그래프

* 우측 = 신뢰구간

#datagraph_line.py

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

economics = pd.read_csv('../assets/economics.csv')
# print(economics)

# sns.lineplot(data=economics, x='date', y='unemploy')
# plt.show()

#x축에 연도 표시
#date 탕비으로 변환
economics['date2'] = pd.to_datetime(economics['date'])
#연도만 추출
economics['year'] = economics['date2'].dt.year
sns.lineplot(data=economics, x='year', y='unemploy')
plt.show()

# 신뢰구간 표시 제거
sns.lineplot(data=economics, x='year', y='unemploy', ci=None)
plt.show()




 

 

# 상자 그래프 (box plot)

* 데이터의 분포 또는 퍼져 있는 형태를 직사각 상자로 표현

* 전체 데이터에서 특정데이터의 위치를 표현

 

# datagraph_box.py

import pandas as pd
mpg = pd.read_csv("../assets/mpg.csv")
print(mpg)

import seaborn as sns
import matplotlib.pyplot as plt

sns.boxplot(data=mpg, x='drv', y='hwy')
plt.show()

# 아래 순서대로 실습을 해봅시다!

dataanalysis/assets/economics_anormaly.csv 데이터 사용

1. 고용률 이상치를 np.nan으로 변경 (1개 행)

2. 총고용자수와 고용률 결측치 제거 (5개 행)

3. 실업자수 극단치 제거 (5개 행)

4. 물가지수별 고용률을 산점도그래프로 표현

5. 조사년월별 고용자수를 막대그래프로 표현

6. 조사년월별 물가지수의 변동을 라인그래프로 표현

7. 조사년월별 고용률을 박스그래프로 표현

# 실습
#dataanalysis/assets/economics_anormaly.csv 데이터 사용

#필요한 라이브러리 임포트
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np

#p 함수만들기
def p(str):
    print(str, '\n')

df = pd.read_csv('../assets/economics_anormaly.csv')
p(df)


#그래프
plt.rcParams.update({"figure.dpi": "150"}) #해상도, 기본값 72
plt.rcParams.update({"figure.figsize": [8, 6]}) #가로/세로 크기, 기본값[6, 4]
plt.rcParams.update({"font.size": "30"}) #글자크기, 기본값 10
plt.rcParams.update({"font.family": "Malgun Gothic"}) # 글자체, 기본값 sans-serif


# 1. 고용률 이상치를 np.nan으로 변경 (1개 행)
df['고용률'] = np.where(df['고용률']>100, np.nan, df['고용률'])
p(df)

# 2. 총고용자수와 고용률 결측치 제거 (5개 행)
df1=df.dropna(subset=['총고용자수', '고용률'])
p(df1)

# 3. 실업자수 극단치 제거 (5개 행)
df['실업자수'] = np.where(df['실업자수'] == 394839483984394839, np.nan, df['실업자수'])
p(df)

df=df.dropna(subset=['실업자수'])
p(df)

# 4. 물가지수별 고용률을 산점도그래프로 표현
sns.scatterplot(data=df, x='물가지수', y='고용률')
plt.rcParams.update({"font.family": "Malgun Gothic"})
plt.show()

# 5. 조사년월별 고용자수를 막대그래프로 표현
sns.barplot(data=df, x='조사년월', y='고용자수')
plt.show()
# 6. 조사년월별 물가지수의 변동을 라인그래프로 표현
sns.lineplot(data=df, x='조사년월', y='물가지수')
plt.show()
# 7. 조사년월별 고용률을 박스그래프로 표현
sns.boxplot(data=df, x='조사년월', y='고용률')
plt.show()