본문 바로가기
[파이썬]/데이터 분석

[데이터 분석] 데이터 시각화를 통한 데이터 분석(matplotlib, matplotlib.pyplot, seaborn)

by sung min_Kim 2023. 12. 4.

 본 글에서는 "데이터 시각화를 통한 데이터 분석"에 관한 내용을 다룰 것이다. 이전에 데이터 가공(전처리) 작업을 수행한 데이터프레임 객체를 시각화하여 데이터 분석을 진행할 것이다. 이 데이터프레임 객체는 "포항시 BIS 교통카드 사용내역 데이터"에 대한 정보를 담고 있다. 차례와 사용 툴은 아래와 같다.

 [차례]
 첫 번째, 사용할 데이터 호출 및 검증
 두 번째, 데이터 시각화 라이브러리 호출

 세 번째, 기준월 및 기준일자별 버스 이용량 시각화 분석 - 히트맵
 네 번째, 시간 및 승객구분별 버스 내 체류시간(분) 시각화 - 막대그래프, 히스토그램
 다섯 번째, 승하차정류장별 버스내체류시간(분) 상위 30건 시각화 분석 - 선그래프

 [사용 툴]
- Jupyter notebook(웹 기반 대화형 코딩 환경)
 
 [사용 라이브러리]
 - pandas
 - matplotlib, matplotlib.pyplot
 - seaborn

 


· 사용할 데이터 호출 및 검증


 우선 판다스 라이브러리와 사용할 데이터프레임을 호출하여 주도록 하자.

# 판다스 라이브러리 호출
import pandas as pd

# 사용할 파일 호출
df_bus_card_tot = pd.read_csv("./01_data/all/df_bus_card_tot.csv")
df_bus_card_tot.head(1)

 

사용할 데이터프레임 호출


 호출한 데이터프레임의 결측치, 이상치 데이터가 존재하는지 검증을 수행한다.

# 결측치 데이터 확인
df_bus_card_tot.info()

 
 전체 행의 수와 결측치가 아닌 열의 개수가 일치한 결과를 보아, 결측치가 존재하지 않는 데이터임을 확인할 수 있다.

결측치가 존재하지 않는 데이터

 

# 이상치 데이터 확인
df_bus_card_tot.describe()


 데이터가 표준편차(std) 내에 잘 분포되어 있고, 중앙값 역시 데이터의 전반적인 특성을 잘 반영하고 있다. 또한, 이 데이터의 성격에 따라 마이너스 값이 정상적으로 존재하지 않아야 하는데, 그런 값이 없으므로 이상치가 존재하지 않을 가능성이 높다고 할 수 있다. 

이상치가 존재할 확률이 적은 데이터

 


· 데이터 시각화 라이브러리 호출

 

### 시각화 라이브러리
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns

# 폰트 환경설정 라이브러리
from matplotlib import font_manager, rc
plt.rc("font", family = "Malgun Gothic")

# 그래프 내에 마이너스(-) 표시 기호 적용하기
plt.rcParams["axes.unicode_minus"] = False

 시각화의 개념과 시각화 라이브러리가 무엇을 의미하는지에 대해서는 아래의 링크에 잘 정리해 두었으니 참고하시길 바란다.
(2023.12.03 - [[파이썬]/데이터 분석] - [데이터 분석] 시각화 라이브러리 Matplotlib, Seaborn, matplotlib.pyploy (+폰트 설정, 마이너스 기호 적용))

 


· 기준월 및 기준일자별 버스 이용량 시각화 분석 - 히트맵

 

1_피벗 테이블 생성

 
 피벗 테이블은 데이터를 요약하는 통계표이다. 원본 데이터의 여러 열을 새롭게 조직화하여, 복잡한 데이터 관계를 단순한 형태로 표현한다. 피벗 테이블은 특정 열의 값을 새로운 열 또는 행의 헤더로 재구성하며, 원하는 값에 대한 요약 통계를 제공한다.


# 피벗 테이블 생성
df_pivot = df_bus_card_tot.pivot_table(index = "기준월",
                                       columns = "기준일",
                                       values = "승객구분",
                                       aggfunc = "count")
