본문 바로가기
Python

전국 신규 아파트 분양가격 동향 분석, seaborn을 이용한 시각화

2023. 2. 6.

전혀 다른 형태의 두 데이터를 전처리하고 하나의 데이터프레임으로 병합한다.

병합된 데이터프레임을 다루어 데이터를 요약, 분석하고 다양한 방법으로 시각화한다.

라이브러리 임포트

데이터분석과 시각화에 사용될 라이브러리를 임포트한다.
그래프에서 정상적인 한글 표현을 위해 koreanize-matplotlib을 사용한다.

import koreanize_matplotlib
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

 

데이터 로드

2013~2015 전국 지역별 평균 분양가격 데이터를 df_first에, 2015~2021 전국 지역별 평균 분양가격 데이터를 df_last 변수에 로드한다. 데이터는 공공데이터포털에 원본이 있다.

df_first

dffist

보기엔 편할 수 있어도 분석하기에는 까다로운 형태이며,

df_last

dflast

df_first와는 완전 다른 형태인 것을 확인하였다.

df_last 데이터 전처리

df_last.info()

info()를 통해 먼저 데이터 요약을 확인한다.

lastinfo

데이터형태와 결측치를 주의깊게 보면, 분양 가격이 numeric 데이터가 아닌 object형이며 결측치가 479개 존재하는 것이 보인다.

데이터 타입 변경

# astype에서 에러가 발생
# to_numeric을 사용하고 errors='coerce' 사용해서 강제 변환
df_last['분양가격'] = pd.to_numeric(df_last['분양가격'], errors='coerce')
df_last['분양가격']

결측치의 존재로 astype 사용시 에러가 발생하기 때문에, to_numeric에 erros='coerce'를 사용하여 결측치를 강제 변환하였다.

lasttype


컬럼 추가, 제거

2013~2015년 데이터인 df_first는 분양가격이 평 기준인  반면 df_last는 제곱미터 기준 분양가격이므로 이를 똑같이 평 단위 기준으로 맞추기 위해 3.3을 곱하여 "평당분양가격" 컬럼을 추가해준다.

df_last['평당분양가격'] = df_last['분양가격'] * 3.3


df_last의 "규모구분" 컬럼의 unique 값을 보자.

df_last['규모구분'].unique()

아래와 같이 긴 텍스트 형태로 되어있는 것을 확인할 수 있다.

scale


하지만 직관적이지도 않고 메모리 측면에서도 좋지 않기 때문에 replace를 통해 개선한다.

df_last['전용면적'] = df_last['규모구분'].str.replace(' |전용면적|제곱미터|이하', "", regex=True)
df_last['전용면적'] = df_last['전용면적'].str.replace('초과', "~", regex=True)
df_last

 

"규모구분" 컬럼의 데이터 값 중 공백, 전용면적, 제곱미터, 이하를 삭제해주고 초과를 물결로 바꾼 "전용면적" 컬럼을 추가하였다.

replace

"규모구분"에 비해 "전용면적"이 직관적이고 메모리 사용량도 적다.

이제 "규모구분"과 "분양가격"은 필요없는 컬럼이 되었다.

df_last = df_last.drop(['규모구분', '분양가격'], axis=1)
df_last

drop()을 통해 제거해준다.

dropped

df_last에는 필요한 컬럼만 남게 되었다.

df_last pairplot 확인

sns.pairplot(df_last, hue='지역명', corner=True)

corner=True 사용함으로써 중복한 그래프는 표시되지 않는다.

pairplot

수도권과 지방의 분양가 차이를 대략적으로 확인 가능하다.

df_first 데이터 전처리

df_first.info()

우선 데이터프레임의 정보를 확인한다.

결측치가 없는 것을 확인할 수 있다.

melt로 Tidy Data (깔끔한 데이터) 만들기
df_first의 데이터는 df_last와 상당히 다른 모습을 가지고 있다.
두 데이터프레임을 병합하기 전에 같은 형태로 만들어 주어야 한다.
melt를 통해 열에 있는 데이터를 행으로 녹인다.

df_first_melt = pd.melt(df_first, id_vars='지역')
df_first_melt.columns = ["지역명", "기간", "평당분양가격"]
df_first_melt.head(2)

옆으로 쭉 퍼져 있던 시간 정보가 아래와 같이 변경되었다.

melted

"기간"을 이용해 연도와 월 분리

# 연도만 반환
def parse_year(date):
    return int(date.split('년')[0])

 

# 월만 반환
def parse_month(date):
    return int(date.split('년')[1].replace('월', ''))

YYYY년MM월 형태의 데이터에서 각각 YYYY, MM만 추출하는 위의 두 함수를 "기간"에 적용하여 파생변수를 만든다.

df_first_melt['연도'] = df_first_melt['기간'].apply(parse_year)
df_first_melt['월'] = df_first_melt['기간'].apply(parse_month)
df_first_melt.sample(2)

sample을 확인해보면

meltsample

연도와 월이 잘 생성되었다. 최초 기간이 쭉 늘어져 있던 것과 달리 깔끔한 데이터가 되었다.

