홍동이의 성장일기
[👩💻TIL 7일차 ] 유데미 스타터스 취업 부트캠프 4기 본문
목차
[96차시]지점별 기온분포 시각화-박스플롯,바이올린플롯
[서울시 폭염, 열대야 현황]
[지역별 인구구조 시각화]
[연령별 인구구조 시각화]
[아파트 실거래가 분석, 시각화]
[96차시]지점별 기온분포 시각화-박스플롯,바이올린플롯
1
- 서귀포, 서울, 대관령 지점 2020년 평균기온 서브셋
# 서브플롯 그리기
fig = plt.figure(figsize=(15,5))
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)
# 박스플롯
plt.rcParams['boxpl5ot.boxprops.color']='b'
plt.rcParams['boxplot.boxprops.linewidth']=2
plt.rcParams['boxplot.capprops.color']='r'
plt.rcParams['boxplot.capprops.linewidth']=2
plt.rcParams['boxplot.meanline']=True
ax1.boxplot([df_2020_sgp['평균기온(°C)'],df_2020_seoul['평균기온(°C)'],df_2020_dgr['평균기온(°C)']],
labels=['서귀포', '서울', '대관령'], showmeans=True)
# 바이올린플롯
v = ax2.violinplot([df_2020_sgp['평균기온(°C)'],df_2020_seoul['평균기온(°C)'],df_2020_dgr['평균기온(°C)']],
showmeans=True, showmedians=True, quantiles=[[0.25,0.75],[0.25,0.75],[0.25,0.75]])
v['bodies'][0].set_color('r')
v['bodies'][1].set_color('g')
v['bodies'][2].set_color('b')
v['cmins'].set_edgecolor('r')
v['cmaxes'].set_edgecolor('r')
v['cmeans'].set_edgecolor('r')
v['cmedians'].set_edgecolor('w')
v['cquantiles'].set_edgecolor('w')
ax2.set_xticks(range(1,4,1))
ax2.set_xticklabels(['서귀포', '서울', '대관령'])
fig.suptitle('서귀포, 서울, 대관령 평균기온 분포', size=15)
fig.tight_layout()
plt.show()
[97차시]서울시 폭염, 열대야 현황 시각화
[98차시]최고 폭염, 최고 열대야 강조하기
[99차시]연도별 폭염, 열대야 일수 추출
[100차시]연도별 폭염, 열대야 일수 시각화
import matplotlib.pyplot as plt
import pandas as pd
plt.rcParams['font.family']='Malgun Gothic'
plt.rcParams['axes.unicode_minus']=False
데이터 준비 및 확인¶
- 기상자료개방포털 > 데이터 > 기상관측 > 지상 > 종관기상관측(ASOS)
https://data.kma.go.kr/data/grnd/selectAsosRltmList.do?pgmNo=36
[ 자료형태 ] 일자료
[ 지점 ] 전체
[ 자료 ] 기온>최저,최고,평균
[ 기간 ] 1911~2020 (10년단위로 나누어 다운로드)
데이터프레임 생성¶
df_1911 = pd.read_csv('data/1911-1920 일별 기온.csv', encoding='cp949')
df_1921 = pd.read_csv('data/1921-1930 일별 기온.csv', encoding='cp949')
df_1931 = pd.read_csv('data/1931-1940 일별 기온.csv', encoding='cp949')
df_1941 = pd.read_csv('data/1941-1950 일별 기온.csv', encoding='cp949')
df_1951 = pd.read_csv('data/1951-1960 일별 기온.csv', encoding='cp949')
df_1961 = pd.read_csv('data/1961-1970 일별 기온.csv', encoding='cp949')
df_1971 = pd.read_csv('data/1971-1980 일별 기온.csv', encoding='cp949')
df_1981 = pd.read_csv('data/1981-1990 일별 기온.csv', encoding='cp949')
df_1991 = pd.read_csv('data/1991-2000 일별 기온.csv', encoding='cp949')
df_2001 = pd.read_csv('data/2001-2010 일별 기온.csv', encoding='cp949')
df_2011 = pd.read_csv('data/2011-2020 일별 기온.csv', encoding='cp949')
# 데이터프레임 연결하기
df = pd.concat([df_1911,df_1921,df_1931,df_1941,df_1951,df_1961,df_1971,df_1981,df_1991,df_2001,df_2011]
,ignore_index=True)
df.head()
지점 | 지점명 | 일시 | 평균기온(°C) | 최저기온(°C) | 최고기온(°C) | |
---|---|---|---|---|---|---|
0 | 105 | 강릉 | 1911-10-04 | NaN | 12.2 | 26.2 |
1 | 105 | 강릉 | 1911-10-09 | NaN | 6.0 | 16.6 |
2 | 105 | 강릉 | 1911-10-16 | NaN | 9.2 | 15.5 |
3 | 105 | 강릉 | 1911-11-01 | NaN | 6.0 | 14.8 |
4 | 105 | 강릉 | 1911-11-04 | NaN | 10.2 | 19.5 |
df.tail()
지점 | 지점명 | 일시 | 평균기온(°C) | 최저기온(°C) | 최고기온(°C) | |
---|---|---|---|---|---|---|
1596830 | 295 | 남해 | 2020-12-27 | 4.4 | 2.5 | 6.0 |
1596831 | 295 | 남해 | 2020-12-28 | 4.7 | 1.1 | 11.5 |
1596832 | 295 | 남해 | 2020-12-29 | 5.4 | 1.0 | 11.2 |
1596833 | 295 | 남해 | 2020-12-30 | -3.0 | -5.4 | 1.6 |
1596834 | 295 | 남해 | 2020-12-31 | -1.3 | -7.4 | 2.8 |
데이터타입 확인/변경¶
df.dtypes
지점 int64
지점명 object
일시 object
평균기온(°C) float64
최저기온(°C) float64
최고기온(°C) float64
dtype: object
df['일시'] = pd.to_datetime(df['일시'])
df.dtypes
지점 int64
지점명 object
일시 datetime64[ns]
평균기온(°C) float64
최저기온(°C) float64
최고기온(°C) float64
dtype: object
데이터 확인¶
df.shape
(1596835, 6)
df['지점명'].nunique()
102
서울시 폭염/열대야 현황 시각화¶
서울시 데이터 추출하여 서브셋 생성¶
df_seoul = df[df['지점명']=='서울'].copy()
df_seoul
지점 | 지점명 | 일시 | 평균기온(°C) | 최저기온(°C) | 최고기온(°C) | |
---|---|---|---|---|---|---|
3299 | 108 | 서울 | 1911-01-01 | -10.1 | -14.2 | -6.5 |
3300 | 108 | 서울 | 1911-01-02 | -12.5 | -19.7 | -5.9 |
3301 | 108 | 서울 | 1911-01-03 | -4.3 | -10.2 | -1.4 |
3302 | 108 | 서울 | 1911-01-04 | 0.8 | -2.6 | 2.2 |
3303 | 108 | 서울 | 1911-01-05 | -3.9 | -8.7 | 1.7 |
... | ... | ... | ... | ... | ... | ... |
1295576 | 108 | 서울 | 2020-12-27 | 5.8 | 1.4 | 10.0 |
1295577 | 108 | 서울 | 2020-12-28 | 6.7 | 4.2 | 11.4 |
1295578 | 108 | 서울 | 2020-12-29 | 0.1 | -6.2 | 4.3 |
1295579 | 108 | 서울 | 2020-12-30 | -10.9 | -12.9 | -6.2 |
1295580 | 108 | 서울 | 2020-12-31 | -8.9 | -12.9 | -5.0 |
38961 rows × 6 columns
서울시 폭염 데이터 추출¶
- 폭염: 일 최고기온이 33도 이상
df_seoul_hotday = df_seoul[df_seoul['최고기온(°C)']>=33].copy()
df_seoul_hotday
지점 | 지점명 | 일시 | 평균기온(°C) | 최저기온(°C) | 최고기온(°C) | |
---|---|---|---|---|---|---|
3519 | 108 | 서울 | 1911-08-09 | 27.0 | 23.1 | 33.0 |
3520 | 108 | 서울 | 1911-08-10 | 28.2 | 24.2 | 33.8 |
3522 | 108 | 서울 | 1911-08-12 | 28.7 | 25.8 | 34.5 |
3523 | 108 | 서울 | 1911-08-13 | 27.5 | 23.0 | 33.8 |
3527 | 108 | 서울 | 1911-08-17 | 26.4 | 21.5 | 33.5 |
... | ... | ... | ... | ... | ... | ... |
1295075 | 108 | 서울 | 2019-08-14 | 30.4 | 25.9 | 35.7 |
1295379 | 108 | 서울 | 2020-06-13 | 26.9 | 20.6 | 33.5 |
1295388 | 108 | 서울 | 2020-06-22 | 28.6 | 21.7 | 35.4 |
1295452 | 108 | 서울 | 2020-08-25 | 29.9 | 26.0 | 34.5 |
1295453 | 108 | 서울 | 2020-08-26 | 30.2 | 27.0 | 34.5 |
1028 rows × 6 columns
서울시 폭염 데이터 시각화¶
plt.rcParams['figure.figsize']=(15,5)
plt.plot(df_seoul_hotday['일시'],df_seoul_hotday['최고기온(°C)'], 'r.')
plt.xlabel('일시')
plt.ylabel('최고기온')
plt.title('서울시 폭염일 현황(1911~2020)', size=20)
plt.show()
서울시 열대야 데이터 추출¶
- 일 최저기온 25도 이상
df_seoul_hotnight = df_seoul[df_seoul['최저기온(°C)']>=25]
df_seoul_hotnight
지점 | 지점명 | 일시 | 평균기온(°C) | 최저기온(°C) | 최고기온(°C) | |
---|---|---|---|---|---|---|
3522 | 108 | 서울 | 1911-08-12 | 28.7 | 25.8 | 34.5 |
4601 | 108 | 서울 | 1914-07-26 | 29.7 | 25.8 | 35.6 |
4602 | 108 | 서울 | 1914-07-27 | 30.2 | 25.6 | 35.5 |
4605 | 108 | 서울 | 1914-07-30 | 25.7 | 25.1 | 27.4 |
4621 | 108 | 서울 | 1914-08-15 | 27.2 | 25.2 | 31.5 |
... | ... | ... | ... | ... | ... | ... |
1295452 | 108 | 서울 | 2020-08-25 | 29.9 | 26.0 | 34.5 |
1295453 | 108 | 서울 | 2020-08-26 | 30.2 | 27.0 | 34.5 |
1295454 | 108 | 서울 | 2020-08-27 | 27.1 | 25.6 | 28.6 |
1295455 | 108 | 서울 | 2020-08-28 | 27.3 | 26.0 | 29.7 |
1295456 | 108 | 서울 | 2020-08-29 | 26.8 | 25.5 | 29.0 |
549 rows × 6 columns
서울시 열대야 데이터 시각화¶
plt.plot(df_seoul_hotnight['일시'],df_seoul_hotnight['최저기온(°C)'], 'k.')
plt.xlabel('일시')
plt.ylabel('일 최저기온(°C)')
plt.title('서울시 열대야 현황(1911~2020)', size=20)
plt.show()
💡최근들어 열대야가 많아지고 있다. 일 최저기온 또한 높아지고 있다.
최고 폭염일, 최고 열대야 강조하기¶
폭염이 가장 심했던 날¶
폭염이 가장 심했던 날 best10¶
- 데이터프레임.nlargest(개수,컬럼명) : 컬럼의 값이 큰 순으로 개수만큼 출력
df_seoul_hotestday = df_seoul_hotday.nlargest(10, '최고기온(°C)')
df_seoul_hotestday
지점 | 지점명 | 일시 | 평균기온(°C) | 최저기온(°C) | 최고기온(°C) | |
---|---|---|---|---|---|---|
1294697 | 108 | 서울 | 2018-08-01 | 33.6 | 27.8 | 39.6 |
719667 | 108 | 서울 | 1994-07-24 | 33.1 | 28.1 | 38.4 |
1294696 | 108 | 서울 | 2018-07-31 | 32.6 | 27.8 | 38.3 |
57401 | 108 | 서울 | 1939-08-10 | 30.1 | 24.5 | 38.2 |
85687 | 108 | 서울 | 1943-08-24 | 29.0 | 23.2 | 38.2 |
719666 | 108 | 서울 | 1994-07-23 | 32.6 | 28.0 | 38.2 |
1294687 | 108 | 서울 | 2018-07-22 | 31.8 | 25.3 | 38.0 |
1294711 | 108 | 서울 | 2018-08-15 | 31.7 | 28.3 | 38.0 |
85691 | 108 | 서울 | 1943-08-28 | 29.2 | 24.5 | 37.9 |
1294698 | 108 | 서울 | 2018-08-02 | 33.7 | 30.3 | 37.9 |
💡2018년도가 5개 들어있음
폭염이 가장 심했던 날짜, 최고기온¶
df_seoul_hotestday = df_seoul_hotestday.iloc[[0]]
print(df_seoul_hotestday.iloc[0,2].date())
print(df_seoul_hotestday.iloc[0,5])
2018-08-01
39.6
시각화¶
# plot
plt.plot(df_seoul_hotnight['일시'],df_seoul_hotnight['최고기온(°C)'], 'k.')
plt.xlabel('일시')
plt.ylabel('최고기온(°C)')
plt.title('서울시 폭염일 현황(1911~2020)', size=20)
# 가장 더웠던 날 표시
plt.plot(df_seoul_hotestday.iloc[0,2].date(), df_seoul_hotestday.iloc[0,5], 'r^')
# 가장 더웠던 날짜, 온도 표시
plt.text(df_seoul_hotestday.iloc[0,2].date(), df_seoul_hotestday.iloc[0,5]+0.5,
str(df_seoul_hotestday.iloc[0,2].date()) + '(' + str(df_seoul_hotestday.iloc[0,5]) + '°C)',
ha='center', size=12)
plt.yticks(range(33,42))
plt.show()
열대야가 가장 심했던 날¶
열대야가 가장 심했던 날 best10¶
df_seoul_hotestnight = df_seoul_hotnight.nlargest(10,'최저기온(°C)')
열대야가 가장 심했던 날짜, 최고기온¶
print(df_seoul_hotestnight.iloc[0,2].date())
print(df_seoul_hotestnight.iloc[0,4])
2018-08-02
30.3
시각화¶
# plot
plt.plot(df_seoul_hotnight['일시'],df_seoul_hotnight['최저기온(°C)'], 'k.')
plt.xlabel('일시')
plt.ylabel('일 최저기온(°C)')
plt.title('서울시 열대야 현황(1911~2020)', size=20)
# 가장 더웠던 밤 표시
plt.plot(df_seoul_hotestnight.iloc[0,2].date(), df_seoul_hotestnight.iloc[0,4], 'r^')
plt.text(df_seoul_hotestnight.iloc[0,2].date(), df_seoul_hotestnight.iloc[0,4]+0.5,
str(df_seoul_hotestnight.iloc[0,2].date())+'('+str(df_seoul_hotestnight.iloc[0,4])+')',
ha='center', size=12)
plt.yticks(range(25, 33))
# 가장 더웠던 날짜, 온도 표시
plt.show()
💡위 그래프를 통해 서울시의 열대야 일수가 늘어나고 있는 것을 확인할 수 있다.
연도별 폭염일수, 열대야일수 추출¶
연도별 폭염일수 추출¶
# 연도별 폭염일수 : 연도로 그룹핑하여 일수 카운트
df_seoul_hotday_count = df_seoul_hotday.groupby(df_seoul_hotday['일시'].dt.year)['일시'].count().to_frame()
df_seoul_hotday_count
일시 | |
---|---|
일시 | |
1911 | 5 |
1912 | 3 |
1914 | 11 |
1915 | 10 |
1916 | 2 |
... | ... |
2016 | 24 |
2017 | 13 |
2018 | 35 |
2019 | 15 |
2020 | 4 |
97 rows × 1 columns
💡폭염일이 없는 날은 누락되어있다.
# 폭염일이 없는 날을 포함시키기 위하여 1911~2020년의 연도 데이터프레임 생성
df_years=pd.DataFrame(range(1911,2021))
# 인덱스를 연도로 설정
df_years.index=df_years[0]
df_years
0 | |
---|---|
0 | |
1911 | 1911 |
1912 | 1912 |
1913 | 1913 |
1914 | 1914 |
1915 | 1915 |
... | ... |
2016 | 2016 |
2017 | 2017 |
2018 | 2018 |
2019 | 2019 |
2020 | 2020 |
110 rows × 1 columns
# 연도별 폭염일수, 연도 데이터프레임 concat
df_seoul_hotday_count = pd.concat([df_years, df_seoul_hotday_count], axis=1)
df_seoul_hotday_count
0 | 일시 | |
---|---|---|
1911 | 1911 | 5.0 |
1912 | 1912 | 3.0 |
1913 | 1913 | NaN |
1914 | 1914 | 11.0 |
1915 | 1915 | 10.0 |
... | ... | ... |
2016 | 2016 | 24.0 |
2017 | 2017 | 13.0 |
2018 | 2018 | 35.0 |
2019 | 2019 | 15.0 |
2020 | 2020 | 4.0 |
110 rows × 2 columns
# 불필요한 컬럼 삭제
df_seoul_hotday_count.drop(columns=[0], inplace=True)
df_seoul_hotday_count
일시 | |
---|---|
1911 | 5.0 |
1912 | 3.0 |
1913 | NaN |
1914 | 11.0 |
1915 | 10.0 |
... | ... |
2016 | 24.0 |
2017 | 13.0 |
2018 | 35.0 |
2019 | 15.0 |
2020 | 4.0 |
110 rows × 1 columns
# 결측치 확인
df_seoul_hotday_count.isnull().sum()
일시 13
dtype: int64
# null --> 폭염일이 없음을 뜻함 --> null을 0으로 채우기
df_seoul_hotday_count = df_seoul_hotday_count.fillna(0)
# 컬럼명을 알맞게 바꾸기
df_seoul_hotday_count.columns=['폭염일수']
# 폭염일수 데이터를 정수형으로 바꾸기
df_seoul_hotday_count = df_seoul_hotday_count.astype('int64')
# 폭염이 가장 많았던 해의 데이터 best10
df_seoul_hotday_count.nlargest(10, '폭염일수')
폭염일수 | |
---|---|
1939 | 47 |
1943 | 43 |
2018 | 35 |
1994 | 29 |
1919 | 25 |
1950 | 25 |
1930 | 24 |
2016 | 24 |
1924 | 23 |
1929 | 22 |
💡과거의 데이터들이 많이 포함되어 있는 것을 알 수 있다.
연도별 열대야일수 추출¶
# 연도별 열대야일수 : 연도로 그룹핑하여 데이터갯수 카운트
df_seoul_hotnight_count = df_seoul_hotnight.groupby(df_seoul_hotnight['일시'].dt.year)['일시'].count().to_frame()
df_seoul_hotnight_count
일시 | |
---|---|
일시 | |
1911 | 1 |
1914 | 4 |
1915 | 3 |
1919 | 1 |
1921 | 1 |
... | ... |
2016 | 32 |
2017 | 14 |
2018 | 28 |
2019 | 16 |
2020 | 14 |
82 rows × 1 columns
# 연도 데이터프레임과 연도별 열대야일수 데이터프레임 concat
df_seoul_hotnight_count = pd.concat([df_years,df_seoul_hotnight_count], axis=1)
# 불필요한 컬럼 삭제
df_seoul_hotnight_count.drop(columns=[0], inplace=True)
# 컬럼명 변경
df_seoul_hotnight_count.columns=['열대야일수']
# 결측치 확인
df_seoul_hotnight_count.isnull().sum()
열대야일수 28
dtype: int64
# null--> 0으로 채우기
df_seoul_hotnight_count = df_seoul_hotnight_count.fillna(0)
# 열대야일수 자료형을 정수형으로 변경
df_seoul_hotnight_count = df_seoul_hotnight_count.astype('int')
# 열대야 일수가 가장 많았던 해의 데이터 best10
df_seoul_hotnight_count.nlargest(10, '열대야일수')
열대야일수 | |
---|---|
1994 | 34 |
2016 | 32 |
2018 | 28 |
2013 | 20 |
2012 | 17 |
1967 | 16 |
2019 | 16 |
1995 | 15 |
1997 | 14 |
2010 | 14 |
연도별 폭염일수, 열대야일수 시각화¶
서브플롯으로 비교하기¶
fig, ax = plt.subplots()
# 서브플롯 만들기
fig, ax = plt.subplots(1,2,sharex=True,sharey=True)
# 연도별 폭염일수, 열대야일수 시각화
ax[0].plot(df_seoul_hotday_count.index, df_seoul_hotday_count['폭염일수'], 'r.-')
ax[1].plot(df_seoul_hotnight_count.index, df_seoul_hotnight_count['열대야일수'], 'b.-')
# xlabel
ax[0].set_xlabel('연도')
ax[1].set_xlabel('연도')
# ylabel
ax[0].set_ylabel('폭염일수')
ax[1].set_ylabel('열대야일수')
# xticks, yticks 범위 지정하고 틱 공유
ax[0].set_xticks(range(1910, 2021, 10))
ax[0].set_yticks(range(0, 50, 5))
# title
ax[0].set_title('서울시 연도별 폭염 일수')
ax[1].set_title('서울시 연도별 열대야 일수')
fig.tight_layout()
plt.show()
💡폭염은 1940년대에 많이 발생했으며, 열대야는 점점 증가하는 추세를 보이고 있다.
다중막대그래프로 비교하기¶
fig, ax = plt.subplots()
fig, ax = plt.subplots()
ax.bar(df_seoul_hotday_count.index, df_seoul_hotday_count['폭염일수'], width=-0.4,
align='edge', color='r', label='폭염일수')
ax.bar(df_seoul_hotnight_count.index, df_seoul_hotnight_count['열대야일수'], width=0.4,
align='edge', color='b', label='열대야일수')
ax.legend()
ax.set_title('서울시 연도별 폭염/열대야 일수', size=20)
ax.set_xlabel('연도')
ax.set_ylabel('일수')
ax.set_xticks(range(1910, 2021, 10))
ax.set_yticks(range(0, 50, 5))
plt.show()
[101차시]지역별 인구구조 시각화 데이터수집
[102차시]시도별 총인구수 시각화
[103차시]시도별 세대당 인구 시각화
[104차시]시도별 성별 인구 시각화
[105차시]구별, 동별 총 인구수 시각화
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
plt.rcParams['font.family']='Malgun Gothic'
plt.rcParams['axes.unicode_minus']=False
데이터 수집 및 전처리¶
- 행정안전부
https://www.mois.go.kr/
정책자료 > 주민등록인구통계
전체읍면동 현황 - 바로가기
https://jumin.mois.go.kr/index.jsp
데이터프레임 생성 및 전처리¶
데이터프레임 생성¶
df = pd.read_csv('C:/스타터스 교육생공유용/파이썬 교재 및 실습자료/파이썬 데이터 시각화 데이터/data/202110_202110_주민등록인구및세대현황_월간.csv', encoding='cp949')
df
행정구역 | 2021년10월_총인구수 | 2021년10월_세대수 | 2021년10월_세대당 인구 | 2021년10월_남자 인구수 | 2021년10월_여자 인구수 | 2021년10월_남여 비율 | |
---|---|---|---|---|---|---|---|
0 | 서울특별시 (1100000000) | 9,532,428 | 4,422,587 | 2.16 | 4,630,630 | 4,901,798 | 0.94 |
1 | 서울특별시 종로구 (1111000000) | 145,346 | 73,613 | 1.97 | 70,552 | 74,794 | 0.94 |
2 | 서울특별시 종로구 청운효자동(1111051500) | 12,011 | 5,252 | 2.29 | 5,553 | 6,458 | 0.86 |
3 | 서울특별시 종로구 사직동(1111053000) | 9,367 | 4,686 | 2.00 | 4,206 | 5,161 | 0.81 |
4 | 서울특별시 종로구 삼청동(1111054000) | 2,478 | 1,251 | 1.98 | 1,178 | 1,300 | 0.91 |
... | ... | ... | ... | ... | ... | ... | ... |
3847 | 제주특별자치도 서귀포시 서홍동(5013058000) | 10,999 | 4,517 | 2.44 | 5,435 | 5,564 | 0.98 |
3848 | 제주특별자치도 서귀포시 대륜동(5013059000) | 15,216 | 6,760 | 2.25 | 7,691 | 7,525 | 1.02 |
3849 | 제주특별자치도 서귀포시 대천동(5013060000) | 13,900 | 6,474 | 2.15 | 7,048 | 6,852 | 1.03 |
3850 | 제주특별자치도 서귀포시 중문동(5013061000) | 11,886 | 5,731 | 2.07 | 6,057 | 5,829 | 1.04 |
3851 | 제주특별자치도 서귀포시 예래동(5013062000) | 3,916 | 2,011 | 1.95 | 2,004 | 1,912 | 1.05 |
3852 rows × 7 columns
컬럼명 변경¶
df.columns
Index(['행정구역', '2021년10월_총인구수', '2021년10월_세대수', '2021년10월_세대당 인구',
'2021년10월_남자 인구수', '2021년10월_여자 인구수', '2021년10월_남여 비율'],
dtype='object')
df.columns=['행정구역', '총인구수', '세대수', '세대당 인구',
'남자 인구수', '여자 인구수', '남여 비율']
df.head(1)
행정구역 | 총인구수 | 세대수 | 세대당 인구 | 남자 인구수 | 여자 인구수 | 남여 비율 | |
---|---|---|---|---|---|---|---|
0 | 서울특별시 (1100000000) | 9,532,428 | 4,422,587 | 2.16 | 4,630,630 | 4,901,798 | 0.94 |
자료형 확인, 변환¶
# 자료형 확인
df.dtypes
행정구역 object
총인구수 object
세대수 object
세대당 인구 float64
남자 인구수 object
여자 인구수 object
남여 비율 float64
dtype: object
💡숫자 중 ,가 들어있어서 object형으로 인식되고 있다.
# 숫자형으로 변환
# 콤마 없앤 후 int로 변경
df['총인구수'] = df['총인구수'].str.replace(',','').astype('int64')
df['세대수'] = df['세대수'].str.replace(',','').astype('int64')
df['남자 인구수'] = df['남자 인구수'].str.replace(',','').astype('int64')
df['여자 인구수'] = df['여자 인구수'].str.replace(',','').astype('int64')
df.dtypes
행정구역 object
총인구수 int64
세대수 int64
세대당 인구 float64
남자 인구수 int64
여자 인구수 int64
남여 비율 float64
dtype: object
시도별 서브셋 생성¶
컬럼.str.contains(문자열)
: 문자열이 포함된 데이터 추출
df_sido = df[df['행정구역'].str.contains('00000000')].copy()
df_sido
행정구역 | 총인구수 | 세대수 | 세대당 인구 | 남자 인구수 | 여자 인구수 | 남여 비율 | |
---|---|---|---|---|---|---|---|
0 | 서울특별시 (1100000000) | 9532428 | 4422587 | 2.16 | 4630630 | 4901798 | 0.94 |
452 | 부산광역시 (2600000000) | 3356311 | 1541975 | 2.18 | 1642368 | 1713943 | 0.96 |
674 | 대구광역시 (2700000000) | 2390721 | 1062993 | 2.25 | 1178486 | 1212235 | 0.97 |
826 | 인천광역시 (2800000000) | 2945009 | 1294158 | 2.28 | 1474536 | 1470473 | 1.00 |
999 | 광주광역시 (2900000000) | 1442454 | 643841 | 2.24 | 713483 | 728971 | 0.98 |
1102 | 대전광역시 (3000000000) | 1454228 | 662615 | 2.19 | 725742 | 728486 | 1.00 |
1187 | 울산광역시 (3100000000) | 1122566 | 481811 | 2.33 | 576723 | 545843 | 1.06 |
1249 | 세종특별자치시 (3600000000) | 368276 | 151639 | 2.43 | 183879 | 184397 | 1.00 |
1273 | 경기도 (4100000000) | 13549577 | 5820524 | 2.33 | 6820025 | 6729552 | 1.01 |
1882 | 강원도 (4200000000) | 1537717 | 743798 | 2.07 | 774008 | 763709 | 1.01 |
2095 | 충청북도 (4300000000) | 1596948 | 757980 | 2.11 | 810093 | 786855 | 1.03 |
2265 | 충청남도 (4400000000) | 2118977 | 999286 | 2.12 | 1083133 | 1035844 | 1.05 |
2492 | 전라북도 (4500000000) | 1789770 | 847406 | 2.11 | 890378 | 899392 | 0.99 |
2754 | 전라남도 (4600000000) | 1834653 | 901203 | 2.04 | 923037 | 911616 | 1.01 |
3100 | 경상북도 (4700000000) | 2627925 | 1273579 | 2.06 | 1324128 | 1303797 | 1.02 |
3469 | 경상남도 (4800000000) | 3318161 | 1503397 | 2.21 | 1670394 | 1647767 | 1.01 |
3806 | 제주특별자치도 (5000000000) | 676569 | 306741 | 2.21 | 339195 | 337374 | 1.01 |
- 시도명 컬럼 추가
df_sido['시도명'] = df_sido['행정구역'].str.split(' ').str[0] # 공백으로 문자열 분리
df_sido.head()
행정구역 | 총인구수 | 세대수 | 세대당 인구 | 남자 인구수 | 여자 인구수 | 남여 비율 | 시도명 | |
---|---|---|---|---|---|---|---|---|
0 | 서울특별시 (1100000000) | 9532428 | 4422587 | 2.16 | 4630630 | 4901798 | 0.94 | 서울특별시 |
452 | 부산광역시 (2600000000) | 3356311 | 1541975 | 2.18 | 1642368 | 1713943 | 0.96 | 부산광역시 |
674 | 대구광역시 (2700000000) | 2390721 | 1062993 | 2.25 | 1178486 | 1212235 | 0.97 | 대구광역시 |
826 | 인천광역시 (2800000000) | 2945009 | 1294158 | 2.28 | 1474536 | 1470473 | 1.00 | 인천광역시 |
999 | 광주광역시 (2900000000) | 1442454 | 643841 | 2.24 | 713483 | 728971 | 0.98 | 광주광역시 |
시도별 인구수 시각화¶
- 인구 수가 가장 많은 지역은 어디일까?
- 인구 수가 가장 적은 지역은 어디일까?
총 인구수로 데이터 정렬하기¶
df_sido = df_sido.sort_values('총인구수', ascending=False)
막대그래프로 시각화하기¶
matplotlib.pyplot으로 시각화하기¶
plt.rcParams['figure.figsize']=(15,5)
plt.bar(df_sido['시도명'],df_sido['총인구수'])
plt.xticks(rotation=45)
plt.title('2021년 10월 시도별 총 인구수', size=20)
plt.xlabel('시도명')
plt.ylabel('총인구수')
plt.grid(axis='y', ls=':')
plt.show()
seaborn으로 시각화하기¶
sns.barplot(data=df_sido, x='시도명', y='총인구수')
#seaborn으로 그래프를 제작할 때 matplotlib 함수 사용이 가능하다.
plt.xticks(rotation=45)
plt.title('2021년 10월 시도별 총 인구수', size=20)
plt.grid(axis='y', ls=':')
plt.show()
💡seaborn의 데이터에는 ''가 들어가지 않는다. x와 y값에는 ''가 들어간다.
💡우리나라 인구의 대부분은 경기도와 서울특별시에 몰려있다.
파이그래프로 시각화하기¶
plt.figure(facecolor='snow')
plt.pie(df_sido['총인구수'], labels=df_sido['시도명'],
autopct='%.1f%%', pctdistance=0.8, rotatelabels=True)
plt.title('2021년 10월 시도별 총 인구수', size=20)
plt.show()
시도별 세대당 인구수 시각화¶
- 2중 y축 표시하기
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
fig, ax1 = plt.subplots()
#막대그래프
ax1.bar(df_sido['시도명'],df_sido['총인구수'],width=-0.4
, align='edge', label='총인구')
ax1.bar(df_sido['시도명'],df_sido['세대수'],width=0.4
, align='edge', label='세대수')
ax1.legend(loc=(0.3, 0.8))
ax1.set_xlabel('시도명')
ax1.set_ylabel('총인구수, 세대수')
plt.xticks(rotation=45)
#꺾은선그래프
ax2 = ax1.twinx()
ax2.plot(df_sido['시도명'],df_sido['세대당 인구'], 'k^-.',
mfc='r', mec='r', label='세대당 인구')
ax2.legend(loc=(0.6, 0.85))
ax2.set_ylabel('세대당 인구')
ax2.set_title('2021년 10월 시도별 총 인구수, 세대수, 세대당 인구', size=20)
plt.show()
💡세종특별시는 세대당 인구가 가장 많고 세대수가 가장 적다. 세대당 인구가 가장 적은 곳은 전라남도이다.
시도별 성별 인구수 시각화¶
fig, ax1 = plt.subplots()
ax1.bar(df_sido['시도명'],df_sido['남자 인구수'],width=-0.4
, align='edge', color='skyblue', label='남자 인구수')
ax1.bar(df_sido['시도명'],df_sido['여자 인구수'],width=0.4
, align='edge', color='pink', label='여자 인구수')
ax1.legend(loc=(0.2,0.8))
plt.xticks(rotation=45)
ax2 = ax1.twinx()
ax2.plot(df_sido['시도명'],df_sido['남여 비율'], 'b^-.',
mfc='r', mec='r', label='남여 비율')
ax2.legend(loc=(0.6,0.85))
#수평선
ax2.axhline(1, color='k')
ax2.set_title('2021년 10월 시도별 남여인구수, 남여비율', size=20)
plt.show()
💡선을 기준으로 위는 남자의 비율이 아래는 여자의 비율이 많은 것이다.
성별 인구수 차이¶
성별 인구수 차이 컬럼 생성¶
- 내림차순으로 정렬
df_sido['남여인구수차이'] = df_sido['남자 인구수']-df_sido['여자 인구수']
df_sido = df_sido.sort_values('남여인구수차이', ascending=False)
df_sido
행정구역 | 총인구수 | 세대수 | 세대당 인구 | 남자 인구수 | 여자 인구수 | 남여 비율 | 시도명 | 남여인구수차이 | |
---|---|---|---|---|---|---|---|---|---|
1273 | 경기도 (4100000000) | 13549577 | 5820524 | 2.33 | 6820025 | 6729552 | 1.01 | 경기도 | 90473 |
2265 | 충청남도 (4400000000) | 2118977 | 999286 | 2.12 | 1083133 | 1035844 | 1.05 | 충청남도 | 47289 |
1187 | 울산광역시 (3100000000) | 1122566 | 481811 | 2.33 | 576723 | 545843 | 1.06 | 울산광역시 | 30880 |
2095 | 충청북도 (4300000000) | 1596948 | 757980 | 2.11 | 810093 | 786855 | 1.03 | 충청북도 | 23238 |
3469 | 경상남도 (4800000000) | 3318161 | 1503397 | 2.21 | 1670394 | 1647767 | 1.01 | 경상남도 | 22627 |
3100 | 경상북도 (4700000000) | 2627925 | 1273579 | 2.06 | 1324128 | 1303797 | 1.02 | 경상북도 | 20331 |
2754 | 전라남도 (4600000000) | 1834653 | 901203 | 2.04 | 923037 | 911616 | 1.01 | 전라남도 | 11421 |
1882 | 강원도 (4200000000) | 1537717 | 743798 | 2.07 | 774008 | 763709 | 1.01 | 강원도 | 10299 |
826 | 인천광역시 (2800000000) | 2945009 | 1294158 | 2.28 | 1474536 | 1470473 | 1.00 | 인천광역시 | 4063 |
3806 | 제주특별자치도 (5000000000) | 676569 | 306741 | 2.21 | 339195 | 337374 | 1.01 | 제주특별자치도 | 1821 |
1249 | 세종특별자치시 (3600000000) | 368276 | 151639 | 2.43 | 183879 | 184397 | 1.00 | 세종특별자치시 | -518 |
1102 | 대전광역시 (3000000000) | 1454228 | 662615 | 2.19 | 725742 | 728486 | 1.00 | 대전광역시 | -2744 |
2492 | 전라북도 (4500000000) | 1789770 | 847406 | 2.11 | 890378 | 899392 | 0.99 | 전라북도 | -9014 |
999 | 광주광역시 (2900000000) | 1442454 | 643841 | 2.24 | 713483 | 728971 | 0.98 | 광주광역시 | -15488 |
674 | 대구광역시 (2700000000) | 2390721 | 1062993 | 2.25 | 1178486 | 1212235 | 0.97 | 대구광역시 | -33749 |
452 | 부산광역시 (2600000000) | 3356311 | 1541975 | 2.18 | 1642368 | 1713943 | 0.96 | 부산광역시 | -71575 |
0 | 서울특별시 (1100000000) | 9532428 | 4422587 | 2.16 | 4630630 | 4901798 | 0.94 | 서울특별시 | -271168 |
💡+: 남자 인구수가 더 많다, -: 여자 인구수가 더 많다
시각화¶
sns.barplot(data=df_sido, x='시도명', y='남여인구수차이')
plt.xticks(rotation=45)
plt.axhline(0, color='gray')
plt.title('2021년 10월 시도별 남여 인구수 차이', size=20)
plt.ylabel('남자인구수 - 여자인구수')
plt.show()
서울시 구별/동별 인구수 시각화¶
서울시 구별 인구수 시각화¶
서브셋 생성¶
df_seoul = df[df['행정구역'].str.find('구 (11')>0].copy()
df_seoul.head(1)
행정구역 | 총인구수 | 세대수 | 세대당 인구 | 남자 인구수 | 여자 인구수 | 남여 비율 | |
---|---|---|---|---|---|---|---|
1 | 서울특별시 종로구 (1111000000) | 145346 | 73613 | 1.97 | 70552 | 74794 | 0.94 |
df_seoul['구'] = df_seoul['행정구역'].str.split(' ').str[1]
df_seoul.head()
행정구역 | 총인구수 | 세대수 | 세대당 인구 | 남자 인구수 | 여자 인구수 | 남여 비율 | 구 | |
---|---|---|---|---|---|---|---|---|
1 | 서울특별시 종로구 (1111000000) | 145346 | 73613 | 1.97 | 70552 | 74794 | 0.94 | 종로구 |
19 | 서울특별시 중구 (1114000000) | 122781 | 63409 | 1.94 | 59802 | 62979 | 0.95 | 중구 |
35 | 서울특별시 용산구 (1117000000) | 223713 | 111067 | 2.01 | 107607 | 116106 | 0.93 | 용산구 |
52 | 서울특별시 성동구 (1120000000) | 287174 | 134517 | 2.13 | 139958 | 147216 | 0.95 | 성동구 |
70 | 서울특별시 광진구 (1121500000) | 340814 | 167559 | 2.03 | 164425 | 176389 | 0.93 | 광진구 |
df_seoul = df_seoul.sort_values('총인구수', ascending=False)
df_seoul
행정구역 | 총인구수 | 세대수 | 세대당 인구 | 남자 인구수 | 여자 인구수 | 남여 비율 | 구 | |
---|---|---|---|---|---|---|---|---|
404 | 서울특별시 송파구 (1171000000) | 659239 | 282185 | 2.34 | 317773 | 341466 | 0.93 | 송파구 |
256 | 서울특별시 강서구 (1150000000) | 575370 | 270623 | 2.13 | 277041 | 298329 | 0.93 | 강서구 |
381 | 서울특별시 강남구 (1168000000) | 533878 | 234533 | 2.28 | 255473 | 278405 | 0.92 | 강남구 |
168 | 서울특별시 노원구 (1135000000) | 512129 | 217201 | 2.36 | 246650 | 265479 | 0.93 | 노원구 |
340 | 서울특별시 관악구 (1162000000) | 487357 | 276315 | 1.76 | 244844 | 242513 | 1.01 | 관악구 |
188 | 서울특별시 은평구 (1138000000) | 473369 | 214126 | 2.21 | 226514 | 246855 | 0.92 | 은평구 |
432 | 서울특별시 강동구 (1174000000) | 463752 | 201428 | 2.30 | 227755 | 235997 | 0.97 | 강동구 |
237 | 서울특별시 양천구 (1147000000) | 448634 | 181434 | 2.47 | 219862 | 228772 | 0.96 | 양천구 |
118 | 서울특별시 성북구 (1129000000) | 432081 | 195126 | 2.21 | 208308 | 223773 | 0.93 | 성북구 |
362 | 서울특별시 서초구 (1165000000) | 415083 | 171083 | 2.43 | 198470 | 216613 | 0.92 | 서초구 |
277 | 서울특별시 구로구 (1153000000) | 397330 | 180541 | 2.20 | 195909 | 201421 | 0.97 | 구로구 |
101 | 서울특별시 중랑구 (1126000000) | 388218 | 185505 | 2.09 | 191601 | 196617 | 0.97 | 중랑구 |
324 | 서울특별시 동작구 (1159000000) | 386246 | 184598 | 2.09 | 186863 | 199383 | 0.94 | 동작구 |
305 | 서울특별시 영등포구 (1156000000) | 377524 | 186585 | 2.02 | 186390 | 191134 | 0.98 | 영등포구 |
220 | 서울특별시 마포구 (1144000000) | 369695 | 179571 | 2.06 | 173985 | 195710 | 0.89 | 마포구 |
70 | 서울특별시 광진구 (1121500000) | 340814 | 167559 | 2.03 | 164425 | 176389 | 0.93 | 광진구 |
86 | 서울특별시 동대문구 (1123000000) | 337538 | 167754 | 2.01 | 166842 | 170696 | 0.98 | 동대문구 |
153 | 서울특별시 도봉구 (1132000000) | 318299 | 138655 | 2.30 | 154970 | 163329 | 0.95 | 도봉구 |
205 | 서울특별시 서대문구 (1141000000) | 305840 | 143723 | 2.13 | 146208 | 159632 | 0.92 | 서대문구 |
139 | 서울특별시 강북구 (1130500000) | 300278 | 144501 | 2.08 | 146240 | 154038 | 0.95 | 강북구 |
52 | 서울특별시 성동구 (1120000000) | 287174 | 134517 | 2.13 | 139958 | 147216 | 0.95 | 성동구 |
294 | 서울특별시 금천구 (1154500000) | 230740 | 116935 | 1.97 | 116588 | 114152 | 1.02 | 금천구 |
35 | 서울특별시 용산구 (1117000000) | 223713 | 111067 | 2.01 | 107607 | 116106 | 0.93 | 용산구 |
1 | 서울특별시 종로구 (1111000000) | 145346 | 73613 | 1.97 | 70552 | 74794 | 0.94 | 종로구 |
19 | 서울특별시 중구 (1114000000) | 122781 | 63409 | 1.94 | 59802 | 62979 | 0.95 | 중구 |
시각화¶
sns.barplot(data=df_seoul, x='구', y='총인구수')
plt.title('2021년 10월 서울시 구별 총 인구수', size=20)
plt.xticks(rotation=45)
plt.show()
💡송파구의 인구가 가장 많다.
동별 인구수 시각화¶
- 송파구 동별 인구수 시각화
서브셋 만들기¶
df_song = df[df['행정구역'].str.find('동(1171')>0].copy()
#송파구만하면 동이 없는 데이터도 불러와지기 때문에
df_song['동'] = df_song['행정구역'].str.split(' ').str[2].str.split('(').str[0]
df_song
행정구역 | 총인구수 | 세대수 | 세대당 인구 | 남자 인구수 | 여자 인구수 | 남여 비율 | 동 | |
---|---|---|---|---|---|---|---|---|
405 | 서울특별시 송파구 풍납1동(1171051000) | 12989 | 6027 | 2.16 | 6355 | 6634 | 0.96 | 풍납1동 |
406 | 서울특별시 송파구 풍납2동(1171052000) | 24977 | 11019 | 2.27 | 11873 | 13104 | 0.91 | 풍납2동 |
407 | 서울특별시 송파구 거여1동(1171053100) | 12615 | 5648 | 2.23 | 6367 | 6248 | 1.02 | 거여1동 |
408 | 서울특별시 송파구 거여2동(1171053200) | 18811 | 8153 | 2.31 | 9252 | 9559 | 0.97 | 거여2동 |
409 | 서울특별시 송파구 마천1동(1171054000) | 19005 | 8785 | 2.16 | 9718 | 9287 | 1.05 | 마천1동 |
410 | 서울특별시 송파구 마천2동(1171055000) | 18845 | 8726 | 2.16 | 9587 | 9258 | 1.04 | 마천2동 |
411 | 서울특별시 송파구 방이1동(1171056100) | 15771 | 6263 | 2.52 | 7603 | 8168 | 0.93 | 방이1동 |
412 | 서울특별시 송파구 방이2동(1171056200) | 26657 | 15316 | 1.74 | 12388 | 14269 | 0.87 | 방이2동 |
413 | 서울특별시 송파구 오륜동(1171056600) | 18063 | 5929 | 3.05 | 8857 | 9206 | 0.96 | 오륜동 |
414 | 서울특별시 송파구 오금동(1171057000) | 38637 | 15663 | 2.47 | 18739 | 19898 | 0.94 | 오금동 |
415 | 서울특별시 송파구 송파1동(1171058000) | 23987 | 12264 | 1.96 | 11205 | 12782 | 0.88 | 송파1동 |
416 | 서울특별시 송파구 송파2동(1171059000) | 19219 | 7235 | 2.66 | 9239 | 9980 | 0.93 | 송파2동 |
417 | 서울특별시 송파구 석촌동(1171060000) | 31669 | 16904 | 1.87 | 15120 | 16549 | 0.91 | 석촌동 |
418 | 서울특별시 송파구 삼전동(1171061000) | 30443 | 16078 | 1.89 | 14341 | 16102 | 0.89 | 삼전동 |
419 | 서울특별시 송파구 가락본동(1171062000) | 26387 | 11877 | 2.22 | 13063 | 13324 | 0.98 | 가락본동 |
420 | 서울특별시 송파구 가락1동(1171063100) | 27316 | 9799 | 2.79 | 13238 | 14078 | 0.94 | 가락1동 |
421 | 서울특별시 송파구 가락2동(1171063200) | 32457 | 12460 | 2.60 | 15945 | 16512 | 0.97 | 가락2동 |
422 | 서울특별시 송파구 문정1동(1171064100) | 20092 | 8487 | 2.37 | 9949 | 10143 | 0.98 | 문정1동 |
423 | 서울특별시 송파구 문정2동(1171064200) | 28923 | 15708 | 1.84 | 13304 | 15619 | 0.85 | 문정2동 |
424 | 서울특별시 송파구 장지동(1171064600) | 29458 | 12066 | 2.44 | 14248 | 15210 | 0.94 | 장지동 |
425 | 서울특별시 송파구 위례동(1171064700) | 37697 | 12241 | 3.08 | 18331 | 19366 | 0.95 | 위례동 |
426 | 서울특별시 송파구 잠실본동(1171065000) | 28026 | 15435 | 1.82 | 13259 | 14767 | 0.90 | 잠실본동 |
427 | 서울특별시 송파구 잠실2동(1171067000) | 35210 | 11633 | 3.03 | 16842 | 18368 | 0.92 | 잠실2동 |
428 | 서울특별시 송파구 잠실3동(1171068000) | 34389 | 11930 | 2.88 | 16353 | 18036 | 0.91 | 잠실3동 |
429 | 서울특별시 송파구 잠실4동(1171069000) | 21252 | 7268 | 2.92 | 10189 | 11063 | 0.92 | 잠실4동 |
430 | 서울특별시 송파구 잠실6동(1171071000) | 16765 | 5879 | 2.85 | 7940 | 8825 | 0.90 | 잠실6동 |
431 | 서울특별시 송파구 잠실7동(1171072000) | 9579 | 3392 | 2.82 | 4468 | 5111 | 0.87 | 잠실7동 |
df_song = df_song.sort_values('총인구수', ascending=False)
시각화¶
sns.barplot(data=df_song, x='동', y='총인구수')
plt.title('2021년 10월 송파구 동별 총 인구수', size=20)
plt.xticks(rotation=45)
plt.show()
💡송파구의 오금동에 인구수가 가장 많다.
[106차시]데이터 수집 및 전처리
[107차시]시도-연령별 인구구조
[108차시]서울시 구별 인구구조
[109차시]특정 동 인구구조
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
plt.rcParams['font.family']='Malgun Gothic'
plt.rcParams['axes.unicode_minus']=False
데이터 수집 및 전처리¶
행정안전부
https://www.mois.go.kr/
정책자료 > 주민등록인구통계>연령별 인구 통계
성별구분하지않음, 1세단위, 0~100세이상, 전체읍면동 현황
df = pd.read_csv('C:/스타터스 교육생공유용/파이썬 교재 및 실습자료/파이썬 데이터 시각화 데이터/data/202110_202110_연령별인구현황_월간.csv', encoding='cp949')
df.head(3)
행정구역 | 2021년10월_계_총인구수 | 2021년10월_계_연령구간인구수 | 2021년10월_계_0세 | 2021년10월_계_1세 | 2021년10월_계_2세 | 2021년10월_계_3세 | 2021년10월_계_4세 | 2021년10월_계_5세 | 2021년10월_계_6세 | ... | 2021년10월_계_91세 | 2021년10월_계_92세 | 2021년10월_계_93세 | 2021년10월_계_94세 | 2021년10월_계_95세 | 2021년10월_계_96세 | 2021년10월_계_97세 | 2021년10월_계_98세 | 2021년10월_계_99세 | 2021년10월_계_100세 이상 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 서울특별시 (1100000000) | 9,532,428 | 9,532,428 | 43,440 | 45,655 | 49,757 | 52,347 | 56,653 | 64,586 | 67,597 | ... | 8,207 | 6,755 | 5,313 | 3,972 | 2,568 | 1,869 | 1,385 | 1,319 | 820 | 2,228 |
1 | 서울특별시 종로구 (1111000000) | 145,346 | 145,346 | 476 | 501 | 564 | 579 | 667 | 795 | 850 | ... | 169 | 150 | 109 | 100 | 67 | 47 | 31 | 27 | 30 | 54 |
2 | 서울특별시 종로구 청운효자동(1111051500) | 12,011 | 12,011 | 44 | 48 | 58 | 56 | 86 | 73 | 96 | ... | 8 | 12 | 8 | 7 | 7 | 3 | 3 | 3 | 3 | 5 |
3 rows × 104 columns
컬럼삭제¶
df.drop(columns=['2021년10월_계_총인구수','2021년10월_계_연령구간인구수'], inplace=True)
df.head(1)
행정구역 | 2021년10월_계_0세 | 2021년10월_계_1세 | 2021년10월_계_2세 | 2021년10월_계_3세 | 2021년10월_계_4세 | 2021년10월_계_5세 | 2021년10월_계_6세 | 2021년10월_계_7세 | 2021년10월_계_8세 | ... | 2021년10월_계_91세 | 2021년10월_계_92세 | 2021년10월_계_93세 | 2021년10월_계_94세 | 2021년10월_계_95세 | 2021년10월_계_96세 | 2021년10월_계_97세 | 2021년10월_계_98세 | 2021년10월_계_99세 | 2021년10월_계_100세 이상 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 서울특별시 (1100000000) | 43,440 | 45,655 | 49,757 | 52,347 | 56,653 | 64,586 | 67,597 | 67,337 | 68,428 | ... | 8,207 | 6,755 | 5,313 | 3,972 | 2,568 | 1,869 | 1,385 | 1,319 | 820 | 2,228 |
1 rows × 102 columns
인덱스 변경¶
df.index=df['행정구역']
df.head(1)
행정구역 | 2021년10월_계_0세 | 2021년10월_계_1세 | 2021년10월_계_2세 | 2021년10월_계_3세 | 2021년10월_계_4세 | 2021년10월_계_5세 | 2021년10월_계_6세 | 2021년10월_계_7세 | 2021년10월_계_8세 | ... | 2021년10월_계_91세 | 2021년10월_계_92세 | 2021년10월_계_93세 | 2021년10월_계_94세 | 2021년10월_계_95세 | 2021년10월_계_96세 | 2021년10월_계_97세 | 2021년10월_계_98세 | 2021년10월_계_99세 | 2021년10월_계_100세 이상 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
행정구역 | |||||||||||||||||||||
서울특별시 (1100000000) | 서울특별시 (1100000000) | 43,440 | 45,655 | 49,757 | 52,347 | 56,653 | 64,586 | 67,597 | 67,337 | 68,428 | ... | 8,207 | 6,755 | 5,313 | 3,972 | 2,568 | 1,869 | 1,385 | 1,319 | 820 | 2,228 |
1 rows × 102 columns
df = df.drop(columns=['행정구역'])
df.head(1)
2021년10월_계_0세 | 2021년10월_계_1세 | 2021년10월_계_2세 | 2021년10월_계_3세 | 2021년10월_계_4세 | 2021년10월_계_5세 | 2021년10월_계_6세 | 2021년10월_계_7세 | 2021년10월_계_8세 | 2021년10월_계_9세 | ... | 2021년10월_계_91세 | 2021년10월_계_92세 | 2021년10월_계_93세 | 2021년10월_계_94세 | 2021년10월_계_95세 | 2021년10월_계_96세 | 2021년10월_계_97세 | 2021년10월_계_98세 | 2021년10월_계_99세 | 2021년10월_계_100세 이상 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
행정구역 | |||||||||||||||||||||
서울특별시 (1100000000) | 43,440 | 45,655 | 49,757 | 52,347 | 56,653 | 64,586 | 67,597 | 67,337 | 68,428 | 74,261 | ... | 8,207 | 6,755 | 5,313 | 3,972 | 2,568 | 1,869 | 1,385 | 1,319 | 820 | 2,228 |
1 rows × 101 columns
컬럼명 변경¶
df.columns = df.columns.str.split('_').str[-1]
df.head(1)
0세 | 1세 | 2세 | 3세 | 4세 | 5세 | 6세 | 7세 | 8세 | 9세 | ... | 91세 | 92세 | 93세 | 94세 | 95세 | 96세 | 97세 | 98세 | 99세 | 100세 이상 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
행정구역 | |||||||||||||||||||||
서울특별시 (1100000000) | 43,440 | 45,655 | 49,757 | 52,347 | 56,653 | 64,586 | 67,597 | 67,337 | 68,428 | 74,261 | ... | 8,207 | 6,755 | 5,313 | 3,972 | 2,568 | 1,869 | 1,385 | 1,319 | 820 | 2,228 |
1 rows × 101 columns
자료형 확인/변경¶
df.dtypes
0세 object
1세 object
2세 object
3세 object
4세 object
...
96세 object
97세 object
98세 object
99세 object
100세 이상 object
Length: 101, dtype: object
#숫자형으로 변경
for i in range(101):
df.iloc[:,i] = df.iloc[:,i].str.replace(',','').astype('int64')
df.dtypes
0세 int64
1세 int64
2세 int64
3세 int64
4세 int64
...
96세 int64
97세 int64
98세 int64
99세 int64
100세 이상 int64
Length: 101, dtype: object
시도-연령별 인구구조¶
서브셋 만들기¶
컬럼.str.contains(문자열)
: 해당 문자열이 포함된 데이터 추출
df_sido = df[df.index.str.contains('00000000')]
시각화¶
다중플롯¶
plt.rcParams['figure.figsize']=(12,5)
for i in range(len(df_sido)):
plt.plot(df_sido.iloc[i], label=df_sido.index[i].split(' ')[0])
plt.legend()
plt.xticks(range(0,101,5))
plt.xlabel('연령')
plt.ylabel('인구수')
plt.title('2021년 10월 시도-연령별 인구수', size=20)
plt.show()
서브플롯¶
plt.subplot(행,열,순번)
fig = plt.figure(figsize=(20,30))
for i in range(len(df_sido)):
plt.subplot(6,3,i+1) #서브플롯은 0이 아닌 1부터 시작하기 때문에 i+1을 해줌
plt.plot(df_sido.iloc[i])
plt.xticks(range(0,101,10))
plt.title(df_sido.index[i].split(' ')[0])
plt.grid(ls=':')
fig.tight_layout()
plt.show()
💡지방으로 갈수록 노인인구가 많아진다.
서울시 구별 인구구조¶
서브셋 만들기¶
df_seoul = df[df.index.str.find('구 (11')>0]
시각화¶
다중플롯¶
for i in range(len(df_seoul)):
plt.plot(df_seoul.iloc[i], label=df_seoul.index[i].split(' ')[1])
plt.xticks(range(0,101,10))
plt.title('2021년 서울 구별-연령별 인구구조', size=20)
plt.legend(ncol=2)
plt.ylabel('인구수')
plt.show()
서브플롯¶
fig.add_subplot(행,열,순번)
fig = plt.figure(figsize=(15,30))
for i in range(len(df_seoul)):
ax = fig.add_subplot(9,3,i+1)
ax.plot(df_seoul.iloc[i])
ax.set_title(df_seoul.index[i].split(' ')[1])
ax.set_xticks(range(0,101,10))
# y값이 가장 큰 그래프를 찾아 y 축 통일
ax.set_yticks(range(0,15000,1000))
fig.tight_layout()
plt.show()
💡특징이 있는 구가 존재함: 종로구, 중구는 사람이 많이 살지 않는다. 관악구는 2-30대가 많다. 고시촌 및 대학가가 형성되어있고 출퇴근 접근성이 좋기 때문이다
특정 동 인구구조¶
학군지 인구구조¶
- 대치, 목
fig, ax = plt.subplots()
df_dong = df[(df.index.str.contains('강남구 대치'))|(df.index.str.contains('양천구 목'))].copy()
df_dong
0세 | 1세 | 2세 | 3세 | 4세 | 5세 | 6세 | 7세 | 8세 | 9세 | ... | 91세 | 92세 | 93세 | 94세 | 95세 | 96세 | 97세 | 98세 | 99세 | 100세 이상 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
행정구역 | |||||||||||||||||||||
서울특별시 양천구 목1동(1147051000) | 95 | 111 | 136 | 183 | 209 | 293 | 373 | 403 | 482 | 485 | ... | 22 | 18 | 11 | 9 | 5 | 4 | 2 | 7 | 0 | 3 |
서울특별시 양천구 목2동(1147052000) | 147 | 117 | 135 | 150 | 145 | 180 | 168 | 185 | 184 | 181 | ... | 25 | 14 | 13 | 9 | 3 | 4 | 1 | 6 | 0 | 2 |
서울특별시 양천구 목3동(1147053000) | 121 | 134 | 116 | 125 | 155 | 119 | 150 | 116 | 94 | 118 | ... | 16 | 16 | 13 | 6 | 5 | 3 | 1 | 4 | 2 | 6 |
서울특별시 양천구 목4동(1147054000) | 50 | 65 | 87 | 84 | 111 | 127 | 152 | 163 | 200 | 237 | ... | 23 | 12 | 12 | 4 | 2 | 3 | 2 | 2 | 2 | 12 |
서울특별시 양천구 목5동(1147055000) | 112 | 111 | 140 | 195 | 242 | 320 | 416 | 488 | 543 | 637 | ... | 27 | 25 | 19 | 21 | 9 | 12 | 3 | 4 | 1 | 3 |
서울특별시 강남구 대치1동(1168060000) | 39 | 43 | 63 | 93 | 115 | 166 | 223 | 272 | 357 | 380 | ... | 18 | 15 | 8 | 5 | 4 | 4 | 1 | 4 | 2 | 5 |
서울특별시 강남구 대치2동(1168061000) | 79 | 101 | 109 | 142 | 170 | 159 | 238 | 284 | 318 | 379 | ... | 16 | 19 | 13 | 7 | 8 | 6 | 1 | 2 | 3 | 2 |
서울특별시 강남구 대치4동(1168063000) | 41 | 49 | 48 | 48 | 52 | 67 | 75 | 92 | 102 | 102 | ... | 13 | 7 | 2 | 3 | 1 | 1 | 1 | 0 | 1 | 1 |
8 rows × 101 columns
fig, ax = plt.subplots(3,3,figsize=(15,10),sharey=True)
# 서브플롯의 행번호:r, 열번호:c
r,c= 0,0
for i in range(len(df_dong)):
ax[r][c].plot(df_dong.iloc[i])
ax[r][c].set_xticks(range(0,101,10))
ax[r][c].set_title(df_dong.index[i].split('(')[0])
c+=1 #그래프를 채우면 열 한칸 이동
if c%3==0: #열이 3칸 모두 채워지면
r+=1 #한 행 밑으로 내려가고
c=0 #첫번째 열부터 다시 시작한다
fig.tight_layout()
💡몇몇 지역에서는 10대의 학생과 4-50대 부모의 인구수가 많은 것으로 나타난다. (학군쪽으로 발달되어있음)
특정 구의 동별 인구구조¶
df_dong2 = df[df.index.str.contains('관악구')]
df_dong2
0세 | 1세 | 2세 | 3세 | 4세 | 5세 | 6세 | 7세 | 8세 | 9세 | ... | 91세 | 92세 | 93세 | 94세 | 95세 | 96세 | 97세 | 98세 | 99세 | 100세 이상 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
행정구역 | |||||||||||||||||||||
서울특별시 관악구 (1162000000) | 1540 | 1679 | 1728 | 1747 | 1999 | 2174 | 2341 | 2276 | 2307 | 2438 | ... | 335 | 274 | 209 | 156 | 96 | 58 | 56 | 62 | 31 | 98 |
서울특별시 관악구 보라매동(1162052500) | 72 | 92 | 91 | 100 | 104 | 132 | 149 | 135 | 122 | 123 | ... | 19 | 17 | 12 | 9 | 8 | 3 | 3 | 4 | 0 | 3 |
서울특별시 관악구 청림동(1162054500) | 122 | 116 | 114 | 110 | 130 | 143 | 127 | 104 | 109 | 116 | ... | 18 | 15 | 11 | 3 | 5 | 1 | 1 | 0 | 2 | 3 |
서울특별시 관악구 성현동(1162056500) | 116 | 139 | 144 | 153 | 172 | 191 | 243 | 227 | 233 | 248 | ... | 36 | 21 | 10 | 7 | 6 | 3 | 2 | 4 | 3 | 5 |
서울특별시 관악구 행운동(1162057500) | 85 | 106 | 82 | 109 | 102 | 119 | 117 | 114 | 116 | 118 | ... | 20 | 15 | 8 | 6 | 4 | 2 | 5 | 4 | 0 | 6 |
서울특별시 관악구 낙성대동(1162058500) | 45 | 43 | 44 | 55 | 55 | 57 | 85 | 82 | 89 | 65 | ... | 4 | 9 | 6 | 0 | 3 | 1 | 3 | 1 | 2 | 4 |
서울특별시 관악구 청룡동(1162059500) | 93 | 122 | 114 | 113 | 120 | 130 | 137 | 115 | 119 | 128 | ... | 18 | 13 | 5 | 13 | 5 | 2 | 5 | 3 | 1 | 3 |
서울특별시 관악구 은천동(1162060500) | 153 | 134 | 164 | 153 | 182 | 201 | 220 | 224 | 235 | 258 | ... | 20 | 19 | 19 | 13 | 5 | 5 | 2 | 5 | 1 | 4 |
서울특별시 관악구 중앙동(1162061500) | 32 | 26 | 40 | 32 | 41 | 41 | 44 | 48 | 36 | 45 | ... | 9 | 4 | 3 | 3 | 1 | 3 | 0 | 0 | 1 | 5 |
서울특별시 관악구 인헌동(1162062500) | 82 | 104 | 103 | 89 | 93 | 103 | 94 | 111 | 118 | 125 | ... | 16 | 7 | 9 | 7 | 9 | 5 | 1 | 4 | 2 | 2 |
서울특별시 관악구 남현동(1162063000) | 84 | 87 | 93 | 71 | 106 | 92 | 117 | 104 | 89 | 85 | ... | 9 | 8 | 9 | 2 | 4 | 9 | 1 | 3 | 1 | 3 |
서울특별시 관악구 서원동(1162064500) | 60 | 73 | 58 | 50 | 66 | 66 | 64 | 55 | 85 | 66 | ... | 9 | 10 | 5 | 3 | 6 | 1 | 3 | 0 | 0 | 5 |
서울특별시 관악구 신원동(1162065500) | 45 | 38 | 50 | 37 | 57 | 49 | 58 | 55 | 76 | 54 | ... | 10 | 10 | 10 | 5 | 2 | 4 | 4 | 4 | 5 | 4 |
서울특별시 관악구 서림동(1162066500) | 63 | 56 | 58 | 67 | 81 | 73 | 93 | 82 | 78 | 83 | ... | 11 | 11 | 12 | 8 | 5 | 3 | 3 | 1 | 2 | 7 |
서울특별시 관악구 신사동(1162068500) | 65 | 57 | 76 | 62 | 79 | 78 | 97 | 75 | 84 | 88 | ... | 10 | 8 | 6 | 11 | 4 | 3 | 0 | 3 | 0 | 4 |
서울특별시 관악구 신림동(1162069500) | 44 | 33 | 46 | 24 | 34 | 44 | 32 | 34 | 23 | 25 | ... | 7 | 6 | 3 | 8 | 3 | 1 | 2 | 0 | 0 | 5 |
서울특별시 관악구 난향동(1162071500) | 57 | 80 | 86 | 91 | 117 | 119 | 114 | 143 | 135 | 157 | ... | 11 | 8 | 6 | 8 | 1 | 1 | 1 | 2 | 2 | 2 |
서울특별시 관악구 조원동(1162072500) | 42 | 67 | 43 | 45 | 61 | 75 | 69 | 68 | 65 | 80 | ... | 13 | 7 | 15 | 7 | 2 | 1 | 1 | 1 | 1 | 2 |
서울특별시 관악구 대학동(1162073500) | 53 | 50 | 58 | 66 | 56 | 68 | 59 | 65 | 100 | 80 | ... | 12 | 13 | 9 | 7 | 3 | 1 | 2 | 4 | 1 | 0 |
서울특별시 관악구 삼성동(1162074500) | 42 | 64 | 55 | 69 | 80 | 91 | 94 | 103 | 89 | 110 | ... | 37 | 33 | 21 | 18 | 10 | 3 | 10 | 8 | 2 | 6 |
서울특별시 관악구 미성동(1162076500) | 99 | 105 | 115 | 148 | 148 | 179 | 190 | 202 | 179 | 226 | ... | 25 | 22 | 14 | 7 | 4 | 2 | 5 | 2 | 4 | 18 |
서울특별시 관악구 난곡동(1162077500) | 86 | 87 | 94 | 103 | 115 | 123 | 138 | 130 | 127 | 158 | ... | 21 | 18 | 16 | 11 | 6 | 4 | 2 | 9 | 1 | 7 |
22 rows × 101 columns
fig, ax = plt.subplots(7,3,figsize=(15,15),sharey=True)
# 서브플롯의 행번호:r, 열번호:c
r,c= 0,0
for i in range(1, len(df_dong2)): #관악구 전체 데이터는 제외해주어야 한다.
ax[r][c].plot(df_dong2.iloc[i])
ax[r][c].set_xticks(range(0,101,10))
ax[r][c].set_title(df_dong2.index[i].split('(')[0])
c+=1 #그래프를 채우면 열 한칸 이동
if c%3==0: #열이 3칸 모두 채워지면
r+=1 #한 행 밑으로 내려가고
c=0 #첫번째 열부터 다시 시작한다
fig.tight_layout()
💡관악구에는 대체로 2-30대 인구수가 많다.
[110차시]아파트 실거래가 데이터 수집
[111차시]시도별 아파트 매매가 데이터 추출
[112차시]시도별 아파트 매매가 현황 시각화
[113차시]시도별 아파트 매매가 분포 시각화
[114차시]시도별 아파트 평균 매매가 거래건
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams['font.family']='Malgun Gothic'
plt.rcParams['axes.unicode_minus']=False
데이터 수집 및 전처리¶
데이터 수집¶
- 국토교통부 실거래가 공개시스템
http://rtdown.molit.go.kr/
df=pd.read_csv('C:/스타터스 교육생공유용/파이썬 교재 및 실습자료/파이썬 데이터 시각화 데이터/data/아파트(매매)__실거래가_20211122131854.csv', encoding='cp949')
df
시군구 | 번지 | 본번 | 부번 | 단지명 | 전용면적(㎡) | 계약년월 | 계약일 | 거래금액(만원) | 층 | 건축년도 | 도로명 | 해제사유발생일 | 거래유형 | 중개사소재지 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 강원도 강릉시 견소동 | 202 | 202 | 0 | 송정한신 | 59.800 | 202108 | 12 | 15,000 | 2 | 1997 | 경강로2539번길 8 | NaN | - | - |
1 | 강원도 강릉시 견소동 | 202 | 202 | 0 | 송정한신 | 84.945 | 202108 | 28 | 25,000 | 1 | 1997 | 경강로2539번길 8 | NaN | - | - |
2 | 강원도 강릉시 견소동 | 202 | 202 | 0 | 송정한신 | 39.080 | 202108 | 28 | 12,000 | 7 | 1997 | 경강로2539번길 8 | NaN | - | - |
3 | 강원도 강릉시 견소동 | 289 | 289 | 0 | 송정해변신도브래뉴아파트 | 59.990 | 202108 | 5 | 22,700 | 5 | 2005 | 경강로2539번길 22 | NaN | - | - |
4 | 강원도 강릉시 견소동 | 289 | 289 | 0 | 송정해변신도브래뉴아파트 | 84.990 | 202108 | 9 | 32,500 | 6 | 2005 | 경강로2539번길 22 | NaN | - | - |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
56238 | 충청북도 충주시 호암동 | 1191 | 1191 | 0 | 호암힐데스하임 | 84.890 | 202108 | 24 | 41,000 | 5 | 2019 | 호암토성2로 1 | NaN | - | - |
56239 | 충청북도 충주시 호암동 | 1191 | 1191 | 0 | 호암힐데스하임 | 99.800 | 202108 | 27 | 52,000 | 6 | 2019 | 호암토성2로 1 | NaN | - | - |
56240 | 충청북도 충주시 호암동 | 1191 | 1191 | 0 | 호암힐데스하임 | 84.960 | 202108 | 27 | 42,500 | 2 | 2019 | 호암토성2로 1 | NaN | - | - |
56241 | 충청북도 충주시 호암동 | 1191 | 1191 | 0 | 호암힐데스하임 | 120.490 | 202108 | 31 | 58,000 | 7 | 2019 | 호암토성2로 1 | NaN | - | - |
56242 | 충청북도 충주시 호암동 | 1191 | 1191 | 0 | 호암힐데스하임 | 84.890 | 202108 | 31 | 44,800 | 4 | 2019 | 호암토성2로 1 | NaN | - | - |
56243 rows × 15 columns
데이터 전처리¶
해제사유 발생일¶
- 해제사유 발생일 : 계약이 해지된 건에 대한 해지일
# 해제사유 발생일이 존재하는 데이터 삭제
df=df.drop(index=df[df['해제사유발생일'].notnull()].index)
df[df['해제사유발생일'].notnull()]
시군구 | 번지 | 본번 | 부번 | 단지명 | 전용면적(㎡) | 계약년월 | 계약일 | 거래금액(만원) | 층 | 건축년도 | 도로명 | 해제사유발생일 | 거래유형 | 중개사소재지 |
---|
사용할 컬럼만 추출¶
- 시군구, 전용면적(㎡), 거래금액(만원)
df = df[['시군구', '전용면적(㎡)', '거래금액(만원)']]
df.head()
시군구 | 전용면적(㎡) | 거래금액(만원) | |
---|---|---|---|
0 | 강원도 강릉시 견소동 | 59.800 | 15,000 |
1 | 강원도 강릉시 견소동 | 84.945 | 25,000 |
2 | 강원도 강릉시 견소동 | 39.080 | 12,000 |
3 | 강원도 강릉시 견소동 | 59.990 | 22,700 |
4 | 강원도 강릉시 견소동 | 84.990 | 32,500 |
자료형 확인 및 변경¶
df.dtypes
시군구 object
전용면적(㎡) float64
거래금액(만원) object
dtype: object
# 전용면적 : int(소수점 무시)
df['전용면적(㎡)']=df['전용면적(㎡)'].astype('int64')
# 거래금액 : int
df['거래금액(만원)']=df['거래금액(만원)'].str.replace(',','').astype('int64')
df.dtypes
시군구 object
전용면적(㎡) int64
거래금액(만원) int64
dtype: object
시도별 아파트 매매가 데이터 추출¶
시도 컬럼 추가¶
df['시도'] = df['시군구'].str.split(' ').str[0]
df['시도'].unique()
array(['강원도', '경기도', '경상남도', '경상북도', '광주광역시', '대구광역시', '대전광역시', '부산광역시',
'서울특별시', '세종특별자치시', '울산광역시', '인천광역시', '전라남도', '전라북도', '제주특별자치도',
'충청남도', '충청북도'], dtype=object)
df['시도'].nunique()
17
#거래가 가장 많았던 전용면적
df['전용면적(㎡)'].value_counts()
84 16709
59 13125
49 2256
39 1288
74 1016
...
243 1
214 1
230 1
207 1
222 1
Name: 전용면적(㎡), Length: 213, dtype: int64
💡가장 거래가 많았던 84제곱미터로 결정!
분석할 전용면적 서브셋¶
df_84 = df[df['전용면적(㎡)']==84].copy()
df_84
시군구 | 전용면적(㎡) | 거래금액(만원) | 시도 | |
---|---|---|---|---|
1 | 강원도 강릉시 견소동 | 84 | 25000 | 강원도 |
4 | 강원도 강릉시 견소동 | 84 | 32500 | 강원도 |
7 | 강원도 강릉시 견소동 | 84 | 31900 | 강원도 |
9 | 강원도 강릉시 교동 | 84 | 41000 | 강원도 |
14 | 강원도 강릉시 교동 | 84 | 37900 | 강원도 |
... | ... | ... | ... | ... |
56236 | 충청북도 충주시 호암동 | 84 | 47700 | 충청북도 |
56237 | 충청북도 충주시 호암동 | 84 | 41800 | 충청북도 |
56238 | 충청북도 충주시 호암동 | 84 | 41000 | 충청북도 |
56240 | 충청북도 충주시 호암동 | 84 | 42500 | 충청북도 |
56242 | 충청북도 충주시 호암동 | 84 | 44800 | 충청북도 |
16709 rows × 4 columns
시도별 평균, 최대, 최소, 중간값 추출¶
df_84_mean = df_84.groupby('시도')['거래금액(만원)'].mean()
df_84_max = df_84.groupby('시도')['거래금액(만원)'].max()
df_84_min = df_84.groupby('시도')['거래금액(만원)'].min()
df_84_median = df_84.groupby('시도')['거래금액(만원)'].median()
df_84_price = pd.concat([df_84_mean,df_84_max,df_84_min,df_84_median],axis=1)
df_84_price.columns=['평균', '최대', '최소', '중간'] #컬럼명 변경
df_84_price = df_84_price.sort_values('평균', ascending=False) #평균값을 기준으로 내림차순 정렬
df_84_price['평균'] = round(df_84_price['평균'],1) #평균컬럼 소수점 첫번째 자리까지만 표시
df_84_price
평균 | 최대 | 최소 | 중간 | |
---|---|---|---|---|
시도 | ||||
서울특별시 | 121650.9 | 384500 | 29500 | 109000.0 |
세종특별자치시 | 71412.6 | 119000 | 23800 | 74000.0 |
경기도 | 57935.9 | 220000 | 7400 | 52500.0 |
인천광역시 | 52835.0 | 130000 | 16700 | 47500.0 |
대전광역시 | 45900.6 | 127000 | 12500 | 44435.0 |
제주특별자치도 | 43831.7 | 95000 | 13500 | 42750.0 |
부산광역시 | 43642.9 | 183000 | 9400 | 38000.0 |
대구광역시 | 39517.4 | 148000 | 13700 | 35900.0 |
광주광역시 | 38281.8 | 104500 | 10700 | 34000.0 |
울산광역시 | 36790.1 | 120000 | 6900 | 33000.0 |
경상남도 | 30821.5 | 109000 | 5300 | 28400.0 |
충청북도 | 28915.2 | 72000 | 7600 | 27000.0 |
전라북도 | 26839.7 | 66500 | 4200 | 22800.0 |
충청남도 | 26264.9 | 94500 | 3500 | 23700.0 |
강원도 | 25735.6 | 72500 | 7000 | 23700.0 |
경상북도 | 25636.6 | 64500 | 4000 | 25219.0 |
전라남도 | 23643.1 | 74000 | 6000 | 23000.0 |
시도별 아파트 매매가 현황 시각화¶
- 다중막대그래프
import numpy as np
x_index = np.arange(1, len(df_84_price)+1)
x_index #그래프의 x축으로 사용
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17])
plt.rcParams['figure.figsize']=(15,5)
plt.bar(x_index-0.3, df_84_price['최대'], width=0.2, label='최대')
plt.bar(x_index-0.1, df_84_price['평균'], width=0.2, label='평균')
plt.bar(x_index+0.1, df_84_price['중간'], width=0.2, label='중간')
plt.bar(x_index+0.3, df_84_price['최소'], width=0.2, label='최소')
plt.legend()
plt.xticks(x_index, labels=df_84_price.index, rotation=45)
plt.grid(axis='y', ls=':')
plt.title('2021년 8월 시도별 아파트 매매가 현황(84㎡)', size=20)
plt.ylabel('매매가(만원)')
plt.show()
💡서울의 경우 아파트 매매가 간의 편차가 타지역에 비해 크다.
서울시 아파트 매매가 분포¶
서울시 서브셋¶
df_84_seoul = df_84[df_84['시도']=='서울특별시'].copy()
df_84_seoul.head()
시군구 | 전용면적(㎡) | 거래금액(만원) | 시도 | |
---|---|---|---|---|
35560 | 서울특별시 강남구 개포동 | 84 | 285000 | 서울특별시 |
35561 | 서울특별시 강남구 개포동 | 84 | 275000 | 서울특별시 |
35567 | 서울특별시 강남구 개포동 | 84 | 289000 | 서울특별시 |
35573 | 서울특별시 강남구 개포동 | 84 | 298000 | 서울특별시 |
35583 | 서울특별시 강남구 개포동 | 84 | 77000 | 서울특별시 |
구 컬럼 추가¶
# 구이름
df_84_seoul['구'] = df_84_seoul['시군구'].str.split(' ').str[1]
df_84_seoul.head()
시군구 | 전용면적(㎡) | 거래금액(만원) | 시도 | 구 | |
---|---|---|---|---|---|
35560 | 서울특별시 강남구 개포동 | 84 | 285000 | 서울특별시 | 강남구 |
35561 | 서울특별시 강남구 개포동 | 84 | 275000 | 서울특별시 | 강남구 |
35567 | 서울특별시 강남구 개포동 | 84 | 289000 | 서울특별시 | 강남구 |
35573 | 서울특별시 강남구 개포동 | 84 | 298000 | 서울특별시 | 강남구 |
35583 | 서울특별시 강남구 개포동 | 84 | 77000 | 서울특별시 | 강남구 |
df_84_seoul['구'].nunique()
25
박스플롯으로 시각화¶
구별 데이터 분리¶
# 구이름
seoul_gu = df_84_seoul['구'].unique()
seoul_gu
array(['강남구', '강동구', '강북구', '강서구', '관악구', '광진구', '구로구', '금천구', '노원구',
'도봉구', '동대문구', '동작구', '마포구', '서대문구', '서초구', '성동구', '성북구', '송파구',
'양천구', '영등포구', '용산구', '은평구', '종로구', '중구', '중랑구'], dtype=object)
df_seoul_gu = []
for i in range(len(seoul_gu)):
df_seoul_gu.append(df_84_seoul.groupby('구')['거래금액(만원)'].get_group(seoul_gu[i]))
박스플롯으로 시각화¶
plt.boxplot(df_seoul_gu, labels=seoul_gu, showmeans=True)
plt.xticks(rotation=45)
plt.ylabel('매매가(만원)')
plt.title('2021년 8월 서울시 아파트 매매가 분포(84㎡)', size=20)
plt.show()
💡서초구의 아파트 매매가 분포가 가장 크고 가격대도 높다. 성동구의 경우 매우 높은 가격에 이루어진 거래가 있다는 것을 확인할 수 있다.
서울시 아파트 구별 평균 매매가, 거래건수¶
서울시 아파트 구별 평균 매매가¶
df_84_seoul_mean = df_84_seoul.groupby('구')['거래금액(만원)'].mean()
df_84_seoul_mean = round(df_84_seoul_mean, 1)
df_84_seoul_mean
구
강남구 166324.5
강동구 130831.1
강북구 78541.3
강서구 107935.7
관악구 94022.2
광진구 141525.0
구로구 89275.4
금천구 75415.4
노원구 89126.3
도봉구 77755.1
동대문구 102024.5
동작구 136100.0
마포구 145163.1
서대문구 124358.7
서초구 246792.5
성동구 152622.2
성북구 99480.3
송파구 171039.4
양천구 107729.2
영등포구 115432.1
용산구 161473.7
은평구 94170.7
종로구 143280.0
중구 129078.6
중랑구 82726.4
Name: 거래금액(만원), dtype: float64
서울시 아파트 구별 거래건수¶
df_84_seoul_count = df_84_seoul.groupby('구')['거래금액(만원)'].count()
df_84_seoul_count.sort_values(ascending=False)
구
성북구 104
강서구 98
강남구 84
성동구 72
송파구 71
동작구 63
강동구 61
마포구 61
은평구 58
노원구 57
구로구 57
영등포구 53
중랑구 53
서대문구 52
도봉구 49
동대문구 49
양천구 48
강북구 46
서초구 40
관악구 36
광진구 32
금천구 26
용산구 19
중구 14
종로구 12
Name: 거래금액(만원), dtype: int64
💡이중y축 그래프를 그리기 위해선 x축을 통일시켜야한다.
df_84_seoul_mean_count = pd.concat([df_84_seoul_mean, df_84_seoul_count], axis=1)
df_84_seoul_mean_count.columns=['평균매매가(만원)', '거래건수']
df_84_seoul_mean_count= df_84_seoul_mean_count.sort_values('평균매매가(만원)', ascending=False)
df_84_seoul_mean_count
평균매매가(만원) | 거래건수 | |
---|---|---|
구 | ||
서초구 | 246792.5 | 40 |
송파구 | 171039.4 | 71 |
강남구 | 166324.5 | 84 |
용산구 | 161473.7 | 19 |
성동구 | 152622.2 | 72 |
마포구 | 145163.1 | 61 |
종로구 | 143280.0 | 12 |
광진구 | 141525.0 | 32 |
동작구 | 136100.0 | 63 |
강동구 | 130831.1 | 61 |
중구 | 129078.6 | 14 |
서대문구 | 124358.7 | 52 |
영등포구 | 115432.1 | 53 |
강서구 | 107935.7 | 98 |
양천구 | 107729.2 | 48 |
동대문구 | 102024.5 | 49 |
성북구 | 99480.3 | 104 |
은평구 | 94170.7 | 58 |
관악구 | 94022.2 | 36 |
구로구 | 89275.4 | 57 |
노원구 | 89126.3 | 57 |
중랑구 | 82726.4 | 53 |
강북구 | 78541.3 | 46 |
도봉구 | 77755.1 | 49 |
금천구 | 75415.4 | 26 |
fig, ax1 = plt.subplots()
ax1.bar(df_84_seoul_mean_count.index, df_84_seoul_mean_count['평균매매가(만원)'], label='평균매매가')
plt.xticks(rotation=45)
ax2 = ax1.twinx()
ax2.plot(df_84_seoul_mean_count['거래건수'], 'k^--', mfc='r', mec='r', label='거래건수')
ax1.legend(loc='upper left', edgecolor='k')
ax2.legend(loc='upper right', edgecolor='k')
ax1.set_ylabel('평균매매가(만원)')
ax2.set_ylabel('거래건수')
plt.title('2021년 8월 서울시 아파트 평균매매가, 거래건수(84㎡)', size=20)
plt.show()
💡2021년 8월 서울시 아파트 평균매매가는 서초구가 가장 높았고, 거래건수는 성북구와 강서구가 많았다.
✏️ 어제 일과를 마친 후 강의를 3개 정도 듣고 집에가서 오늘 시간이 조금 남았다. 그래서 애매하게 잘리는 아파트 실거래가 분석, 시각화 강의를 끝까지 들었다! 비슷한 내용을 여러 번 반복하니 조금 헷갈렸던 부분들이 이해되는 시간이었던 것 같다.
파트너간 상보적 학습 및 강의 내용 리뷰
강의를 듣고 헷갈리는 부분에 대해 공유했다. 나는 데이터프레임을 concat하는 과정에서 강사님의 결과와 다른 부분이 있었다. 왼쪽사진은 1913년도의 빈 일시가 잘 concat되어있는데 오른쪽사진은 결과값이 이상했다.
알고보니 df_seoul_hotday_count가 인덱스대로 정렬되어있지 않아서 그렇다고 한다. 해당 데이터프레임 정렬 후 concat하면 왼쪽과 같은 결과가 나온다고 한다!
그 외에도 경기도를 분석할 때 시/구를 처리하는 법에 대해 공유했다. 시도, 군구를 묶어서 분석하면 경기도 지역을 분석하기 편리하다는 팁을 얻었다👍 또 그래프를 그릴 때 두개의 그래프를 더 보기 좋게 구현하는 방법에 대해 고민해보았다. 마지막으로는 범례를 불러올때 iloc가 아닌 column으로 불러오는 과정에서 생기는 오류에 대해 살펴보았다. 컬럼으로 불러오면 시리즈가 되어서 오류가 나는 것 같다고 하셨다.
* 유데미 큐레이션 바로가기 : https://bit.ly/3HRWeVL
* STARTERS 취업 부트캠프 공식 블로그 : https://blog.naver.com/udemy-wjtb
💡본 후기는 유데미-웅진씽크빅 취업 부트캠프 4기 데이터분석/시각화 학습 일지 리뷰로 작성되었습니다.
'교육 > 유데미 스타터스 4기' 카테고리의 다른 글
[👩💻TIL 9일차 ] 유데미 스타터스 취업 부트캠프 4기 (2) | 2023.02.16 |
---|---|
[👩💻TIL 8일차 ] 유데미 스타터스 취업 부트캠프 4기 (0) | 2023.02.15 |
[👩💻TIL 6일차 ] 유데미 스타터스 취업 부트캠프 4기 (0) | 2023.02.13 |
유데미 스타터스 취업 부트캠프 4기 - 데이터분석/시각화(태블로) 1주차 학습 일지 (0) | 2023.02.10 |
[👩💻TIL 5일차 ] 유데미 스타터스 취업 부트캠프 4기 (0) | 2023.02.10 |