ilovechoonsik
[STARTERS 4기 TIL] 공공 데이터 분석 #2 (230214) 본문

📖 오늘 내가 배운 것
공공 데이터 분석
서울시 연간 기온변화
전국 지점별 기온
서울시 폭염, 열대야 현황
지역별 인구구조
연령별 인구구조
아파트 실거래가
상가(상권) 정보
-> 분석 및 시각화
1. 분석 프로세스
1.1 데이터 추출/준비 및 확인
목적 | 방안 |
1. 수집 | 개방포털 접속 및 다운로드 |
2. 데이터 프레임 생성 및 연결 | concat() - axis - ignore_index |
3. 데이터 확인 | dtypes shape() info() unique(), nuique() |
4. 전처리 | isnull() drop() dropna() astype(), to_datetime() replace() loc[], iloc[] apply() |
5. 목적에 맞는 서브셋 생성 | 다양한 기법 사용해서 가공 후 copy() |
1.2 EDA/시각화
목적 | 방안 |
EDA | 1.1 과정의 모든 방안 이용 |
시각화 | matplotlib, seaborn |
2. 다시 볼만한 내용
데이터 분석 프로세스 구간 별 중요했던, 다시 볼만한 개념 정리
2.1 수집 및 전처리
2.1.1 subset 생성할 때 데이터 찾는, 뽑는 방법들
(1) str, find 사용 - boolean indexing
# 서울시 구별 인구수 시각화
# 구 (11 로 시작하면 구 이기 때문에 str과 문자열 함수 find 사용하여 True로 반환받는다
# 그 값이 0 보다 클 것이기 때문에 조건을 걸고 boolean indexing!
df_seoul = df[df['행정구역'].str.find('구 (11')>0].copy()
# 구 별로 데이터를 그룹화 할 것이기 때문에 str-split을 통해 분리하고
# 그 중 str[1]번째 데이터를 가져온다,
df_seoul['구'] = df_seoul['행정구역'].str.split(' ').str[1]
# 동별 인구수 시각화
# 송파구 동별 인구수 시각화
df_song['동'] = df_song['행정구역'].str.split(' ').str[2].str.split('(').str[0]
df_song
(2) str.contains - boolean indexing
- 컬럼.str.contains(문자열) : 문자열이 포함된 데이터 추출
df_sido = df[df['행정구역'].str.contains('00000000')].copy()
(3) groupby 후 값없어서 생략된 연도 포함시키기
# 연도별 폭염일수 : 연도로 그룹핑하여 일수 카운트
df_seoul_hotday_count = df_seoul_hotday.groupby(df_seoul_hotday['일시'].dt.year)['일시'].count().to_frame()
# 폭염일이 없는 날을 포함시키기 위하여 1911~2020년의 연도 데이터프레임 생성
df_years = pd.DataFrame(range(1911,2021))
df_years.index = df_years[0]
df_years
# 연도별 폭염일수, 연도 데이터프레임 concat
df_seoul_hotday_count = pd.concat([df_seoul_hotday_count,df_years], axis=1)
df_seoul_hotday_count
(4) str -> int 자료형 일괄 변경
for i in range(101):
df.iloc[:,i] = df.iloc[:,i].str.replace(',','').astype('int64')
# df의 모든행의 100까지의 열을 각각 돌면서 , 을 뺴버리고 int64로 변경!
# 이걸 df.iloc[:,i] i에 맞춰 전부 적용
(5) index 가지고 데이터 삭제하기
계약이 된 상태인 행들만 보고 싶다! 해제사유발생한 행(notnull())은 날려줘라~
df = df.drop(index=df[df['해제사유발생일'].notnull()].index)
(6) 컬럼의 중복되지 않는 고유한 값들만 보려면 + 볼 수 있는 행 수 늘리기 (=저번 🥓)
df_store_class = df_store[['상권업종대분류명','상권업종중분류명','상권업종소분류명']].drop_duplicates().sort_values(['상권업종대분류명','상권업종중분류명','상권업종소분류명'])
# 상권업종 분류표 모두보기(최대 행 수 지정)
pd.options.display.max_rows=20
2.3 시각화 부분
2.3.1 다중 막대그래프를 통한 비교
서울시 연도별 폭염일수, 열대야일수 (bar)
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='k', 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()

