-
[PROJECT] 서울 아파트가격과 인프라개수 간의 상관관계 분석DEV/🔍 PROJECT 2021. 3. 4. 13:41
서울시 아파트 집값을 보면 미친듯이 올라가고있다. 1. 데이터 소스(Data Source)
1) 서울시 집값 데이터 - 국토교통부 실거래가 공개시스템(https://rt.molit.go.kr/)
2) 인프라 시설 수 - 서울 열린데이터 광장 (https://data.seoul.go.kr/)
2. 데이터 기준
1) 서울시 집값(아파트) 데이터 분석
(1) 수집된 데이터 기간 : 2019년 1월 ~ 2019년 12월
(2) 데이터 수 : 약 7.5만 개
(3) 필요 데이터 : 자치구, 거래금액, 단위면적, 1\mx 당 거래금액( 각 거래금액/ 단위면적)
2) 인프라 시설
(1) 수집된 데이터 기간 : 2019년도 기준
(2) 필요데이터 : 공원 수, 문화시설 수, 체육시설 수, 병원 수, 도서관 수
3) 세대수
(1) 수집된 데이터 기간 : 2019년도 기준
(2) 필요데이터 : 세대수
3. 조작적 정의 필요
(1) 생활인프라란?
공원 + 병원 + 문화시설 + 체육시설 + 도서관 시설을 포함한 생활기반시설로 정의함.
(**이번 상관관계에서는 학군 영향을 고려하지 않아 교육시설을 제외함. )
(2) 세대당 인프라 수
인프라 수를 1세대로 나눈 계수로 1세대당 이용할 수 있는 인프라수
4. 데이터 수집과 전처리
1) 실거래가
(1) 전용면적, 거래금액, 시군구 데이터만 추출
(2) 시군구 데이터중 '구'데이터만 추출
(3) 단위면적당거래액(만원/㎡) = 거래금액 / 전용면적
import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt from matplotlib import font_manager, rc # 1. 실거래가 엑셀데이터 불러오기 df_apartcontract = pd.read_excel('apartmentcontract(2019).xlsx', encoding='utf-8') # (1) column 값을 '전용면적' 하고 ' 거래금액' '시군구'만 남기로 다 버리기 df_apartcontract=df_apartcontract[['전용면적(㎡)' , '거래금액(만원)' , '시군구']] 전용면적(㎡) 거래금액(만원) 시군구 0 77.75 134,500 서울특별시 강남구 개포동 1 77.75 160,000 서울특별시 강남구 개포동 2 67.28 124,000 서울특별시 강남구 개포동 # 원본데이터에 숫자가 문자형으로 되어있어서 오류가 생김. 숫자로 변경. df_apartcontract['price'] = df_apartcontract['price'].str.replace(',', '') df_apartcontract['price'] = df_apartcontract['price'].astype('float') # 변경된 정보 확인. df_apartcontract.info() <class 'pandas.core.frame.DataFrame'> RangeIndex: 74962 entries, 0 to 74961 Data columns (total 3 columns): area 74962 non-null float64 price 74960 non-null float64 location 74960 non-null object dtypes: float64(2), object(1) memory usage: 1.7+ MB # (2) '구' 로만 이루어진 열 생성 df_apartcontract['gu_list'] = df_apartcontract.location.str.split(' ').str[1] #순서 2번째에 있는 str 가져옴 area price location gu_list 0 77.75 134500.0 서울특별시 강남구 개포동 강남구 1 77.75 160000.0 서울특별시 강남구 개포동 강남구 2 67.28 124000.0 서울특별시 강남구 개포동 강남구 3 79.97 141000.0 서울특별시 강남구 개포동 강남구 4 79.97 155000.0 서울특별시 강남구 개포동 강남구 #(3) 단위면적당가격(만원) = 거래금액 / 전용면적 df_apartcontract['price_per_unit'] = df_apartcontract['price'] / df_apartcontract['area']
여기서 끝내면 안된다.
피벗테이블을 이용해서 gu_list를 인덱스열로 맞춰 정렬하자
df_apartcontract = pd.pivot_table(df_apartcontract, index='gu_list', aggfunc=np.mean) df_apartcontract.head() area price price_per_unit gu_list 강남구 92.015143 180117.408530 2054.677253 강동구 74.969871 73773.287281 1007.978136 강북구 73.627570 46805.089734 665.266528 강서구 72.590566 60390.313736 852.656551 관악구 73.113978 53568.518293 758.240790 # 이름 편하게 변경 df_apartcontract.columns = ['전용면적(㎡)', '거래금액(만원)', '단위면적당거래액(만원/㎡)']
2) 인프라 시설
(1) 공원, 문화시설, 체육시설, 병원, 도서관에 대한 전반적인 엑셀파일을 저장 후
(2) 필요한 정보인 각 시설의 개수만 추출함. 이후, str → astype → float
#인프라 시설에 관련된 파일을 읽어올때, 아예 index_col = '자치구'로 가져오자 df_infra = pd.read_excel('infra.xlsx', encoding='utf-8', index_col = '자치구') df_people = pd.read_excel('people.xlsx', encoding='utf-8', index_col = '자치구') #join함수로 인프라시설과 세대수 데이터프레임을 합치자. df_semitotal= df_apartcontract.join(df_infra) df_total= df_semitotal.join(df_people) #'인프라 개수'를 '세대'로 나눈 '세대별 인프라수'열 추가 df_total['세대별 인프라수'] = df_total['인프라 개수'] / df_total['세대']
5. 데이터 전치리 완료 확인
1제곱미터당 가격을 살펴보면, 강남구가 2천만원대에 거래되고있음을 확인.
인프라개수를 살펴보면, 강남구가 2천개 정도로 파악됨
6. 단위면적당 거래액(집값)과 인프라간의 상관관계분석
# 피어슨 상관계수:
-1에 가까울수록 음의 상관관계, 1에 가까울수록 양의 상관관계, 0에 가까울수록 상관관계가 적음
1) 단순히 이번에는 상관관계 여부만 판단해보자.
df_corr = df_total[['단위면적당거래액(만원/㎡)', '공원 수', '문화시설 수', '체육시설 수', '병원 수', '도서관 수', '인프라 개수', '세대별 인프라수']] df_corr.corr()
2) 그래프를 통해 직관적으로 상관관계를 파악해보자.
sns.set(style="ticks", color_codes=True) sns.pairplot(df_corr, kind="reg") # reg : 선으로 plot 표현
공원수 : 0.397959
문화시설수 : 0.272730
체육시설 수: 0.643007
병원수 : 0.720516
도서관수 : 0.204496
전체인프라개수 : 0.712631
세대별 인프라수 : 0.600707
모두 양의 상관관계를 가지고 있다고 나옴.
그러나!
과연 정말 상관관계를 가지는 지를 확인하려면
유의값 (p값) 을 봐야한다.
from scipy import stats # 각 문화시설과 가격의 관계 비교 (1) 공원 수 result = stats.pearsonr(df_corr['단위면적당거래액(만원/㎡)'],df_corr['공원 수']) print("피어슨 상관계수 :", result[0]) print('p-value:', result[1]) 피어슨 상관계수 : 0.39795918289003596 p-value: 0.048818980386512084 (2) 체육시설 수 result = stats.pearsonr(df_corr['단위면적당거래액(만원/㎡)'],df_corr['체육시설 수']) print("피어슨 상관계수 :", result[0]) print('p-value:', result[1]) 피어슨 상관계수 : 0.6430072084770091 p-value: 0.0005266733251440204 (3) 병원 수 result = stats.pearsonr(df_corr['단위면적당거래액(만원/㎡)'],df_corr['병원 수']) print("피어슨 상관계수 :", result[0]) print('p-value:', result[1]) 피어슨 상관계수 : 0.7205161149673736 p-value: 4.863894760099187e-05 #--> 0.0000486 (4) 도서관 수 result = stats.pearsonr(df_corr['단위면적당거래액(만원/㎡)'],df_corr['도서관 수']) print("피어슨 상관계수 :", result[0]) print('p-value:', result[1]) 피어슨 상관계수 : 0.2044964002696702 p-value: 0.32681529739329407 (5) 전체 인프라 개수 result = stats.pearsonr(df_corr['단위면적당거래액(만원/㎡)'],df_corr['인프라 개수']) print("피어슨 상관계수 :", result[0]) print('p-value:', result[1]) 피어슨 상관계수 : 0.7126307980058937 p-value: 6.414171375002959e-05 (6) 세대별 인프라 개수 result = stats.pearsonr(df_corr['단위면적당거래액(만원/㎡)'],df_corr['세대별 인프라수']) print("피어슨 상관계수 :", result[0]) print('p-value:', result[1]) 피어슨 상관계수 : 0.6007065024684994 p-value: 0.001497162529584169
7. 상관관계분석 결과해석
p값이 0.05 이하인 요인 :
도서관을 제외한 모든 변수_ 유의수준내에서 상관관계
전체 인프라 개수와 집값간의 상관관계는 0.712로 매우 높음.
p값 - 0.00006
자치구별 세대수를 나눈 세대별 인프라 개수 또한 짒간간의 상관관계가 0.600으로 매우 높음.
p값 - 0. 0014
8. 시각화1) 단위면적당 거래금액으로 시각화표현import json geo_path = 'skorea_municipalities_geo_simple.json' geo_str = json.load( open(geo_path, encoding='utf-8') ) # <-> .dump #지도 가져오기 import folium 8. 9 # tiles : 지도 타입 (default type or "Stamen Terrain" or "Stamen Toner") # location : 초기 지도 center 위치 map = folium.Map(location=[37.5502, 126.982], zoom_start=11, tiles='Stamen Toner') # , tiles='Stamen Toner' map
map = folium.Map(location=[37.5502, 126.982], zoom_start=11, tiles='Stamen Toner') map.choropleth(geo_data = geo_str, data = df_corr['단위면적당거래액(만원/㎡)'], #시각화의 대상이 될 데이터 columns = [ df_corr.index, df_corr['단위면적당거래액(만원/㎡)'] ], #df의 index 칼럼을 가져와 인식하고 fill_color = 'PuRd', key_on = 'feature.id') map
역시나..강남구, 송파구, 강동구, 용산구가 비싸다
2) 인프라시설 수 시각화표현
- 인프라시설을 모두 찍었으면 좋겠지만, 우선 간단한 시각화를 하기때문에 이번 파트에서는 구별 중심좌표를 사용해서 표시하도록 한다.
1-1) 각 좌표가져오기(구글맵)
import googlemaps # googlemaps에서 위치data가져오기 import googlemaps gmaps = googlemaps.Client(key="AIzaSyDyBsZst8hPPDepUFjIpxdiyqfBAVqlsoY") # -- input your key -- tmpMap = gmaps.geocode('강남구', language="ko") tmpMap
[{'address_components': [{'long_name': '강남구', 'short_name': '강남구', 'types': ['political', 'sublocality', 'sublocality_level_1']}, {'long_name': '서울특별시', 'short_name': '서울특별시', 'types': ['administrative_area_level_1', 'political']}, {'long_name': '대한민국', 'short_name': 'KR', 'types': ['country', 'political']}], 'formatted_address': '대한민국 서울특별시 강남구', 'geometry': {'bounds': {'northeast': {'lat': 37.5373614, 'lng': 127.1244733}, 'southwest': {'lat': 37.4563361, 'lng': 127.0114055}}, 'location': {'lat': 37.5172363, 'lng': 127.0473248}, 'location_type': 'APPROXIMATE', 'viewport': {'northeast': {'lat': 37.5373614, 'lng': 127.1244733}, 'southwest': {'lat': 37.4563361, 'lng': 127.0114055}}}, 'place_id': 'ChIJ-4m1XyOkfDURartwxRuXMbM', 'types': ['political', 'sublocality', 'sublocality_level_1']}]
tmpMap[0].get('geometry') #우리는 location 의 lat & lng 를 사용
{'bounds': {'northeast': {'lat': 37.5373614, 'lng': 127.1244733}, 'southwest': {'lat': 37.4563361, 'lng': 127.0114055}}, 'location': {'lat': 37.5172363, 'lng': 127.0473248}, 'location_type': 'APPROXIMATE', 'viewport': {'northeast': {'lat': 37.5373614, 'lng': 127.1244733}, 'southwest': {'lat': 37.4563361, 'lng': 127.0114055}}}
#index 를 column으로 생성 df_total['자치구'] = df_total.index df_total.head()
# 자치구 주소 list로 정리 lat = [] lng = [] for name in df_total['자치구']: # gmaps.reverse_geocode((longitude 값, latitude 값), language="ko") == 경도 & 위도 값으로 주소값 가져오기 # gmaps.geocode('한글 주소', language="ko") 로 위도/경도, 우편번호까지 알 수 있음 tmpMap = gmaps.geocode(name) # ex) 서울강남경찰서 tmpLoc = tmpMap[0].get('geometry') # 배열 형태( [~] )로 들어오기 때문에 [0]으로 호출 lat.append(tmpLoc['location']['lat']) # dict(tmpLoc)의 데이터는 dict['key값'] 로 value 호출 lng.append(tmpLoc['location']['lng']) df_total['lat'] = lat df_total['lng'] = lng df_total.head()
map = folium.Map(location=[37.5502, 126.982], zoom_start=11) for n in df_total.index: folium.CircleMarker ([df_total['lat'][n], df_total['lng'][n]], radius=df_total['세대별 인프라수'][n]*2000, # circle 의 크기를 결정 color='#3186cc', fill=True, fill_color='#3186cc').add_to(map) map
3) 두 지도 합치기 ( 집값과 인프라개수)
# 두 지도 합치기 map = folium.Map(location=[37.5502, 126.982], zoom_start=11) map.choropleth(geo_data = geo_str, data = df_corr['단위면적당거래액(만원/㎡)'], columns = [df_corr.index, df_corr['단위면적당거래액(만원/㎡)']], fill_color = 'PuRd', #PuRd, YlGnBu <- color brewer (http://colorbrewer2.org/) : ‘BuGn’, ‘BuPu’, ‘GnBu’, ‘OrRd’, ‘PuBu’, ‘PuBuGn’, ‘PuRd’, ‘RdPu’, ‘YlGn’, ‘YlGnBu’, ‘YlOrBr’, and ‘YlOrRd’ key_on = 'feature.id') # GeoJSON 규약을 따름, json 파일(지도 데이터)의 "feature" type의 "id" 에 매칭된다 for n in df_total.index: folium.CircleMarker ([df_total['lat'][n], df_total['lng'][n]], radius=df_total['세대별 인프라수'][n]*2000, color='#3186cc', fill=True, fill_color='#3186cc').add_child(folium.Popup(df_total['자치구'][n])).add_to(map) # .add_child(folium.Popup(df_total['자치구'][n])) 는 원에 마우스 가져가면 자치구명을 띄워주는 코드 map.save('index.html') # 현재 폴더에 지도가 html 형식으로 자동저장되며 html페이지에서는 한글이 꺠지지 않고 잘 나옴. map
역시나 구를 기반으로 인프라수를 측정하다보니 예상대로 직관적이지 않은 시각화가 되었다.
위 그래프로는 명확하게 나오지 않아 다른 시각화그래프를 만들어보자
4) 단위면적당 가격과 인프라 시설 수의 막대그래프 시각화
%matplotlib inline # matplotlib의 한글문제를 해결 font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name() # font_name rc('font', family=font_name) #그래프 df = pd.read_excel('dataset.xlsx', encoding = 'utf-8') import pandas as pd import matplotlib.pyplot as plt ax=df.plot(kind='bar', x='자치구', y='단위면적당거래액(만원/㎡)', color='orange', figsize=(15,7)) ax2=df.plot(kind='line', x='자치구', y='인프라 개수', secondary_y=True,color='DarkBlue', ax=ax) ax.set_ylabel('단위면적당가격') ax2.set_ylabel('인프라 개수') plt.tight_layout() plt.show()
- 강남구에서 인프라개수, 집값 모두 높았은 것으로 확인.
- 강남 3구라고 칭해지는 서초구, 송파구에서 집값이 높지만, 인프라개수는 강남에 비해 떨어지는 것을 확인. 하지만 다른 지역구보단 높은 인프라개수를 가지고 있음을 확인.
- 용산구 또한 강남3구와 비교해 집값이 높은 지역, 하지만 최근 재개발로 인프라개수는 다른 지역구에 비해 현저히 적은 편에 속함.
5) 지역별 인프라시설별 개수 그래프화
plt.rcParams["figure.figsize"] = (17,7) df_total.iloc[:,3:-6].plot.bar(stacked=True, rot=0) plt.show()
- 전체적으로 병원수가 많고 체육시설 또한 확보가 된 상태이지만, 도서관, 문화시설 수와 공원수가 적은 상태.
- 이는 서울시 도시정책에 있어 도서관,문화시설과 공원수를 늘려야함을 시사함.
- 그렇다면, 집값이 싸고 평균보다 높은 지역은 어디일까?
6) 결과분석 : 내 집 찾기
- 강동구, 강서구, 노원구가 조건에 맞는 지역에 나타났다.
- 용산구는 추후 인프라시설이 더욱 많아질 것으로 예상되는 지역으로 나타났다.
'코딩 > 🔍 PROJECT' 카테고리의 다른 글
[PROJECT] METABOX (0) 2021.10.04 [PROJECT] LAFESTA COMMERCE SITE (0) 2021.09.19