관리 메뉴

ilovechoonsik

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

STARTERS 4기 🚉/TIL 👶🏻

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

춘시기좋아 2023. 2. 14. 18:00

 

📖 오늘 내가 배운 것

 

공공 데이터 분석

서울시 연간 기온변화

전국 지점별 기온 

서울시 폭염, 열대야 현황 

지역별 인구구조

연령별 인구구조 

아파트 실거래가 

상가(상권) 정보

 

-> 분석 및 시각화

 

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('202110월 남여인구수, 남여비율', 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 그리는 다양한 방법들 어떤 상황에 뭘 사용하는 게 좋은지 명확히 하기

 

 

 

#유데미 #유데미코리아 #유데미큐레이션 #유데미부트캠프 #취업부트캠프 #스타터스부트캠프 #데이터시각화 #데이터분석 #데이터드리븐 #태블로

Comments