본문 바로가기
코딩과 알고리즘

파도(16) - 파이스크립트의 특좌앙~점으로 머신러닝!

반응형

🐳 '파도'는 크레이가 도전하고 있는 파이스크립트 도전기의 줄임말입니다.

지난 게시글에서 연재되는 글입니다. : https://itadventure.tistory.com/557

 

파도!(15) - 라쏘회귀와 4차방정식까지

🍿 '파도'는 파이스크립트 도전기의 줄임말입니다. 지난 게시글에서 연재되는 글입니다. : https://itadventure.tistory.com/555 파도!(14) - 릿지 리그레션으로 정확도가 높아진다구? ※ '파도'는 파이스크

itadventure.tistory.com

파이스크립트는 파이썬보다 속도가 느립니다. 로딩속도도 매우 더디고요.
하지만 전혀 아무것도 설치되지 않은 컴퓨터에서 웹브라우저만 있으면 작동이 되지요.

처음에는 자바스크립트 가상머신이 파이썬을 흉내를 내는 줄로 생각 했었는데요.
그게 아니더라구요. 요새 신기술로 분류될 수 있는 웹어셈블리라는 기술이 실제 파이썬을 작동시키는 것입니다.
그것도 내 컴퓨터에서 말이지요. 파이스크립트가 작동하는 것은 웹서버가 아니라 내 컴퓨터이지요.

웹서버는 다른 곳에 있지만 파이스크립트로 머신러닝을 작동시켜 보면 내 컴퓨터의 CPU 사용율이 엄청 올라갑니다.

 

파이썬은 죽지 않는다. 다만 메모리에 떠 있을 뿐이다.


거의 1.5G 가량의 메모리를 점유하고 있는데요. 웹페이지가 모두 뜬 상태에서도 계속 메모리를 차지하고 있습니다. 왜 그럴까요? 그것은 바로 웹브라우저 내 파이썬이 현재 작동하고 있는 상태이기 때문이지요.

그렇기 때문에 한번 떠 있는 파이썬 엔진은 명령을 받으면 바로 작동하도록 대기하고 있으며
웹페이지를 새로 고침하지 않더라도 파이썬 엔진으로 명령만 전달하면 뭔가 새로운 작동을 시도합니다.
놀랍지 않나요? :)

오늘은 그걸 이용해서 릿지리그레션과 라쏘리그레션, 그리고 알파값을 웹 브라우저에서 자유롭게 선택상자를 선택하여 그래프가 어느정도 적중하는지 살펴보려고 합니다.

우선 통쾌(?)하게 소스와 결과물을 이번 게시글에 공개하고 설명은 다음 게시글에서 진행하려고 합니다 :)

 

소스를 공개합니다!

 

이번 파이스크립트 소스는 아래와 같으며 크레이의 홈페이지에서도 결과를 확인하실 수 있습니다.
http://dreamplan7.cafe24.com/pyscript/py11-1.html

<html> 
    <head>
      <title>다항회귀 + 라쏘 리그레션</title>
      <link rel="stylesheet" 
        href="https://pyscript.net/alpha/pyscript.css" /> 
      <script defer 
        src="https://pyscript.net/alpha/pyscript.js"></script> 
<py-env>
  - pandas
  - matplotlib
  - seaborn
  - scikit-learn
  - paths:
    - ./NANUMMYEONGJO.TTF
    - ./NANUMMYEONGJOBOLD.TTF
    - ./common.py
</py-env>
    </head>
  <body> 
    <link rel="stylesheet" href="pytable.css"/>

    알고리즘 선택 :
    <select id="algorithm">
      <option value="">알고리즘을 선택하세요</option>
      <option value="릿지">릿지 회귀 (Ridge Regression)</option>
      <option value="라쏘">라쏘 회귀 (Lasso Regression)</option>
    </select><br/>
    알파값 선택 : 
    <select id="alpha_value">
       <option value="0.001">0.001</option>
       <option value="0.01">0.01</option>
       <option value="0.1">0.1</option>
       <option value="1">1</option>
       <option value="10">10</option>
       <option value="100">100</option>
    </select><br/>
    훈련점수 : <span id="train_score" style=''></span><br/>
    테스트점수 : <span id="test_score" style=''></span><br/>
    
    <div id="graph"></div>
<py-script>
import pandas as pd
from pyodide.http import open_url
from common import *
import numpy as np

from datetime import datetime

# 경고 문구 제거
import warnings
warnings.filterwarnings( 'ignore' )

# 판다스에서 csv 를 데이터 프레임으로 읽어옴
매출데이터 = pd.read_csv(open_url(
  "http://dreamplan7.cafe24.com/pyscript/csv/avocado.csv"
))      

# 3개 필드만 추려서 데이터 프레임을 다시 만듬
매출데이터 = 매출데이터[[
  'Date', 
  'Total Volume',
  'AveragePrice'
]]   

# 영문 제목을 한글로 변경
매출데이터.columns = [
  '날짜', 
  '매출량',
  '평균가격'
]

