파이썬/ai

[Ai, Python] Streamlit을 이용한 모델 시각화-7 (인천광역시 집 값 예측)

hojung 2022. 6. 26.
728x90
반응형

1. Streamlit이란?

파이썬 라이브러리 중 하나로 딥러닝 모델이나 데이터 시각화를 쉽게 구현하고 웹서비스로 만들고 싶을 때 이용하면 좋다.

다음은 공식 사이트이다. 

https://streamlit.io/

 

Streamlit • The fastest way to build and share data apps

Streamlit is an open-source app framework for Machine Learning and Data Science teams. Create beautiful web apps in minutes.

streamlit.io

우선 프로젝트 파일을 만들고 pip을 통해 streamlit을 설치해준다. 터미널 프로젝트 폴더 경로에 다음과 같이 입력해주면 된다. 

pip install streamlit

그 후 app.py라는 파이썬 파일을 하나 만들어주고 streamlit 메소드들을 이용하여 데이터를 시각화해주면 된다. 


2. 구현

1. 모델 불러오기

우선 저번 포스트에서 저장한 모델을 streamlit 프로젝트 폴더 안에 넣어준다. 

모델이 들어있다.

pip install xgboost

명령어를 통해 xgboost를 설치해준 후 xgb의 load_model메소드를 이용해서 모델을 불러와준다. 

import matplotlib.pyplot as plt
import xgboost as xgb
import time
import numpy as np
import pandas as pd
import streamlit as st

# xgb모델 불러오기
xgb_model = xgb.XGBRegressor()
xgb_model.load_model('xgb_load_final2.model')

2. 제목

streamlit에서는 제목을 넣을 수 있는 title이라는 메소드를 제공한다. 

# 제목
st.title('Incheon house Price')
st.header('Incheon House Price Prediction Project')

3. 진행상황 바

로딩 상태를 표시할 수 있는 바이다. 

# Add a placeholder 진행 상황 바
latest_iteration = st.empty()
bar = st.progress(0)
for i in range(100):
    # Update the progress bar with each iteration.
    latest_iteration.text(f'Iteration {i+1}')
    bar.progress(i + 1)
    time.sleep(0.01)

4. 마크다운 사용법

마크다운 사용법은 다음과 같이 write메소드안에 """ 문장 """ 안에 적어 넣는 방법이 있고

st.markdown이라는 메소드를 제공하기도 한다. 

# 변수는 총 11개
# 순서대로 전용면적, 계약년월, 거래금액, 층, 건축년도, 대규모 점포, 근린공원, 반료동물 등록 수, 병원, 학교, station, starbucks
st.write("""
## 사용 변수들
1. 전용면적
2. 계약년월
3. 층
4. 건축년도
5. 대규모 점포
6. 근린공원
7. 반려동물 등록 수
8. 병원
9. 학교
10. 지하철 역 개수
11. 스타벅스 수 
""")

st.sidebar.markdown("[호정의 개발 블로그](https://hojung-testbench.tistory.com/)")

5.  slider 사용, date input사용 

# 지역 변수를 제외한 나머지 변수 설정하는 sidebar
width = st.slider("면적을 선택하세요 단위(m^2)", 11, 291)
# 6. 날짜 입력
contractdate = st.date_input('계약년월')  # 디폴트로 오늘 날짜가 찍혀 있다.
contractString = contractdate.strftime("%Y%m")
contract = float(contractString)
st.write(contractdate.strftime("%Y%m"))

floor = st.slider("층을 선택하세요", 1, 60)
builtYear = st.slider("건축년도를 선택하세요(년도)", 1971, 2022)

다음과 같은 화면으로 나온다. 

6. sidebar사용과 selectbox

# 지역을 고르는 select box
option = st.sidebar.selectbox(
    '어떤 지역을 고르시겠습니까?',
    ('용현동', '구월동', '송도동', '주안동', "숭의동", "연수동", "부평동", "청라동", "동춘동", "학익동"))
st.sidebar.write("개발자 블로그")
st.sidebar.markdown("[호정의 개발 블로그](https://hojung-testbench.tistory.com/)")

sidebar api와 selectbox api는 각각 사이드바와 선택 박스를 만들 수 있는 기능을 제공한다. 

7. 지도 

st.write('You selected:', option)
map_data = pd.DataFrame(
    np.random.rand(1, 2) / [50, 50] + maplatlon,
    columns=['lat', 'lon'])