데이터프레임 합치기

두 데이터프레임을 병합하기 위해 동일한 컬럼 이름을 가져야한다.
따라서 '지역명', '연도', '월', '평당분양가격' 컬럼을 사용하도록 한다.
먼저 df_first에서 원하는 데이터만 가져온다.

cols = ['지역명', '연도', '월', '평당분양가격']
df_first_prepare = df_first_melt.loc[:, cols].copy()
df_first_prepare

df_first_prepare 변수에 담을 때 copy()를 사용하여 예기치 못한 오류를 방지하자.

firstprepare



또한 df_first 데이터에는 "전용면적" 정보가 없기 때문에 df_last에서 모든면적 정보만 사용한다.

df_last_prepare = df_last.loc[df_last['전용면적'] == '모든면적', cols].copy()
df_last_prepare.head()

모든면적에 해당하는 데이터만 copy로 복사하여 df_last_prepare 변수에 담는다.

lastprepare


두 데이터프레임을 concat을 이용해 합친다.

df = pd.concat([df_first_prepare, df_last_prepare], ignore_index=True)
df

그 합쳐진 결과 데이터가 최종적으로 데이터분석, 시각화를 할 데이터가 된다.

df

 

데이터 시각화

groupby를 통해 지역별 평균 평당분양가격을 계산하고 시각화한다.

df.groupby('지역명')['평당분양가격'].mean().plot(kind='barh')

kind='barh'로 수평 막대그래프를 사용하였다.

barh

서울이 압도적인 것을 확인할 수 있다.

연도, 지역별 평균 평당분양가격

yprice = df.groupby(['연도','지역명'])['평당분양가격'].mean().unstack()
yprice

unstack()을 활용하여 지역명이 컬럼으로 지정되었다.

unstack


위 데이터를 이용하여 plot을 그려보면

yprice.plot()

직관적이지 않은 그래프가 나온다.

plot

독보적인 서울을 제외하고 추세를 확인하기 어렵다.

이런 경우 몇 개의 지역만 선정하여 시각화한다.

yprice.loc[:, ['서울', '경기', '제주']].plot(figsize=(6, 4));

서울, 경기, 제주만 확인해보자.

region3


각각의 추세를 명확히 확인할 수 있다.

이번엔 heatmap을 그려보자.

plt.figure(figsize=(12, 6))
sns.heatmap(yprice.T, cmap='BuGn', annot=True, fmt=',.0f')

전치행렬을 사용했고 수치 표현, 색상 지정, 포맷 지정을 하였다.

heatmap

히트맵을 직관적으로 잘 그렸다.
print(plt.colormaps())을 통해 히트맵에 사용할 수 있는 색상 목록을 볼 수 있다.


2013년부터 최근 데이터까지 시각화
지역별 평당 분양가격을 다양한 그래프로 시각화해본다.

1. bar plot

plt.figure(figsize=(15, 5))
sns.barplot(data=df, x='지역명', y='평당분양가격').set_title('지역별 2013~2021 평균 평당 분양가격')

seaborn의 barplot과 pointplot에서 errorbar는 기본적으로 신뢰구간을 표시하는데, 계산에 시간이 오래 걸리므로 errorbar=None을 인자로 사용하면 제거할 수 있다.

barplot2


2. box plot

plt.figure(figsize=(15, 5))
sns.boxplot(data=df, x='지역명', y='평당분양가격').set_title('지역별 2013~2021 평당 분양가격')

box plot은 데이터의 편차를 확인할 수 있는 장점이 있다.

box plot


3. violin plot 

plt.figure(figsize=(15, 5))
sns.violinplot(data=df, x='지역명', y='평당분양가격').set_title('지역별 2013~2021 평당 분양가격')

violin plot은 box plot의 분포를 확인할 수 없다는 단점을 개선하였다.

viloin


4. swarm plot

# swarmplot 으로 지역별 평당분양가격을 그려봅니다.
plt.figure(figsize=(17, 6))
sns.swarmplot(data=df, x='지역명', y='평당분양가격', size=2).set_title('지역별 2013~2021 평당 분양가격')

swarm plot은 strip plot과 violin plot의 조합적 특징으로, 데이터 점의 수와 분포를 시각화한다.

swarm

swarm plot을 그릴 때는 점이 너무 겹치지 않도록 figsize와 점의 size를 조절할 필요가 있다. 


전국 평균 평당 분양가격 2013~2021 추이

plt.figure(figsize=(10, 4))
sns.pointplot(data=df, x='연도', y='평당분양가격', errorbar=None).set_title('전국 평균 평당 분양가격')

pointplot활용, errorbar 제거

point

2013년부터 2021년까지 전국 평균 신규 아파트 평당 분양가격이 매우 많이 상승한 것을 확인할 수 있다.


이렇게 전국 신규 아파트 분양가격 2013~2015년 데이터와 2015~2021년 데이터를 각각 전처리하고 하나의 데이터프레임으로 합쳐 분석하고 시각화해보았다.

반응형

댓글