2.3.2 barplot, plot 특정 부분 강조하기 + 강조용 text 찍기
(1) 2020년 전국 지점별 연평균기온
# 지점별 연 평균기온
# 막대는 x,y다 지정해줘야 함.
plt.figure(figsize=(20,5))
plt.bar(df_2020_mean.index, df_2020_mean.values, color='Lightgreen')
plt.xticks(rotation=90)
plt.axhline(df_2020_mean.max(), color='r', linestyle='--', label='최고'+str(round(df_2020_mean.max(),1)))
plt.axhline(df_2020_mean.mean(), color='g', linestyle='--', label='평균'+str(round(df_2020_mean.mean(),1)))
plt.axhline(df_2020_mean.min(), color='b', linestyle='--', label='최저'+str(round(df_2020_mean.min(),1)))
plt.legend(loc=(0,1), ncol=3, fontsize=12, edgecolor='k')
# 서울지역 표시
# bar 하나 더 그려서 겹쳐버리기, loc으로 index=서울인 값 y축으로
plt.bar('서울', df_2020_mean.loc['서울'])
plt.text('서울', df_2020_mean.loc['서울']+0.5, '서울 ('+str(round(df_2020_mean.loc['서울'],1))+')'
, ha='center', fontsize=15)
plt.title('2020년 전국 지점별 연 평균기온', size=20, pad=20)
plt.show()

(2) 서울시 열대야 현황 (1911 ~ 2020)
# plot
plt.plot(df_seoul_hotnight['일시'], df_seoul_hotnight['최저기온(°C)'], 'k.')
plt.title('서울시 열대야 현황(1911~2020)', size=20)
plt.xlabel('일시')
plt.ylabel('일 최저기온(°C)')
# 가장 더웠던 밤 표시
plt.plot(df_seoul_hotestnight.iloc[0,2].date(), df_seoul_hotestnight.iloc[0,4], 'k^')
# 가장 더웠던 날짜, 온도 표시
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()

2.3.3 y축 공유 시각화 twinx
- 2중 y축 표시하기 (객체 지향으로 그려야 함)
- fig, ax1 = plt.subplots()
- ax2 = ax1.twinx()
(1) 2021년 10월 남여인구수(plot), 남여비율(bar)
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, c='g', alpha=0.5)
ax2.set_title('2021년 10월 남여인구수, 남여비율', size=20, pad=10)
plt.show()

2.3.4 subplots sharex, sharey
# 스타일 파라미터
plt.rcParams['hatch.color']='w'
# 서브플롯 만들기(plt.subplots())
fig, ax = plt.subplots(1,3, figsize=(15,5), sharex=True, sharey=True) # sharex,y 사용
# 서귀포 일평균기온 히스토그램
ax[0].hist(df_2020_sgp['평균기온(°C)'], rwidth=0.9, hatch='//')
ax[0].set_title('2020년 서귀포 일 평균기온 분포')
ax[0].set_xlabel('일 평균기온(°C)')
ax[0].set_ylabel('일수')
# 서울 일평균기온 히스토그램
ax[1].hist(df_2020_seoul['평균기온(°C)'], rwidth=0.9, hatch='--')
ax[1].set_title('2020년 서울 일 평균기온 분포')
ax[1].set_xlabel('일 평균기온(°C)')
# 대관령
ax[2].hist(df_2020_dgr['평균기온(°C)'], rwidth=0.9, hatch='xx')
ax[2].set_title('2020년 대관련 일 평균기온 분포')
ax[2].set_xlabel('일 평균기온(°C)')
# 0°C 수직선 표시 (영하로 내려가는 날 얼마나 되는지 확인하기 위함!)
ax[0].axvline(0, color='k', ls='--')
ax[1].axvline(0, color='k', ls='--')
ax[2].axvline(0, color='k', ls='--')
plt.tight_layout()
plt.show()