df_pivot


 판다스에서 제공하는 'pivot_table()' 함수를 사용하여, 피벗 테이블을 생성한다. 위 코드에서 사용된 구조는 다음과 같다.

 

  • index : 피벗 테이블의 행 인덱스인 y축을 정의한다. 여기서는 "기준월" 열의 값이 행 인덱스인 y축으로 설정된다.

  • columns : 피벗 테이블의 열 인덱스인 x축을 정의한다. 여기서는 "기준일" 열의 값이 열 인덱스인 x축으로 설정된다.

  • values : 피벗 테이블의 값으로 사용된 열을 정의한다. 여기서는 "승객구분" 열의 값이 사용된다.

  • aggfunc : 피벗 테이블에서 각 그룹에 대해 어떤 함수를 적용할지를 정의한다. 여기서는 'count' 함수를 사용해 각 그룹의 개수를 집계한다.

 따라서, 위 코드를 실행하면, 각 '기준월'과 '기준일'에 따른 '승객구분'의 개수를 요약한 피벗 테이블이 'df_pivot'에 저장된다.

pivot_table() => 피벗테이블 생성

 

2_히트맵(heatmap) 시각화


 히트맵(heatmap)은 데이터의 표 형태로서, 셀의 색상을 다르게 하여 데이터의 패턴, 변화, 그래디언트(변화의 정도나 방향)를 명확하게 표현하는 시각화 방법이다. 이를 통해 데이터의 분포화 패턴을 쉽게 파악할 수 있다.

# 그래프 전체 너비, 높이 설정
plt.figure(figsize=(20, 10))

# 그래프 제목 설정
plt.title("기준월 및 기준일자별 버스 이용량 분석")

# 히트맵 시각화
sns.heatmap(df_pivot, annot=True, fmt=".0f", cmap="rocket_r")

# 그래프 호출
plt.show()


 'seaborn' 라이브러리의 'heatmap()' 함수를 사용하여, 히트맵을 생성한다. 위 코드에서 사용된 구조는 다음과 같다.

 

  • plt.figure : 'matplotlib' 라이브러리의 함수이다. 이 함수는 새로운 그림(figure) 객체를 생성하며, 이 그림 위에 그래프를 그릴 수 있다. 이 함수의 주요 인자로는 'figsize'를 사용하여 그림의 너비와 높이를 설정한다. 여기서는 그래프의 너비를 20, 높이를 10으로 설정한다.

  • plt.title : 'matplotlib' 라이브러리의 함수이다. 이 함수는 그래프의 제목을 설정하는 데 사용된다. 여기서는 그래프 이름을 "기준월 및 기준일자별 버스 이용량 분석"으로 설정한다.

  • sns.heatmap : 'seaborn' 라이브러리의 함수이다. 이 함수는 히트맵을 생성하는데 사용된다.

    - df_pivot : 데이터프레임을 히트맵으로 표현한다.

    - annot=True : 각 셀의 집계값을 표시한다. 집계값을 숨기고 싶으면 'annot=False'를 입력한다.

    - fmt=".0f" : 'fmt'는 각 셀에 표시되는 값의 형식을 지정한다. ".0f"는 소수점 이하를 무시하고 정수형으로 표시하라는 의미이다.

    - cmap="roket_r" : 히트맵의 컬러 맵을 설정 한다. 컬러 맵은 데이터 값이 색상으로 표현되는 방식이다.

  • plt. show() : 'matplotlib' 라이브러리의 함수이다. 이 함수는 위의 설정에 따라 그래프를 출력한다.

 

sns,heatmap() => 히트맵(heatmap) 생성

 

3_해석 

 
 1월부터 3월까지의 버스 이용량을 분석한 결과, 1월에 가장 많은 이용량을 나타내고 있으며, 2월에서 3월로 갈수록 이용량이 점차 줄어들고 있는 것으로 확인되었다. 이는 포항시의 관광객 유입이 많은 시기에 버스 이용량도 증가하는 경향이 있기 때문으로 예상된다. 이에 따라, 포항시 관광객 유입 데이터를 수집하여 해당 년월의 버스 이용량과 비교 분석해 볼 필요성이 있다고 판단된다. 

 


· 시간 및 승객구분별 버스 내 체류시간(분) 시각화 - 막대그래프, 히스토그램

 