주간매출_매출량=매출데이터.fillna(0) \
  .groupby('날짜', as_index=False)[['매출량']].sum() \
  .sort_values(by='날짜', ascending=True)
  
주간매출_평균가=매출데이터.fillna(0) \
  .groupby('날짜', as_index=False)[['평균가격']].mean() \
  .sort_values(by='날짜', ascending=True)

주간매출데이터=pd.merge(주간매출_매출량, 주간매출_평균가, on='날짜')

# 날짜(시간값) 추가
주간매출데이터.insert(1, '날짜(시간값)',
  '',
  True)
  
for i in 주간매출데이터['날짜'].index:
  주간매출데이터['날짜(시간값)'].loc[i]=time.mktime(
    datetime.strptime(
      주간매출데이터['날짜'].loc[i], 
      '%Y-%m-%d'
    ).timetuple()
  )

# 10000으로 나눈 매출량 필드 추가
주간매출데이터.insert(3, '매출량(만)', 
  주간매출데이터['매출량']/10000, 
  True)

# 훈련학습용으로 날짜를 연도, 월, 일로 나눈다
주간매출데이터.insert(4, '연도', '', True)
주간매출데이터.insert(5, '월', '', True)
주간매출데이터.insert(6, '일', '', True)
주간매출데이터.insert(7, '주', '', True)

for i in 주간매출데이터['날짜'].index:
  임시=str(주간매출데이터['날짜'].loc[i]).split('-')
  연도=int(임시[0])
  월=int(임시[1])
  일=int(임시[2])
  주간매출데이터['연도'].loc[i]=연도
  주간매출데이터['월'].loc[i]=월
  주간매출데이터['일'].loc[i]=일
  주간매출데이터['주'].loc[i]=str(
    datetime(연도, 월, 일).isocalendar()[1]
  )

createElementDiv(
  document, 
  Element, 
  'output2'
).write(주간매출데이터)

주간매출데이터훈련_넘파이 = 주간매출데이터[['날짜(시간값)', '연도', '월', '일', '평균가격']].to_numpy()
주간매출데이터목표_넘파이 = 주간매출데이터['매출량(만)'].to_numpy()
주간매출데이터날짜_넘파이 = 주간매출데이터['날짜'].to_numpy()

from sklearn.model_selection import train_test_split

훈련용데이터, 테스트데이터, 훈련용목표, 테스트목표 = \
  train_test_split(
    주간매출데이터훈련_넘파이, 
    주간매출데이터목표_넘파이,
    random_state=100,
    shuffle=False)

from sklearn.preprocessing import PolynomialFeatures
폴리 = PolynomialFeatures(degree=4, include_bias=False) # 절편 속성은 제거
폴리.fit(훈련용데이터) # 특성을 다항으로 자동으로 불림
#print(폴리.get_feature_names_out())
훈련용데이터_가공 = 폴리.transform(훈련용데이터) # 학습에 추가된 파라미터에 맞게 다항 변환
테스트데이터_가공 = 폴리.transform(테스트데이터) # 테스트 세트도 다항 변환, fit했던 훈련 poly 를 사용.

#=====================================
from sklearn.preprocessing import StandardScaler
스케일러 = StandardScaler()
스케일러.fit(훈련용데이터_가공)
훈련용데이터_가공 = 스케일러.transform(훈련용데이터_가공)
테스트데이터_가공 = 스케일러.transform(테스트데이터_가공)

from sklearn.linear_model import Ridge
from sklearn.linear_model import Lasso

#=====================================

import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import matplotlib as mat

# 기준 폰트 변경 : legend 의 한글을 적용하려면 필수
fm.fontManager.addfont('./NANUMMYEONGJO.TTF') #  폰트명 : NanumMyeongjo
mat.rc('font', family='NanumMyeongjo')

###################
# 폰트 목록 출력 ( 폰트 추가 후 정확한 이름을 확인하려면 필요
#font_list = [font.name for font in fm.fontManager.ttflist]
#for f in font_list:
#  print(f)      
###################        

# 개별 폰트 적용
NanumMyengjo = fm.FontProperties(
  fname='./NANUMMYEONGJO.TTF'
)
NanumMyengjoBold = fm.FontProperties(
  fname='./NANUMMYEONGJOBOLD.TTF'
)

# 자바스크립트와 통신
from js import document
from pyodide import create_proxy

