Python/실습

[Python Streamlit] IRIS 데이터를 활용한 머신러닝 대시보드 개발

CocoJamjam 2023. 4. 25. 15:46
728x90
반응형

Python을 공부하면서 배운 것들을 활용하여 머신러닝 대시보드를 개발해 보는 실습을 해보자.

이번 실습은 Pycharm (Python 3.9)에서 진행하였다.

목차

1. 사용한 모듈

2. 구상하기

3. Main 페이지가 될 app.py 파일 생성

4. Main 페이지에 들어갈 내용 만들기

5. EDA (탐색적 자료분석) 메뉴

6. ML(머신러닝) 학습 모델 생성

7. ML(머신러닝) 메뉴

8. 모든 페이지를 Main 페이지에 적용하기

9. 실습을 마치며


1. 사용한 모듈

  • Matplotlib과 Seaborn, Plotly를 이용하여 시각화
  • Streamlit을 활용한 웹 배포
  • Scikit-Learn을 활용한 머신러닝 모델 생성
  • 그 외 pandas, joblib, os, numpy 활용

2. 구상하기

Streamlit을 통해 웹 배포를 할 것이기 때문에 어떻게 페이지를 만들 것인지 구상을 먼저 해보자.

  • 우선 IRIS 데이터에 대한 기초정보, 통계분석, 산점도 등이 들어가야겠다.
  • 사이드 바 생성을 통해 메뉴를 만들 생각이다.
  • 메뉴로는 HOME, EDA, ML, ABOUT을 만들어보자.
  • 그 외 자세한 것은 만들면서 생각해 보자.

자 그럼 실습을 시작할 차례!

2. 폴더 생성 및 데이터 넣기

  • Streamlit 폴더에 IRIS데이터와 생성할 머신러닝 모델을 저장할  data 폴더와 model 폴더를 생성한다.
  • data폴더 에는 실습에 필요한 iris.csv 파일을 넣어둔다. ( 데이터 다운로드 링크 - 출처 : Kaggle)
  • 데이터 확인

실습에 사용할 IRIS 데이터

3. Main 페이지가 될 app.py 파일 생성

  • 이제 메인 페이지를 만들어 보자.
  • 메인 페이지 구상
    • 사이드 바 생성을 통한 메뉴 생성
    • 프로젝트 설명, 프로젝트 목표, 데이터 출처 소개
  • 메뉴에는 HOME, EDA, ML, ABOUT 생성
# -*- coding:utf-8 -*-
import streamlit as st					# streamlit 모듈 import

def main():						# 메인 페이지 함수 생성
    st.subheader("Choi's ML Project")			# 페이지 SubHeader 생성

    menu = ['HOME', 'EDA', 'ML', 'About']		# 메뉴에 들어갈 목록 작성
    choice = st.sidebar.selectbox("Menu", menu)		# 사이드 바에 SelectBox 생성

    if choice == 'HOME':				# HOME 페이지
        st.subheader('HOME')

    elif choice == 'EDA':				# EDA 페이지
        st.subheader('탐색적 자료 분석(EDA)')
        pass
    elif choice == 'ML':				# ML 페이지
        st.subheader('머신러닝(ML)')
        pass
    else:						# ABOUT 페이지
        st.subheader('About')


if __name__ == "__main__":				# 메인 페이지 실행
    main()

초기 Main 페이지

4. Main 페이지에 들어갈 내용 만들기

  • utils.py를 만들어 메인 페이지에 들어갈 설명 작성
  • app.py에서 utils.py 내용 import 시키기
# utils.py
# -*- coding:UTF-8 -*-
p_lans = ['Python', 'Julia', 'Go', 'Rust']

