Home 아파트 분양 가격 동향 EDA 및 시각화
Post
Cancel

아파트 분양 가격 동향 EDA 및 시각화

전국 신규 민간 아파트 분양 가격 동향

소개

2013년부터 최근까지 부동산 가격 변동 추세가 아파트 분양가에 반양이되는지 확인해본 프로젝트

데이터셋

공공데이터 포털

  • 전국 평균 분양가격 (2013년 9월 ~ 2015년 8월)
  • 주택도시보증공사 전국 평균 분양가격 (2015년 ~ 2019년 12월)

    구현

    1. 라이브러리

1
2
3
4
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def get_font_family():
    import platform
    system_name = platform.system()

    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

        import matplotlib as mpl
        mpl.font_manager._rebuild()
        findfont = mpl.font_manager.fontManager.findfont
        mpl.font_manager.findfont = findfont
        mpl.backends.backend_agg.findfont = findfont
        
        font_family = "NanumBarunGothic"
    return font_family

plt.rc("font", family=get_font_family())
plt.rc("axes", unicode_minus=False)

2. Data Load

1
2
import glob
glob.glob("data/*")
1
2
['data\\전국 평균 분양가격(2013년 9월부터 2015년 8월까지).csv',
 'data\\주택도시보증공사_전국 신규 민간아파트 분양가격 동향_20210930.csv']
1
2
3
4
df_first = pd.read_csv("data/전국 평균 분양가격(2013년 9월부터 2015년 8월까지).csv", encoding="cp949")
df_last = pd.read_csv("data/주택도시보증공사_전국 신규 민간아파트 분양가격 동향_20210930.csv", encoding="cp949")

print(f"2013~2018 데이터: {df_first.shape}\n2015~2021 데이터: {df_last.shape}")
1
2
2013~2018 데이터: (17, 22)
2015~2021 데이터: (6120, 5)
1
df_first.head()
지역2013년12월2014년1월2014년2월2014년3월2014년4월2014년5월2014년6월2014년7월2014년8월...2014년11월2014년12월2015년1월2015년2월2015년3월2015년4월2015년5월2015년6월2015년7월2015년8월
0서울181891792517925180161809819446188671874219274...20242202692067020670194151884218367183741815218443
1부산811181119078896594029501945394579411...9208920892049235927993279345951595599581
2대구808080808077810182678274836083608370...8439825383278416844184468568854285428795
3인천102041020410408104081000098441005899749973...10020100201001798769876993810551104431044310449
4광주609873267611734673467523765976127622...7752774877527756786179147877788180898231

5 rows × 22 columns

1
df_last.head()
지역명규모구분연도분양가격
0서울모든면적2015105841
1서울전용면적 60제곱미터이하2015105652
2서울전용면적 60제곱미터초과 85제곱미터이하2015105882
3서울전용면적 85제곱미터초과 102제곱미터이하2015105721
4서울전용면적 102제곱미터초과2015105879

df_firstdf_last의 데이터 형태가 다릅니다.
Tidy Data 형식으로 변경해줘야합니다.

Tidy Data

Tidy Data란, 관측치가 행이고 변수가 열인 데이터로 데이터 분석에 용이한 데이터를 의미합니다.
df_first의 경우 wide form 형태이고 df_last의 경우 long form 형태입니다.
lonog form의 경우, 관측치가 행이고 변수가 열이기 때문에, tidy data라 할 수 있으며, df_firstlong form 형태로 변경해줘야합니다.

3. 데이터 요약하기

1
df_first.info()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 17 entries, 0 to 16
Data columns (total 22 columns):
 #   Column    Non-Null Count  Dtype 
---  ------    --------------  ----- 
 0   지역        17 non-null     object
 1   2013년12월  17 non-null     int64 
 2   2014년1월   17 non-null     int64 
 3   2014년2월   17 non-null     int64 
 4   2014년3월   17 non-null     int64 
 5   2014년4월   17 non-null     int64 
 6   2014년5월   17 non-null     int64 
 7   2014년6월   17 non-null     int64 
 8   2014년7월   17 non-null     int64 
 9   2014년8월   17 non-null     int64 
 10  2014년9월   17 non-null     int64 
 11  2014년10월  17 non-null     int64 
 12  2014년11월  17 non-null     int64 
 13  2014년12월  17 non-null     int64 
 14  2015년1월   17 non-null     int64 
 15  2015년2월   17 non-null     int64 
 16  2015년3월   17 non-null     int64 
 17  2015년4월   17 non-null     int64 
 18  2015년5월   17 non-null     int64 
 19  2015년6월   17 non-null     int64 
 20  2015년7월   17 non-null     int64 
 21  2015년8월   17 non-null     int64 