1_필요한 데이터 추출


'기준시간', '승객구분', '버스내체류시간(분)'에 해당하는 데이터를 'df_bus_card_tot' 데이터프레임에서 추출하여 새로운 데이터프레임 'df_temp'를 생성한다.

# 필요한 데이터 추출
df_temp = pd.DataFrame()
df_temp["기준시간"] = df_bus_card_tot["기준시간"]
df_temp["승객구분"] = df_bus_card_tot["승객구분"]
df_temp["버스내체류시간"] = df_bus_card_tot["버스체류시간(분)"]
df_temp.head()

 

필요한 데이터 추출

 

2_그룹화


 '기준시간'과 '승객구분'을 기준으로 'groupby()' 함수를 사용하여 그룹화한 후, 그룹화된 각 그룹의 '버스내체류시간(분)'의 총합을 계산하고, 이를 '버스내체류시간' 기준으로 내림차순으로 정렬한다. 이를 통해 "시간대 및 승객구분별 버스내체류시간(분)을" 확인할 수 있다.

# 그룹화 하기
df_temp2 = df_temp.groupby(["기준시간", "승객구분"], as_index=False).sum()
df_temp2 = df_temp2.sort_values(by=["버스내체류시간"], ascending=False)
df_temp2

 

  • groupby() : 이 함수는 데이터프레임을 특정 열(들)의 값에 따라 그룹화하는 역할을 한다. 여기서는 "기준시간"과, "승객구분" 열을 기준으로 그룹화를 수행하고 있다. 즉 "기준시간"과 "승객구분"열의 같은 행들끼리 그룹을 이룬다.

    - as_index : 이 옵션은 그룹화의 기준이 되는 열들을 인덱스로 사용하지 않고, 새로운 인덱스를 생성하라는 의미이다.

  • sum() : 이 함수는 그룹화된 각 그룹 내에서 모든 숫자형 열의 합계를 계산한다. 예를 들면, '기준시간'이 '5시'이고 '승객구분'이 '일반'인 그룹에는 같은 '기준시간'과 '승객구분'을 가진 여러 행들이 포함될 수 있다. 이 그룹 내에서 '버스내체류시간'의 합계를 구하면, 같은 '기준시간'과 '승객구분'을 가진 승객들의 '버스내체류시간' 총합을 알 수 있다.  

  • sort_values : 이 함수는 데이터프레임을 특정 열의 값에 따라 정렬하는 역할을 한다. 여기서는 "버스내체류시간" 열을 기준으로 정렬을 수행하고 있다.

    - by : 정렬의 기준이 될 열을 지정한다.

    -ascending=False : 이 옵션은 정렬의 방향을 지정한다. 'False'는 내림차순, 'True'는 오름차순을 의미한다.


위 코드의 실행을 통해, "시간대 및 승객구분별 버스 내 체류시간"을 확인할 수 있다.

groupby() => 그룹화


행과 열의 위치를 바꾸어 데이터의 구조를 편하게 살펴볼 수도 있다.

# 데이터의 행과 열의 위치를 교환하기
df_temp2.transpose()


 판다스 라이브러리에서 제공하는 'transpose()' 함수를 사용하면 데이터프레임의 행과 열을 서로 바꿀 수 있다. 이를 통해 데이터의 구조를 변경할 수 있어, 데이터의 분석이나 시각화를 용이하게 하기 위해 사용한다.  

transpose() => 데이터프레임의 행과 열의 위치를 교환

 

3_막대그래프 생성


 막대그래프는 데이터의 수량을 막대의 길이로 표현하는 시각화 방법이다. 특히 범주형 데이터를 비교하는데 매우 유용하며, 시간에 따른 변화나 범주간 비교, 빈도 분석 등에 자주 활용된다. 다만, 막대그래프를 사용할 때에는 'y'축의 시작점을 '0'으로 설정하여 데이터의 왜곡을 방지하는 것이 중요하다.

fig = plt.figure(figsize=(25, 10))

plt.title("시간 및 승객구분별 버스내 체류시간(분) 시각화")

# 막대그래프 생성
sns.barplot(x="기준시간", y="버스내체류시간", hue="승객구분", data=df_temp2)