html_temp = """
<style type="text/css">
.tg  {border-collapse:collapse;border-spacing:0;}
.tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
  overflow:hidden;padding:10px 5px;word-break:normal;}
.tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
  font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
.tg .tg-0lax{text-align:left;vertical-align:top}
</style>
<table class="tg">
<thead>
  <tr>
    <th class="tg-0lax">강의명</th>
    <th class="tg-0lax">AI 플랫폼을 활용한 빅데이터 분석 전문가</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td class="tg-0lax">교과목명</td>
    <td class="tg-0lax">기초문법</td>
  </tr>
  <tr>
    <td class="tg-0lax">프로젝트 주제</td>
    <td class="tg-0lax">파이썬 Streamlit 라이브러리를 활용한 IRIS 데이터 머신러닝 대시보드 개발</td>
  </tr>
  <tr>
    <td class="tg-0lax">프로젝트 마감일</td>
    <td class="tg-0lax">2023년 5월 15일</td>
  </tr>
  <tr>
    <td class="tg-0lax">이름</td>
    <td class="tg-0lax">최재명</td>
  </tr>
</tbody>
</table>
"""

dec_temp ="""
### IRIS 예측 모델 개발
- IRIS 데이터를 활용하여 간단한 EDA 및 예측 모델을 구현한다. 
#### 데이터
    + https://www.kaggle.com/datasets/saurabh00007/iriscsv
"""
# -*- coding:utf-8 -*-
import streamlit as st
from utils import html_temp					# utlis.py의 내용 import
from utils import dec_temp

def main():
    st.subheader("Choi's ML Project")
    st.markdown(html_temp, unsafe_allow_html=True)		# main에 표 적용

    menu = ['HOME', 'EDA', 'ML', 'About']
    choice = st.sidebar.selectbox("Menu", menu)

    if choice == 'HOME':
        st.subheader('HOME')
        st.markdown(dec_temp, unsafe_allow_html=True)		# HOME 탭에 내용 적용
    elif choice == 'EDA':
        st.subheader('탐색적 자료 분석(EDA)')
        pass
    elif choice == 'ML':
        st.subheader('머신러닝(ML)')
        pass
    else:
        st.subheader('About')


if __name__ == "__main__":
    main()

Main 페이지 내용 추가

메인 페이지가 갖춰졌다.

 

5. EDA (탐색적 자료분석) 메뉴

  • eda_app.py 파일 생성
  • EDA에 들어갈 내용 확인
    • 데이터 확인 (데이터 출력)
    • 데이터 Type 확인
    • 기초 통계량 (개수, 평균, 분산, 표준편차, 사분위수 등)
    • Target 빈도수( 종별 개수 ) 확인
    • Matplotlib, Seaborn을 활용한 시각화
    • Plotly를 활용한 시각화
# eda_app.py
# -*- coding:utf-8 -*-
# 라이브러리 import
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import utils