dtypes: int64(21), object(1)
memory usage: 3.0+ KB
1
df_last.info()
1
2
3
4
5
6
7
8
9
10
11
12
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6120 entries, 0 to 6119
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   지역명     6120 non-null   object
 1   규모구분    6120 non-null   object
 2   연도      6120 non-null   int64 
 3   월       6120 non-null   int64 
 4   분양가격    5641 non-null   object
dtypes: int64(2), object(3)
memory usage: 239.2+ KB

4. 결측치 확인하기

1
df_first.isnull().sum()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
지역          0
2013년12월    0
2014년1월     0
2014년2월     0
2014년3월     0
2014년4월     0
2014년5월     0
2014년6월     0
2014년7월     0
2014년8월     0
2014년9월     0
2014년10월    0
2014년11월    0
2014년12월    0
2015년1월     0
2015년2월     0
2015년3월     0
2015년4월     0
2015년5월     0
2015년6월     0
2015년7월     0
2015년8월     0
dtype: int64
1
df_last.isnull().sum()
1
2
3
4
5
6
지역명       0
규모구분      0
연도        0
월         0
분양가격    479
dtype: int64
1
2
# 결측치 비율
df_last.isnull().mean()*100
1
2
3
4
5
6
지역명     0.000000
규모구분    0.000000
연도      0.000000
월       0.000000
분양가격    7.826797
dtype: float64
1
2
# 결측치를 시각화
_ = sns.heatmap(df_last.isnull())

png

5. 데이터 타입 변경

1
2
df_last["분양가격"] = pd.to_numeric(df_last["분양가격"], errors="coerce")
df_last.info()
1
2
3
4
5
6
7
8
9
10
11
12
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6120 entries, 0 to 6119
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   지역명     6120 non-null   object 
 1   규모구분    6120 non-null   object 
 2   연도      6120 non-null   int64  
 3   월       6120 non-null   int64  
 4   분양가격    5625 non-null   float64
dtypes: float64(1), int64(2), object(2)
memory usage: 239.2+ KB

pd.melt로 형태 맞추기

df_first의 경우 wide form 형태이므로 long form 형태로 변경해줍니다.

1
df_first_melt = pd.melt(df_first, id_vars=["지역"])
1
df_first.head(2)
지역2013년12월2014년1월2014년2월2014년3월2014년4월2014년5월2014년6월2014년7월2014년8월...2014년11월2014년12월2015년1월2015년2월2015년3월2015년4월2015년5월2015년6월2015년7월2015년8월
0서울181891792517925180161809819446188671874219274...20242202692067020670194151884218367183741815218443
1부산811181119078896594029501945394579411...9208920892049235927993279345951595599581

2 rows × 22 columns

1
2
df_first_melt.columns = ["지역명","기간", "평당분양가격"]
df_first_melt.head(2)
지역명기간평당분양가격
0서울2013년12월18189
1부산2013년12월8111

df_frist_meltdf_last의 컬럼을 맞춰줍니다.

연도와 월 분리
1
2
3
4
def parse_year(date):
    return int(date.split("")[0])
def parse_month(date):
    return int(date.split("")[-1].replace("", ""))
1
2
df_first_melt["연도"] = df_first_melt["기간"].apply(parse_year)
df_first_melt[""] = df_first_melt["기간"].apply(parse_month)
1
df_first_melt.sample(5)
지역명기간평당분양가격연도
172대구2014년10월8403201410
59세종2014년3월781420143
282충북2015년4월679020154
7경기2013년12월10855201312
328대전2015년7월807920157

6. 분석하기

평당 분양가격 구하기

분양가격을 평당 기준으로 보기 위해 새로운 컬럼을 만듭니다.

1
df_last["평당분양가격"] = df_last["분양가격"]*3.3
1
df_last.sample(5)
지역명규모구분연도분양가격평당분양가격
3634전북전용면적 102제곱미터초과201942634.08692.2
3214전남전용면적 102제곱미터초과2018112502.08256.6
2779충남전용면적 102제곱미터초과201862580.08514.0
5836충남전용면적 60제곱미터이하202162806.09259.8
5471대전전용면적 60제곱미터이하202123061.010101.3

분양가격 요약