2.3.5 pie
plt.figure(facecolor='snow')
plt.pie(df_sido['총인구수'], labels=df_sido['시도명']
,autopct='%.1f%%', pctdistance=0.8, rotatelabels=True)
# autopct 소수점 1번째 자리까지
# pctdistance 퍼센트 표시 밖으로
# text가 pie와 연장선상에 보이도록 표시
plt.title('2021년 10월 시도별 총 인구수', size=20)
plt.show()

2.3.6 row 단위 추출로 다중 plot 그리기

시도 별 연령 별 인구수 시각화
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()

2.3.7 subplot / subplots
(1) subplot - 반복문, 위치 지정하며 바로 그려버리기
• plt.subplot(행, 열, 순번)
fig = plt.figure(figsize=(20,30)) # 객체로 안 받아도 되긴 하는데 tight_layout() 쓰려고 받음
for i in range(len(df_sido)):
plt.subplot(6,3,i+1) # 몇 번째에 들어가는지! 1부터 시작하기 때문에 0일 수 있는 i에 +1 해줘야 함
plt.plot(df_sido.iloc[i]) # 0~마지막 행 데이터 싹 뽑아와 plot
plt.xticks(range(0,101,10))
plt.title(df_sido.index[i].split(" ")[0])
plt.grid(ls=':')
fig.tight_layout()

(2) subplot - 반복문 ax 객체 받기
• fig.add_subplot(행, 열, 순번)
fig = plt.figure(figsize=(15,30)) # fig 객체 생성
for i in range(len(df_seoul)):
ax = fig.add_subplot(9,3,i+1)
ax.plot(df_seoul.iloc[i])
ax.set_xticks(range(0,101,10))
ax.set_title(df_seoul.index[i].split(' ')[1])
ax.set_yticks(range(0,15000,1000))
fig.tight_layout()
fig.suptitle('서울시 구별 인구 분포', y=1.005, weight='bold', size=20)

(3) subplots - [행][열] 반복문
• fig, ax = plt.subplots(col, row , figsize=(x, y), sharex or y=True)
특정 구의 동별 인구구조
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:
r+=1
c=0
fig.tight_layout()

### 추가로 깨달은 점 ###
plt.set_xlabel='연령'
plt.set_ylabel='인구수'
label을 위와 같이 설정하면 오류가 생기며 다시 사용할 수 없게 된다!
from importlib import reload
plt=reload(plt)
reload로 해결하기
💪🏻 앞으로 개선해야 할 점 (추가로 배워야 할 점)
📌 subplot, subplots 그리는 다양한 방법들 어떤 상황에 뭘 사용하는 게 좋은지 명확히 하기
#유데미 #유데미코리아 #유데미큐레이션 #유데미부트캠프 #취업부트캠프 #스타터스부트캠프 #데이터시각화 #데이터분석 #데이터드리븐 #태블로
'STARTERS 4기 🚉 > TIL 👶🏻' 카테고리의 다른 글
[STARTERS 4기 TIL] SQL 다양한 문법 및 활용 (230216) (0) | 2023.02.18 |
---|---|
[STARTERS 4기 TIL] 데이터 베이스 배경, SQL 활용 조작 (230215) (0) | 2023.02.16 |
[STARTERS 4기 TIL] 데이터 시각화 #2 (230213) (0) | 2023.02.13 |
[STARTERS 4기 TIL] 데이터 시각화 (230210) (0) | 2023.02.10 |
[STARTERS 4기 TIL] 공공 데이터 분석 (230209) (0) | 2023.02.09 |