def run_eda_app():						# run_eda_app() 함수 생성
    st.subheader("탐색적 자료 분석")

    iris = pd.read_csv('data/iris.csv')				# 데이터 불러오기
    st.markdown('## IRIS 데이터 확인')
    st.write(iris)						# 데이터 확인하기

    # 메뉴 지정
    # 사이드 바에 하위메뉴 생성
    submenu = st.sidebar.selectbox('하위메뉴', ['기술통계량', '그래프분석', '통계분석'])	
    if submenu == '기술통계량':					# 기술 통계량 메뉴 내용
        st.dataframe(iris)
        with st.expander('데이터 타입'):
            result1 = pd.DataFrame(iris.dtypes)			# 데이터 타입 확인
            st.write(result1)
        with st.expander("기초 통계량"):				# 기초 통계량 확인
            result2 = iris.describe()
            st.write(result2)
        with st.expander("Target 빈도 수 확인"):			# 각 종별 개수 확인
            st.write(iris['species'].value_counts())
    elif submenu == '그래프분석':				# 그래프 메뉴 내용
        st.title("Title")
        with st.expander('산점도'):			
            fig1 = px.scatter(iris,
                             x = 'sepal_width',
                             y = 'sepal_length',
                             color = 'species',
                             size = 'petal_width',
                             hover_data = ['petal_length'])	# Plotly 산점도 생성
            st.plotly_chart(fig1)				# 산점도 출력

        # layouts 나누기
        col1, col2 = st.columns(2)
        with col1:
            st.title('Seaborn')
            fig, ax=plt.subplots()
            # Seaborn 활용 상자그래프 작성
            ax=sns.boxplot(iris,
                           x = 'sepal_width',
                           y = 'sepal_length',
                           ax=ax)
            st.pyplot(fig)

        with col2:
            st.title('Matplotlib')
            # Matplotlib 활용 히스토그램 작성
            fig, ax=plt.subplots()
            ax.hist(iris['sepal_length'], color='green')
            st.pyplot(fig)

        # Tabs
        # iris의 종별 산점도 그래프 탭 만들기
        # Plotly 사용
        # 종 선택할 때마다 산점도 그래프가 달라지도록 함
        tab1, tab2, tab3, tab4, tab5 = st.tabs(['Select','Setosa', 'Versicolor', 'Virginica', 'Kaggle'])
        with tab1:
            with tab1:
                choice0 = st.selectbox('iris 데이터', iris['species'].unique())
                result0 = iris[iris['species'] == choice0]

                st.title('plotly')
                # 그래프 작성
                fig0 = px.scatter(result0
                                  , x='sepal_width'
                                  , y='sepal_length'
                                  , size='sepal_width'
                                  , hover_data=['sepal_length'])
                st.plotly_chart(fig0)
        with tab2:
            st.write('Setosa')
            choice1 = iris['species'].unique()[0]
            result3 = iris[iris['species'] == choice1]
            fig2 = px.scatter(result3,
                             x = 'sepal_width',
                             y = 'sepal_length')
            st.plotly_chart(fig2)

        with tab3:
            st.write('Versicolor')
            choice2 = iris['species'].unique()[1]
            result4 = iris[iris['species'] == choice2]
            fig3 = px.scatter(result4,
                             x = 'sepal_width',
                             y = 'sepal_length')
            st.plotly_chart(fig3)

        with tab4:
            st.write('Virginica')
            choice3 = iris['species'].unique()[2]
            result5 = iris[iris['species'] == choice3]
            fig4 = px.scatter(result5,
                             x = 'sepal_width',
                             y = 'sepal_length')
            st.plotly_chart(fig4)

        with tab5:
            pass

    elif submenu == '통계분석':
        pass
    else:
        st.warning("뭔가 없어요!")

EDA - 기술통계량 일부분
EDA - 그래프 일부분

6. ML(머신러닝) 학습 모델 생성

  • model.py 파일 생성
  • ML 학습 모델 생성
    • sklearn 패키지 활용
    • Logistic 회귀분석을 활용한 ML 학습 모델 생성
    • joblib를 활용한 모델 저장
# model.py
# -*- coding:utf-8 -*-
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

import joblib # 모델 저장 또는 불러올 때

data = pd.read_csv("data/iris.csv")
le = LabelEncoder()
print(le.fit(data['species']))
data['species'] = le.fit_transform(data['species'])
print(le.classes_) # ['Iris-setosa' 'Iris-versicolor' 'Iris-virginica']

X = data.drop(columns = ['species'])
y = data['species']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25)

model = LogisticRegression()
model.fit(X_train, y_train)

# 모델 만들고 배포 (Export)
model_file = open("models/logistic_regression_model_iris_230425.pkl","wb")
joblib.dump(model, model_file)
model_file.close()

models 폴더에 생성된 회귀분석 학습 모델

7. ML(머신러닝) 메뉴

  • ML 내용이 들어간 ml_app.py 파일생성
  • ML에 들어갈 내용 확인
    • ML 학습 모델 불러오기 및 적용
    • 슬라이더를 활용한 임의 데이터 입력
    • 입력된 임의 데이터로 예측한 결과값 출력
# ml_app.py
# -*-coding: utf-8 -*-
import streamlit as st
import joblib
import os
import numpy as np