1
df_last.info()
1
2
3
4
5
6
7
8
9
10
11
12
13
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6120 entries, 0 to 6119
Data columns (total 6 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   지역명     6120 non-null   object 
 1   규모구분    6120 non-null   object 
 2   연도      6120 non-null   int64  
 3   월       6120 non-null   int64  
 4   분양가격    5625 non-null   float64
 5   평당분양가격  5625 non-null   float64
dtypes: float64(2), int64(2), object(2)
memory usage: 287.0+ KB
1
df_last["분양가격"].describe()
1
2
3
4
5
6
7
8
9
count     5625.000000
mean      3459.317867
std       1411.776054
min       1868.000000
25%       2574.000000
50%       3067.000000
75%       3922.000000
max      13835.000000
Name: 분양가격, dtype: float64

컬럼 정리하기

컬럼의 내용을 좀 더 직관적이고 간결하게 변환해줍니다.

1
df_last["규모구분"].unique()
1
2
array(['모든면적', '전용면적 60제곱미터이하', '전용면적 60제곱미터초과 85제곱미터이하',
       '전용면적 85제곱미터초과 102제곱미터이하', '전용면적 102제곱미터초과'], dtype=object)
1
2
df_last["전용면적"] = df_last["규모구분"].str.replace("전용면적|제곱미터|이하| ", "", regex=True)
df_last["전용면적"] = df_last["전용면적"].str.replace("초과", "~")
1
df_last.sample(5)
지역명규모구분연도분양가격평당분양가격전용면적
3411경기전용면적 60제곱미터이하201924444.014665.260
4070경남모든면적201992995.09883.5모든면적
175인천모든면적2015123184.010507.2모든면적
959대구전용면적 102제곱미터초과201693045.010048.5102~
5487강원전용면적 60제곱미터초과 85제곱미터이하202123083.010173.960~85

필요없는 컬럼 제거하기

1
df_last = df_last.drop(["규모구분", "분양가격"], axis=1)
1
df_last.sample(5)
지역명연도평당분양가격전용면적
611부산201659824.160
1021서울20161021981.360
4561충남202037887.060
1884경기2017813322.1102~
4449광주2020214223.0102~

컬럼 맞추기

1
df_first_melt.columns.to_list()
1
['지역명', '기간', '평당분양가격', '연도', '월']
1
df_last.columns.to_list()
1
['지역명', '연도', '월', '평당분양가격', '전용면적']
1
cols = ["지역명", "연도", "", "평당분양가격"]
1
2
df_first_prepare = df_first_melt.loc[:, cols].copy()
df_last_prepare = df_last.loc[df_last["전용면적"]=="모든면적", cols].copy()

데이터 합치기

1
df = pd.concat([df_first_prepare, df_last_prepare], axis=0)
1
df
지역명연도평당분양가격
0서울20131218189.0
1부산2013128111.0
2대구2013128080.0
3인천20131210204.0
4광주2013126098.0
...............
6095전북202198715.3
6100전남2021910487.4
6105경북2021910345.5
6110경남2021910873.5
6115제주2021927574.8

1581 rows × 4 columns

7. 시각화

수치데이터 히스토그램

1
_ = df_last.hist(figsize=(10, 6), bins=100)

png

bins 옵션을 높게 설정하면, 해당 데이터의 수치형 데이터와 범주형 데이터를 찾는데 도움이 됩니다.

Pairplot

1
_ = sns.pairplot(data=df_last, hue="지역명")

png

특정 데이터만 보고 싶은 경우, isin 메서드를 사용할 수 있습니다.

1
_ = sns.pairplot(data=df_last[df_last["지역명"].isin(["서울", "경기", "인천"])], hue="지역명")

png

연도별 평당분양가격

1
2
plt.figure(figsize=(12, 4))
_ = sns.barplot(data=df, x="연도", y="평당분양가격", ci=None)

png

1
2
plt.figure(figsize=(12, 4))
_ = sns.pointplot(data=df, x="연도", y="평당분양가격", ci=None)

png

1
2
plt.figure(figsize=(12, 4))
_ = sns.boxplot(data=df, x="연도", y="평당분양가격")

png

1
2
plt.figure(figsize=(12, 4))
_ = sns.violinplot(data=df, x="연도", y="평당분양가격")

png

1
2
3
plt.figure(figsize=(12, 4))
_ = sns.swarmplot(data=df, x="연도", y="평당분양가격", size=2)

png

지역별 평당분양 가격

1
_ = sns.barplot(data=df, x="지역명", y="평당분양가격", ci=None)

png

1
_ = sns.boxplot(data=df, x="지역명", y="평당분양가격")

png

1
2
plt.figure(figsize=(12, 4))
_ = sns.violinplot(data=df, x="지역명", y="평당분양가격")

png

1
2
plt.figure(figsize=(15, 8))
_ = sns.swarmplot(data=df, x="지역명", y="평당분양가격", size=2)

png

8. 데이터 집계

지역별 분양가격 평균

1
_ = df.groupby("지역명")["평당분양가격"].mean().plot(kind="bar", rot=30)

png

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

1
_ = df.groupby(["연도", "지역명"])["평당분양가격"].mean().unstack().plot.bar(rot=30)

png

1
_ = df.groupby(["연도", "지역명"])["평당분양가격"].mean().unstack()[["서울", "경기"]].plot(kind="bar", rot=30)

png

This post is licensed under CC BY 4.0 by the author.

matplot 한글 폰트 설정

멋쟁이 사자처럼 AI Shcool 5주차

Comments powered by Disqus.