st.map(map_data)

다음과 같이 데이터 프레임을 map api안에 넣어주면 원하는 위도, 경도에 해당하는 위치를 지도에서 보여줄 수 있다. 

maplatlon변수에는 내가 설정한 인천의 위도와 경도가 들어있다. 

8. 차트

# 차트
yrmth_df = df.groupby('yrmth')['거래금액'].agg(AVG='mean', total='count')
vmin = np.min(yrmth_df['total'])
vmax = np.max(yrmth_df['total'])
fig = plt.figure(figsize=(20, 10))
plt.scatter(np.arange(yrmth_df.shape[0]), yrmth_df['AVG'], c=yrmth_df['total'],
            s=yrmth_df['total'], vmin=vmin, vmax=vmax, cmap=plt.cm.Reds)
plt.colorbar(label='total')
plt.title('Monthly Average Price')
plt.xticks(np.arange(yrmth_df.shape[0]), yrmth_df.index.values)
plt.xlabel('YYYYMM - YearMonth')
plt.ylabel('log_Price')
plt.plot(np.arange(yrmth_df.shape[0]), yrmth_df['AVG'])
st.subheader("월 별 아파트 거래량과 거래금액")
st.pyplot(fig)

streamlit에서는 많은 데이터 시각화 기능을 제공하지만 matplotlib을 사용한 차트또한 시각화를 해서 보여줄 수 있다. 

다음은 앞서 feature engineering에서 구현했던 시간 별 거래량과 거래 금액 그래프를 streamlit의 pyplot 메소드를 통해 웹에 구현한 모습이다. 


3. 모델 사용

# scaling되기 전의 데이터
realData = [[width, contract, floor, builtYear, market,
             park, pet, hospital, school, station, starbucks]]

# minMaxScaler를 통해 scaling해줬었으므로 여기서도 해줘야함 scaling 된 데이터를 저장할 곳
scaleData = []

# scaling
for i in range(0, 11):
    scaleData.append((realData[0][i] - mins[i]) / (maxs[i] - mins[i]))
scaleData = [scaleData]
res1 = xgb_model.predict(scaleData)

제일 많은 문제가 되었던 건 xgboost 모델에 2차원의 데이터가 들어가야한다는 점이었다. 계속 [] 배열 안에 데이터를 넣어준 채 모델에 넣어주니 에러가 났다. 하지만 [[]] 안에 2차원 배열 안에 넣어주니 정상적으로 모델이 데이터를 받아들이기 시작했다. 

조건은 내가 위에서 따로 설정해줬으나 데이터는 공개하지 않겠다. 

또한 모델을 학습시킬 때 minmaxScaler를 사용해서 학습을 시켰다. 

이렇게 되면 우리는 새로운 데이터를 모델에 넣어줄 때에도 학습데이터의 변수 별 최대 값 최소값을 알고 있은 뒤 minmaxScaler공식에 의해 변환해준 뒤 모델에 넣어주어야한다.

minmaxScaler 공식 : (값 - 최소값) / (최대 값 - 최소 값)

그 후 값을 한국원 단위로 변환해준다. 

def krw_to_korean_won(arg):
    amount = arg.replace(',', '')
    if int(amount) > 99999999:
        # print amount[0:-8],'억',amount[-8:-4],'만',amount[-4:], '원'
        return '{0}억 {1}만 {2}원'.format(amount[0:-8], amount[-8:-4], amount[-4:])
    elif int(amount) > 9999:
        # print amount[-8:-4],'만',amount[-4:], '원'
        return '{0}만 {1}원'.format(amount[-8:-4], amount[-4:])
    else:
        # print amount[-4:],'원'
        return '{0}원'.format(amount[-4:])

다음 함수를 통해 원 단위로 변환해준다. 

result = round(res1[0] * 10000, -1)
result = int(result)
strresult = str(result)
strresult = krw_to_korean_won(strresult)
st.header("예측 집 값: " + strresult)

다음과 같이 소수점이 없게 반올림을 해준 뒤 int형으로 변환해준다. 다시 string으로 변환해준 뒤 원화 변환 함수를 통과 시킨 후 header메소드를 통해 화면에 찍어주면 다음과 같은 결과가 나온다. 

배포된 주소는 다음과 같다. 

https://incheonhousepriceprediction.streamlit.app/

728x90
반응형

댓글