def run_ml_app():
    st.title("머신러닝 페이지")
    col1, col2 = st.columns(2)
    with col1:        # 슬라이더를 통한 각 Feature별 임의 데이터 입력
        st.subheader("수치를 입력해주세요.")
        

        sepal_length = st.select_slider("Sepal Length", options=np.arange(1, 11))
        sepal_width = st.select_slider("Sepal Width", options=np.arange(1, 11))
        petal_length = st.select_slider("Petal Length", options=np.arange(1, 11))
        petal_width = st.select_slider("Petal Width", options=np.arange(1, 11))

        sample = [sepal_length, sepal_width, petal_length, petal_width]
        st.write(sample)

    with col2:		# 모델 예측값 출력
        st.subheader("모델 결과를 확인해주세요!")
        new_df = np.array(sample).reshape(1, -1)
        st.write(new_df.shape, new_df.ndim)
        
        # 모델 불러오기
        MODEL_PATH = 'models/logistic_regression_model_iris_230425.pkl'
        model = joblib.load(open(os.path.join(MODEL_PATH), 'rb'))
        
        
        # 예측값 출력 탭
        prediction = model.predict(new_df)
        pred_prob = model.predict_proba(new_df)
        st.write(prediction)
        st.write(pred_prob)

        if prediction == 0:
            st.success("Setosa 종입니다. ")
            pred_proba_scores = {"Setosa 확률": pred_prob[0][0] * 100,
                                 "Versicolor 확률": pred_prob[0][1] * 100,
                                 "Virginica 확률": pred_prob[0][2] * 100}
            st.write(pred_proba_scores)
            st.image('https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/Irissetosa1.jpg/220px-Irissetosa1.jpg')

        elif prediction == 1:
            st.success("Versicolor 종입니다.")
            pred_proba_scores = {"Setosa 확률": pred_prob[0][0] * 100,
                                 "Versicolor 확률": pred_prob[0][1] * 100,
                                 "Virginica 확률": pred_prob[0][2] * 100}
            st.write(pred_proba_scores)
            st.image(
                'https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/Blue_Flag%2C_Ottawa.jpg/220px-Blue_Flag%2C_Ottawa.jpg')

        elif prediction == 2:
            st.success("Virginica 종입니다.")
            pred_proba_scores = {"Setosa 확률": pred_prob[0][0] * 100,
                                 "Versicolor 확률": pred_prob[0][1] * 100,
                                 "Virginica 확률": pred_prob[0][2] * 100}
            st.write(pred_proba_scores)
            st.image(
                'https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Iris_virginica_2.jpg/220px-Iris_virginica_2.jpg')
        else:
            st.warning("판별 불가")

ML 페이지

8. 모든 페이지를 Main 페이지에 적용하기

  • app.py에서 모든 페이지 내용 import 시키기
    • eda_app.py
    • ml_app.py
# -*- coding:utf-8 -*-
import streamlit as st
from utils import html_temp
from utils import dec_temp
from eda_app import run_eda_app
from ml_app import run_ml_app
def main():
    st.subheader("Choi's ML Project")
    st.markdown(html_temp, unsafe_allow_html=True)

    menu = ['HOME', 'EDA', 'ML', 'About']
    choice = st.sidebar.selectbox("Menu", menu)

    if choice == 'HOME':
        st.subheader('HOME')
        st.markdown(dec_temp, unsafe_allow_html=True)
    elif choice == 'EDA':
        run_eda_app()
    elif choice == 'ML':
        run_ml_app()
    else:
        st.subheader('About')


if __name__ == "__main__":
    main()

완성한 Streamlit 배포 페이지

9. 실습을 마치며

Streamlit을 통해 Python 작업 내용을 쉽게 배포할 수 있게 되었다.

앞으로도 여러 가지 시각화 및 머신러닝 작업 후에 배포까지 해보도록 하겠다.

728x90
반응형