plt.show()


 'matplotlib'과 'seaborn' 라이브러리를 사용하여 '기준시간'과 '승객구분'에 따른 '버스내체류시간'의 합계를 막대그래프로 시각화하는 작업을 수행한다. 

 

  • sns.barplot : 'seaborn' 라이브러리에서 제공하는 'barplot()' 함수를 사용하여 막대그래프를 생성한다. 

    - x : x축에 표시할 데이터를 열로 지정한다.

    - y : y축에 표시할 데이터를 열로 지정한다.

    - hue : 막대의 색상을 열의 값에 따라 다르게 표시하는 부분이다. 이를 통해 '승객구분' 값에 따른 '버스내체류시간'의 차이를 색상으로 표현할 수 있다.

  • data : 그래프를 그리는 데 사용할 데이터를 데이터프레임으로 지정하는 부분이다. 여기서 사용된 'df_temp2 ' 데이터프레임은 앞서 '기준시간'과 '승객구분'으로 그룹화하여 '버스내체류시간'의 합계를 계산하고 정렬한 결과이다.

 

sns.barplot() => 막대그래프 생성

 

4_히스토그램(밀도그래프) 생성


 히스토그램은 데이터의 분포를 시각적으로 표현하는 그래프로, 데이터의 중심, 분산, 기울기 등을 한눈에 파악할 수 있으며, 이상치나 특이한 패턴을 발견하는데 유용하다.

plt.figure(figsize=(12, 4))
plt.title("시간 및 승객구분별 버스내 체류시간(분단위) 분석")

# 히스토그램 생성
sns.histplot(data = df_temp2,
             x = "기준시간",
             bins = 30,
             kde = True,
             hue = "승객구분",
             multiple="stack",
             stat = "density",
             shrink=0.6)

plt.show()


'seaborn' 라이브러리의 'histplot()' 함수를 사용하여, '기준시간'과 '승객구분'에 따른 '버스내체류시간'의 분포를 히스토그램으로 시각화하며, '승객구분' 값에 따라 색상을 다르게 표현하고, 각 범주가 전체 중에서 차지하는 비율을 표시하는 작업을 수행한다. 따라서, '기준시간'에 따른 '버스내체류시간'의 분포와 '승객구분'에 따른 차이를 쉽게 파악할 수 있다.

 

  •  sns.histplot() : 이 함수는 히스토그램을 생성하는 데 사용된다.

  • data : 그래프를 그리는 데 사용할 데이터를 데이터프레임으로 지정하는 부분이다. 여기서 사용된 'df_temp2' 데이터프레임은 앞서 '기준시간'과 '승객구분'으로 그룹화하여 '버스내체류시간'의 합계를 계산하고 정렬한 결과이다.

  • x : 히스토그램의 x축에 표시할 데이터를 열로 지정하는 부분이다.

  • bins : 히스토그램의 막대의 개수를 지정하는 부분이다. 이는 얼마나 데이터를 세밀하게 나눠서 보여줄지를 결정한다.

  • hue : 막대의 색상을 지정한 열의 값에 따라 다르게 표시하는 부분이다.

  • multiple="stack" : 하나의 막대에 여러 범주를 쌓아서 표현하는 옵션이다.

  • stat="density" : y축을 비율로 표시하는 옵션이다. 이를 통해 전체 중에서 각 범주가 차지하는 비율을 볼 수 있다.

  • shringk=0.6 : 막대의 너비를 조절하는 옵션이다. 원본 사이즈의 60%로 축소한다.

  • pit.show() : 그래프를 화면에 출력하는 코드이다.

 

sns.histplot() => 히스토그램 생성

 


승하차정류장별 버스내체류시간(분) 상위 30건 시각화 분석 - 선그래프


 '승차정류장'에서 '하차정류장'까지의 '버스내체류시간'을 이용하여 체류시간이 많은 구간을 확인할 것이다.

1_필요한 데이터 추출

 

# 구간과 버스내체류시간을 갖는 새 데이터프레임 생성
df_temp3 = pd.DataFrame()

df_temp3["승하차정류장"] = df_bus_card_tot["승차정류장"] + "~" + \
                           df_bus_card_tot["하차정류장"]