def 그래프함수(event):

  알고리즘 = document.getElementById("algorithm").value
  알파값 = float(document.getElementById("alpha_value").value)
    
  if 알고리즘=='릿지':
    #=====================================
    # 릿지모델
    릿지모델 = Ridge(alpha=알파값)
    릿지모델.fit(훈련용데이터_가공, 훈련용목표)

    훈련점수=릿지모델.score(훈련용데이터_가공, 훈련용목표)
    테스트점수=릿지모델.score(테스트데이터_가공, 테스트목표)
    document.getElementById("train_score").innerHTML=훈련점수
    document.getElementById("test_score").innerHTML=테스트점수

    훈련용목표예측 = 릿지모델.predict(훈련용데이터_가공)
    테스트목표예측 = 릿지모델.predict(테스트데이터_가공)
  else:
    #=====================================
    # 라쏘모델
    라쏘모델 = Lasso(alpha=알파값)
    라쏘모델.fit(훈련용데이터_가공, 훈련용목표)
    
    훈련점수=라쏘모델.score(훈련용데이터_가공, 훈련용목표)
    테스트점수=라쏘모델.score(테스트데이터_가공, 테스트목표)
    document.getElementById("train_score").innerHTML=훈련점수
    document.getElementById("test_score").innerHTML=테스트점수

    훈련용목표예측 = 라쏘모델.predict(훈련용데이터_가공)
    테스트목표예측 = 라쏘모델.predict(테스트데이터_가공)

  # 그래프
  fig = plt.figure(
    figsize=(15, 7)
  )
  # 주위 이상한 여백 없애기
  fig.tight_layout() 
  
  plt.title('주간 아보카도 매출량(' + 알고리즘 + ')',
    fontproperties=NanumMyengjoBold, 
    fontsize=32
  );

  # 원본
  plt.plot(        
    훈련용데이터[:,0],
    훈련용목표,
    #marker='o',
    color='gray',
    label='원본'
  )
  plt.plot(        
    테스트데이터[:, 0],
    테스트목표,
    #marker='o',
    color='gray'
  )

  # 훈련
  plt.plot(        
    훈련용데이터[:,0],
    훈련용목표예측,
    marker='d',
    color='blue',
    label='훈련패턴'
  )
  
  # 예측
  plt.plot(        
    테스트데이터[:, 0],
    테스트목표예측,
    marker='*',
    color='green',
    label='예측패턴'
  )

  plt.legend(
    shadow=True
  )

  plt.xticks(
    주간매출데이터훈련_넘파이[:, 0],
    주간매출데이터날짜_넘파이, 
    rotation=90, fontsize=8)

  plt.xlabel('날짜', fontsize=16)
  plt.ylabel('매출량(단위:만)', fontsize=12)

  ax = plt.gca()
  # 축만 그리드
  ax.xaxis.grid(True)

  # 배경색, 마진 조정
  ax.set_facecolor('#e8e7d2')
  ax.margins(x=0.01, y=0.02)
  pyscript.write("graph",fig)

e1 = document.getElementById("algorithm")
e1.addEventListener("change", create_proxy(그래프함수))  

e2 = document.getElementById("alpha_value")
e2.addEventListener("change", create_proxy(그래프함수))  

</py-script> 
  </body> 
</html>


평소처럼 상당한 로딩시간이 소요된 다음에 뭔가 좀 화면이 다르게 보이실텐데요.
바로 그래프가 나오는 대신 뭔가 선택할 수 있는 선택상자가 2개가 보이실 겁니다.

첫번째 선택상자는 알고리즘 종류를 선택하는 상자인데요.
마우스로 클릭하면 2개의 선택항목이 보이실 겁니다.

 

라쏘 회귀를 선택해볼까요?
앗 그러자 1.5초 있다 그래프가 떴습니다 ( 독자 여러분의 컴퓨터 사양에 따라 시간은 차이가 날 수 있습니다 )
훈련점수와 테스트 점수도 함께 표시되었군요. 적중율은 그리 높지 않은데요. 그것은 알파값이 낮아서입니다.

하지만 이제 알파값도 선택상자로 선택할 수 있습니다.
알파값 선택상자를 클릭하면 0.001 부터 100까지 중 선택할 수 있는데요.

하나씩 골라서 살펴보면 점점 적중도와 그래프가 변화하는 것을 보실 수 있습니다.
반응속도는 1초~ 1.5초 소요되는데 저보다 컴퓨터가 좋은 분은 더 빠른 응답 속도를 보이실 겁니다.
알파값 교정이나 알고리즘 선택을 단순히 선택하는 것만으로 머신러닝 결과를 볼 수 있다는 것이
바로 파이스크립트의 특장점입니다.

마무~리

 

이렇게 웹 브라우저 내에 떠 있는 파이썬과 소통하는 기술을 파이스크립트에서는 '프록시'라고 하는데요.
다음 시간에는 작동원리를 설명드리도록 하겠습니다 :)


아무쪼록 필요하신 분께 도움이 되셨을지요 :)
방문해주시는 모든 분들께 늘 감사드립니다.

유익하셨다면 공감  한방, 댓글은 굿잡!
감사합니다~


다음게시글 : https://itadventure.tistory.com/559

 

파도(17) - 자바스크립트와 파이스크립트, 손잡다!

🍬 '파도'는 크레이의 파이스크립트 도전기의 줄임말입니다. 지난 게시글에서 연재되는 글입니다. https://itadventure.tistory.com/558 파도(16) - 파이스크립트의 특좌앙~점으로 머신러닝! 🐳 '파도'는

itadventure.tistory.com

 

반응형