df_temp3["버스내체류시간"] = df_bus_card_tot["버스내체류시간(분)"]
df_temp3


 이는 '승차정류장'과 '하차정류장'을 문자 "~"로 연결하여 새로운 '승하차정류장' 열을 생성하고 있다. 그리고 '버스체류시간(분)' 열의 값을 '버스내체류시간'이라는 새로운 열에 할당하고 있다. 이렇게 생성한 새로운 데이터 프레임 'df_temp3'는 "승하차정류장별 버스내체류시간(분)"의 상위 30건에 대해 시각화 분석을 하는 데 사용할 것이다.

파이썬에서는 괄호 없이 줄 바꿈을 하기 위해서는 \(백슬래시)를 사용하여야 한다.

필요한 데이터 추출

 

2_그룹화


 '승하차정류장' 열의 같은 행들끼리 그룹화를 시키고, 집계 함수를 사용하여 그룹화된 각 그룹의 '버스내체류시간' 열의 값들에 대한 연산을 수행하여 "승하차정류장별 버스내체류시간(분) 상위 30건" 데이터를 추출하도록 한다.

# 승하차정류장별 버스내체류시간 집계하기
df_temp_gp = df_temp3.groupby(["승하차정류장"], as_index=False).sum()
df_temp_gp = df_temp_gp.sort_values(by=["버스내체류시간"], ascending=False)

# 상위 30건
df_temp_30 = df_temp_gp.head(30)
df_temp_30

groupby => 그룹화

 

3_선그래프 생성


 선그래프는 주로 시간에 따른 데이터의 변화를 보여주는 데 사용되며, 데이터의 상승, 하락, 주기 등의 패턴을 쉽게 인식할 수 있다. 하지만, 선 그래프는 데이터의 분포나 개별 값에 대한 정보는 제공하지 않으므로, 이런 정보가 필요한 경우에는 다른 종류의 그래프를 함께 사용하는 것이 좋다.

plt.figure(figsize=(12, 4))
plt.title("승하차정류장별 버스내 체류시간 분석")

# 선그래프 생성
plt.plot(df_temp_30["승하차정류장"], df_temp_30["버스내체류시간"])
plt.xlabel("승하차정류장")
plt.ylabel("버스내체류시간(분)")
plt.xticks(rotation=90)
plt.grid(True)

plt.show()


 이 코드를 실행하면, '승하차정류장'에 따른 '버스내체류시간'의 변화를 보여주는 선 그래프가 생성된다. x축에는 '승하차정류장'이, y축에는 '버스내체류시간'이 표시되며, 각 '승하차정류장'에서의 '버스내체류시간' 값을 선으로 연결한 그래프가 나타날 것이다. 또한, x축의 레이블은 90도로 회전되어 표시되고, 격자선이 그래프 상에 표시된다. 이를 통해 각 '승하차정류장'에서 '버스내체류시간'이 어떻게 변하는지를 시각적으로 쉽게 파악할 수 있게 된다.

 

  • plt.plot() : 'matplotlib' 라이브러리에서 제공하는 함수로, 선 그래프를 생성하는 데 사용된다. 인자로는 x축과 y축에 사용될 열을 지정한다.

  • plt.xlable : x축의 레이블을 설정하는 부분이다.

  • plt.ylable : y축의 레이블을 설정하는 부분이다.

  • plt.xticks : x축의 레이블의 기울기를 설정하는 부분이다. 이를 통해 레이블이 서로 겹치지 않고 명확하게 보일 수 있다.

    - rotation=90 : 기울기가 90도임을 나타낸다.

  • plt.grid(Ture) : 격자선을 표시하는 코드이다. 격자선을 통해 그래프의 가독성이 높아진다.

 



이번 분석에서는 다양한 시각화 도구를 활용하여 데이터를 탐색하고 이해하는 과정을 진행하였다.

히트맵을 사용하여 변수 간의 상관관계를 파악하였고, 
막대그래프히스토그램을 통해 데이터의 분포와 범주별 파이를 살펴보았다.

또한, 선 그래프를 이용해 시간에 따른 변화를 시각화하여,
데이터의 중요한 패턴과 특성을 더욱 명확하게 이해할 수 있었다.

이처럼 다양한 시각화 도구의 활용은 데이터 분석의 효율성을 높이는 중요한 과정이다.