Python {Article077}

ようこそ「Python」へ...

PyScriptで機械学習を使って好みの音楽ジャンルを予測するには

この記事では、PyScriptで機械学習(Machine Learning: Scikit-Learn)を使って男女の好みの音楽ジャンルを予測する方法を解説しています。 Webページから「性別」と「年齢」を入力して[予測]ボタンをクリックするとその人の好みの音楽ジャンルを予測して表示します。 まずは、「GO LIVE DEMO」をクリックして「Live DEMO」をご覧ください。

Visual Studio Code(VSC)からHTMLファイルをブラウザに表示するには「Live Serer」を使用します。 「Live Server」のインストール手順は「記事(Article073)」で解説しています。

説明文の左側に図の画像が表示されていますが縮小されています。 画像を拡大するにはマウスを画像上に移動してクリックします。 画像が拡大表示されます。拡大された画像を閉じるには右上の[X]をクリックします。 画像の任意の場所をクリックして閉じることもできます。

click image to zoom!
図A: PyScript DEMO #1
click image to zoom!
図B: PyScript DEMO #2
click image to zoom!
図C: PyScript DEMO #3
click image to zoom!
図D: PyScript DEMO #4


機械学習で性別と年齢から好みの音楽ジャンルを予測する

  1. 新規HTMLファイルを作成してCSSを追加する

    Visual Studio Code(VSC)を起動したら新規HTMLファイルを作成します。 HTMLファイルが表示されたら「!」を入力してポップアップリストから「先頭行」クリックします。 HTMLのテンプレートが表示されたら行7のtitleを書き換えます。 次に行8-22を入力してCSSを追加します。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Using machine learning to predict music genres with PyScript</title>
        <style>      
            body {
              margin: 5% 5% !important;
            }
            .p_article077 {
              font-size: smaller; 
            }
            .span_article077 {
              font-size: smaller;
            }
            .div_article077 {
              width: 85%; 
              margin: 20px auto;
            }         
        </style>  
     
    </head>
    <body>
    
    </body>
    </html>

  2. headセクションにlink, scriptを追加してPyScriptのCSS, JavaScriptライブラリを取り込む

    headセクションに行23-31を追加します。 行24ではBootstrapのCSSを取り込んでいます。 行25ではPyScriptのCSSを取り込んでいます。 行26ではPyScriptのJavScriptのライブラリを取り込んでいます。 行27-31ではPythonのライブラリを宣言しています。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Using machine learning to predict music genres with PyScript</title>
        <style>      
            body {
              margin: 5% 5% !important;
            }
            .p_article077 {
              font-size: smaller; 
            }
            .span_article077 {
              font-size: smaller;
            }
            .div_article077 {
              width: 85%; 
              margin: 20px auto;
            }         
        </style>  
        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css">           
        <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
        <script defer src="https://pyscript.net/alpha/pyscript.js"></script>        
        <py-env>
          - numpy
          - pandas
          - scikit-learn
        </py-env>     
    </head>
    <body>
    
    </body>
    </html>

  3. bodyセクションにHTMLのh1, div, span, label, input等の要素を配置する

    bodyセクションにdiv, h1, p, label, input等の要素を追加して配置します。 行14-21では機械学習用のパラメータを入力させるためのHTML要素を配置しています。 行24-44では好みの音楽ジャンルを予測する人の条件(性別、年齢)を入力させるためのHTML要素を配置しています。 行47-54では各種ボタンを配置しています。 行57-59では各種ボタンをクリックしたときの結果を表示するためのHTML要素を配置しています。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        :::
    </head>
    <body>
        <!-- Heading Content -->
        <div>
            <h1>Using machine learning to predict music genres with PyScript 🐍</h1>
            <p class="p_article077">(ここでは性別・年齢を選択して好みの音楽のジャンルを予測します)</p>
        </div>
    
        <!-- Training Parameters -->
        <div class="div_article077">
          <!-- Choose Test Split -->
          <div class="form-group">
            <label for="test_split">Choose Test Split: <span class="span_article077">(分割するテスト用データの割合)</span> </label>
            <input type="number" class="form-control" id="test_split" aria-describedby="testSplitHelp" value="0.25">
            <small id="testSplitHelp" class="form-text text-muted">Answer between 0 to 1.</small>
          </div>
        </div>
    
        <!-- Gender / Age Parameters -->
        <div class="div_article077">
          <h2>Choose gender to predict: <span class="span_article077">(予測する人の性別)</span></h2>
          <!-- radio button list -->               
          <div class="row ml-1">                    
            <div class="form-check col-lg-6">
                <input class="form-check-input" type="radio" name="genderSelection" id="male_gender" value="1" checked>
                <label class="form-check-label" for="male_gender">Male(男性)</label>
            </div>
            <div class="form-check col-lg-6">  
                <input class="form-check-input" type="radio" name="genderSelection" id="female_gender" value="0">
                <label class="form-check-label" for="female_gender">Female(女性)</label>
            </div>
          </div>
    
          <!-- Choose Age -->
          <div class="form-group">
            <label for="age">Choose age to predict: <span class="span_article077">(予測する人の年齢)</span> </label>
            <input type="number" class="form-control" id="age" aria-describedby="ageHelp" value="21">
            <small id="ageHelp" class="form-text text-muted">Answer age to predict.</small>
          </div>  
        </div>
        
        <!-- Buttons -->
        <div class="div_article077">
          <div class="form-group">
            <button id="import" class="btn btn-primary mt-2"  pys-onClick="import_data">Import Data</button>
            <button id="train" class="btn btn-primary mt-2"  pys-onClick="train_model">Train Model</button>
            <button id="predict" class="btn btn-primary mt-2"  pys-onClick="predict">Predict</button>
            <button id="score" class="btn btn-primary mt-2"  pys-onClick="calculate_accuracy">Calculate Accuracy</button>   
          </div>
        </div>
    
        <hr />
        <div class="div_article077">
          <div id="output"></div>
        </div>
    
    </body>
    </html>

  4. bodyセクションにpy-scriptを追加してPythonのコードを追加する

    bodyセクションに<py-script>...</py-script>を追加してPythonのコードを記述します。 行63-71ではPythonのライブラリを取り込んでいます。 行72ではPythonの警告メッセージを抑止しています。 行75-76ではglobal変数を定義しています。

    行78-86では関数「import_data()」を定義しています。 この関数ではCSVファイルのURLを指定して音楽のデータ「music.csv」をダウンロードしています。 行83ではPandasのread_csv()でCSVファイルを取り込んでDataFrameに格納しています。 URL指定のCSVファイルを取り込むときはpyodide.httpのopen_url()メソッドを使用して事前にロードしておく必要があります。 CSVファイル「music.csv」のレイアウトは図1を参照してください。

    行88-96では関数「train_model()」を定義しています。 行90-92では音楽データを機械学習用に加工しています。 行94ではDecisionTreeClassifierのモデルを使用して学習させています。 変数xには年齢(age)と性別(gender)のDataFrameが格納されています。 変数yには音楽のジャンル(genre)のDataFrameが格納されています。

    行98-106では関数「predict()」を定義しています。 行100ではHTMLのラジオボタンから性別を取得しています。 行102ではHTMLのテキストボックスから年齢を取得しています。 行104ではmodelのpredict()メソッドで音楽のジャンルを予測しています。 行106では予測結果をWebページに表示しています。

    行108-122では関数「calculate_accuracy()」を定義しています。 行120では予測結果から予測のスコアを取得しています。 行122では予測スコアをWebページに表示しています。スコアは1が満点(予測率100%という意味)です。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        :::    
    </head>
    <body>
        <!-- Heading Content -->
        <div>
            <h1>Using machine learning to predict music genres with PyScript 🐍</h1>
            <p class="p_article077">(ここでは性別・年齢を選択して好みの音楽のジャンルを予測します)</p>
        </div>
    
        <!-- Training Parameters -->
        <div class="div_article077">
          <!-- Choose Test Split -->
          <div class="form-group">
            <label for="test_split">Choose Test Split: <span class="span_article077">(分割するテスト用データの割合)</span> </label>
            <input type="number" class="form-control" id="test_split" aria-describedby="testSplitHelp" value="0.25">
            <small id="testSplitHelp" class="form-text text-muted">Answer between 0 to 1.</small>
          </div>
        </div>
    
        <!-- Gender / Age Parameters -->
        <div class="div_article077">
          <h2>Choose gender to predict: <span class="span_article077">(予測する人の性別)</span></h2>
          <!-- radio button list -->               
          <div class="row ml-1">                    
            <div class="form-check col-lg-6">
                <input class="form-check-input" type="radio" name="genderSelection" id="male_gender" value="1" checked>
                <label class="form-check-label" for="male_gender">Male(男性)</label>
            </div>
            <div class="form-check col-lg-6">  
                <input class="form-check-input" type="radio" name="genderSelection" id="female_gender" value="0">
                <label class="form-check-label" for="female_gender">Female(女性)</label>
            </div>
          </div>
    
          <!-- Choose Age -->
          <div class="form-group">
            <label for="age">Choose age to predict: <span class="span_article077">(予測する人の年齢)</span> </label>
            <input type="number" class="form-control" id="age" aria-describedby="ageHelp" value="21">
            <small id="ageHelp" class="form-text text-muted">Answer age to predict.</small>
          </div>  
        </div>
        
        <!-- Buttons -->
        <div class="div_article077">
          <div class="form-group">
            <button id="import" class="btn btn-primary mt-2"  pys-onClick="import_data">Import Data</button>
            <button id="train" class="btn btn-primary mt-2"  pys-onClick="train_model">Train Model</button>
            <button id="predict" class="btn btn-primary mt-2"  pys-onClick="predict">Predict</button>
            <button id="score" class="btn btn-primary mt-2"  pys-onClick="calculate_accuracy">Calculate Accuracy</button>   
          </div>
        </div>
    
        <hr />
        <div class="div_article077">
          <div id="output"></div>
        </div>
    
        <py-script>
    # import python libraries      
    import pandas as pd
    from pyodide.http import open_url
    
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import accuracy_score
    import joblib   
    from sklearn import tree
    import warnings
    warnings.simplefilter('ignore')
    
    # define global variables
    music_data = pd.DataFrame()
    model = DecisionTreeClassifier()
    
    def import_data(*args, **kwargs):
        # Import the data      
        global music_data      
        csv_file = 'https://raw.githubusercontent.com/akio-ak-kasai/pyscript_tutorial_001/main/music.csv'
        url_content = open_url(csv_file)
        df = pd.read_csv(url_content)
        console.warn(f'df.shape: {df.shape}')
        music_data = df
        pyscript.write('output', f'import_data(): df.shape {df.shape}')  
    
    def train_model(*args, **kwargs):  
        # Prepare the data
        df = music_data
        x = df.drop(columns=['genre'])  # age, gender
        y = df['genre'] # genre
        # Train the Model
        model.fit(x, y)
        console.warn('model.fit(x, y) done!')
        pyscript.write('output', f'train_model(): done!')  
    
    def predict(*args, **kwargs):  
        # Make Predictions
        gender = int(document.querySelector('input[name="genderSelection"]:checked').value); # 1-Male, 0-Female  
        console.warn(f'gender= {gender}')
        age = int(document.getElementById("age").value)
        console.warn(f'age= {age}')
        predections = model.predict([[age, gender]]) 
        console.warn(f'predections: {predections[0]}')
        pyscript.write('output', f'predict(): {predections[0]}')
    
    def calculate_accuracy(*args, **kwargs):
        # Calculating the Accuracy
        test_split = float(document.getElementById("test_split").value) 
        console.warn(f'test_split= {test_split:.2f}')
        df = music_data  
        x = df.drop(columns=['genre'])  
        y = df['genre'] 
        x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=test_split)
        console.warn(f'len(x_train): {len(x_train)}, len(y_train): {len(y_train)}')
        console.warn(f'len(x_test): {len(x_test)}, len(y_test): {len(y_test)}')
        model.fit(x_train, y_train)
        predections = model.predict(x_test) 
        score = accuracy_score(y_test, predections)
        console.warn(f'score: {score}')
        pyscript.write('output', f'calculate_accuracy(): score= {score}')
        </py-script>
    
    </body>
    </html>

    click image to zoom!
    図1: music.csv
    music.csvファイルには音楽データが18件格納されています。 各レコードは年齢(age)、性別(gender)、ジャンル(genre)の列から構成されています。 性別は男性が「1」、女性が「0」となっています。 ちなみにこのCSVファイルは「github.com」にアップロードされています。
  5. HTMLファイルのすべてを掲載

    最後にここで解説したHTMLファイルのすべてを掲載しましたので参考にしてください。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Using machine learning to predict music genres with PyScript</title>
        <style>      
            body {
              margin: 5% 5% !important;
            }
            .p_article077 {
              font-size: smaller; 
            }
            .span_article077 {
              font-size: smaller;
            }
            .div_article077 {
              width: 85%; 
              margin: 20px auto;
            }         
        </style>  
        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css">           
        <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
        <script defer src="https://pyscript.net/alpha/pyscript.js"></script>        
        <py-env>
          - numpy
          - pandas
          - scikit-learn
        </py-env>     
    </head>
    <body>
        <!-- Heading Content -->
        <div>
            <h1>Using machine learning to predict music genres with PyScript 🐍</h1>
            <p class="p_article077">(ここでは性別・年齢を選択して好みの音楽のジャンルを予測します)</p>
        </div>
    
        <!-- Training Parameters -->
        <div class="div_article077">
          <!-- Choose Test Split -->
          <div class="form-group">
            <label for="test_split">Choose Test Split: <span class="span_article077">(分割するテスト用データの割合)</span> </label>
            <input type="number" class="form-control" id="test_split" aria-describedby="testSplitHelp" value="0.25">
            <small id="testSplitHelp" class="form-text text-muted">Answer between 0 to 1.</small>
          </div>
        </div>
    
        <!-- Gender / Age Parameters -->
        <div class="div_article077">
          <h2>Choose gender to predict: <span class="span_article077">(予測する人の性別)</span></h2>
          <!-- radio button list -->               
          <div class="row ml-1">                    
            <div class="form-check col-lg-6">
                <input class="form-check-input" type="radio" name="genderSelection" id="male_gender" value="1" checked>
                <label class="form-check-label" for="male_gender">Male(男性)</label>
            </div>
            <div class="form-check col-lg-6">  
                <input class="form-check-input" type="radio" name="genderSelection" id="female_gender" value="0">
                <label class="form-check-label" for="female_gender">Female(女性)</label>
            </div>
          </div>
    
          <!-- Choose Age -->
          <div class="form-group">
            <label for="age">Choose age to predict: <span class="span_article077">(予測する人の年齢)</span> </label>
            <input type="number" class="form-control" id="age" aria-describedby="ageHelp" value="21">
            <small id="ageHelp" class="form-text text-muted">Answer age to predict.</small>
          </div>  
        </div>
        
        <!-- Buttons -->
        <div class="div_article077">
          <div class="form-group">
            <button id="import" class="btn btn-primary mt-2"  pys-onClick="import_data">Import Data</button>
            <button id="train" class="btn btn-primary mt-2"  pys-onClick="train_model">Train Model</button>
            <button id="predict" class="btn btn-primary mt-2"  pys-onClick="predict">Predict</button>
            <button id="score" class="btn btn-primary mt-2"  pys-onClick="calculate_accuracy">Calculate Accuracy</button>   
          </div>
        </div>
    
        <hr />
        <div class="div_article077">
          <div id="output"></div>
        </div>
    
        <py-script>
    # import python libraries      
    import pandas as pd
    from pyodide.http import open_url
    
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import accuracy_score
    import joblib   
    from sklearn import tree
    import warnings
    warnings.simplefilter('ignore')
    
    # define global variables
    music_data = pd.DataFrame()
    model = DecisionTreeClassifier()
    
    def import_data(*args, **kwargs):
        # Import the data      
        global music_data      
        csv_file = 'https://raw.githubusercontent.com/akio-ak-kasai/pyscript_tutorial_001/main/music.csv'
        url_content = open_url(csv_file)
        df = pd.read_csv(url_content)
        console.warn(f'df.shape: {df.shape}')
        music_data = df
        pyscript.write('output', f'import_data(): df.shape {df.shape}')  
    
    def train_model(*args, **kwargs):  
        # Prepare the data
        df = music_data
        x = df.drop(columns=['genre'])  # age, gender
        y = df['genre'] # genre
        # Train the Model
        model.fit(x, y)
        console.warn('model.fit(x, y) done!')
        pyscript.write('output', f'train_model(): done!')  
    
    def predict(*args, **kwargs):  
        # Make Predictions
        gender = int(document.querySelector('input[name="genderSelection"]:checked').value); # 1-Male, 0-Female  
        console.warn(f'gender= {gender}')
        age = int(document.getElementById("age").value)
        console.warn(f'age= {age}')
        predections = model.predict([[age, gender]]) # [age, gender]
        console.warn(f'predections: {predections[0]}')
        pyscript.write('output', f'predict(): {predections[0]}')
    
    def calculate_accuracy(*args, **kwargs):
        # Calculating the Accuracy
        test_split = float(document.getElementById("test_split").value) # 0.2
        console.warn(f'test_split= {test_split:.2f}')
        df = music_data  
        x = df.drop(columns=['genre'])  
        y = df['genre'] 
        x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=test_split)
        console.warn(f'len(x_train): {len(x_train)}, len(y_train): {len(y_train)}')
        console.warn(f'len(x_test): {len(x_test)}, len(y_test): {len(y_test)}')
        model.fit(x_train, y_train)
        predections = model.predict(x_test) 
        score = accuracy_score(y_test, predections)
        console.warn(f'score: {score}')
        pyscript.write('output', f'calculate_accuracy(): score= {score}')
        </py-script>
    
    </body>
    </html>

  6. HTMLファイルをブラウザに表示する

    Visual Studo Code(VSC)からHTMLファイルをブラウザに表示するには、「Live Server」を使用します。 「Live Server」のインストールと操作については「記事(Article073)」で解説しています。 VSCから「Explorer」アイコンをクリックしてHTMLファイルの一覧を表示します。 一覧からHTMLファイルを右クリックしてポップアップリストから先頭の「Open with Live Server」をクリックします。
    click image to zoom!
    図2-1
    図2-1ではWebページから[Import Data]ボタンをクリックして音楽データを取り込んでいます。 結果としてPandasのDataFrameのshapeが表示されています。shapeからデータ件数が18件でレコードの列数が3(age, gender, genre)であることがわかります。


    click image to zoom!
    図2-2
    図2-2ではWebページから[Train Model]ボタンをクリックして機械学習させています。


    click image to zoom!
    図2-3
    図2-3では[Predict]ボタンをクリックして好みの音楽ジャンルを予測しています。 ここでは21歳男性の好みの音楽ジャンルを予測しています。予測結果として「HipHop」が表示されています。


    click image to zoom!
    図2-4
    図2-4では22歳女性の好みの音楽ジャンルを予測しています。予測結果として「Dance」が表示されています。


    click image to zoom!
    図2-5
    図2-5では[Calculate Accuracy]ボタンをクリックして予測の正解率を計算して表示させています。 正解率のスコアが「1.0」と表示されていますので正解率100%ということになります。 つまり予測が100%当るということです。 「Live DEMO」から「分割するテスト用データの割合」を0.10, 0.20, 0.30...のように変えて正解率がどのように変化するか検証して見てください。

Webページの各種ボタンを実行時に有効にして使い勝手をよくする

  1. Webページの各種ボタンを実行時に有効にする

    ここではWebページ上の[Train Model][Predict][Calculate Accuracy]ボタンを無効状態にしておいて、[Import Data]ボタンをクリックしたときに有効状態に切り替えます。 行77-79のbutton要素の「class」属性にCSSの「disable」を追加します。これでボタンがグレーアウトされます。 さらに「disabled」属性を追加してbutton要素のクリック時のイベントを無効にしておきます。

    行112-117では[Import Data]ボタンをクリックしたときに各種ボタンを有効に切り替えています。 行111ではDataFrameのshape(レコード件数)をチェックしてCSVファイルが正常に取り込まれたか確認しています。 行112, 114, 116ではbutton要素の「class」属性からCSSのクラス名「disabled」を削除しています。 これでボタンのグレーアウトが解除されます。 行113, 115, 117ではbutton要素の「disabled」属性に「Fase]を設定して無効にしています。 つまり、button要素のクリック時のイベントを有効にしています。 これでボタンをクリックしたときにクリック時のイベントが実行されます。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Using machine learning to predict music genres with PyScript</title>
        <style>      
            body {
              margin: 5% 5% !important;
            }
            .p_article077 {
              font-size: smaller; 
            }
            .span_article077 {
              font-size: smaller;
            }
            .div_article077 {
              width: 85%; 
              margin: 20px auto;
            }         
        </style>  
        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css">           
        <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
        <script defer src="https://pyscript.net/alpha/pyscript.js"></script>        
        <py-env>
          - numpy
          - pandas
          - scikit-learn
        </py-env>     
    </head>
    <body>
        <!-- Heading Content -->
        <div>
            <h1>Using machine learning to predict music genres with PyScript 🐍</h1>
            <p class="p_article077">(ここでは性別・年齢を選択して好みの音楽のジャンルを予測します)</p>
        </div>
    
        <!-- Training Parameters -->
        <div class="div_article077">
          <!-- Choose Test Split -->
          <div class="form-group">
            <label for="test_split">Choose Test Split: <span class="span_article077">(分割するテスト用データの割合)</span> </label>
            <input type="number" class="form-control" id="test_split" aria-describedby="testSplitHelp" value="0.25">
            <small id="testSplitHelp" class="form-text text-muted">Answer between 0 to 1.</small>
          </div>
        </div>
    
        <!-- Gender / Age Parameters -->
        <div class="div_article077">
          <h2>Choose gender to predict: <span class="span_article077">(予測する人の性別)</span></h2>
          <!-- radio button list -->               
          <div class="row ml-1">                    
            <div class="form-check col-lg-6">
                <input class="form-check-input" type="radio" name="genderSelection" id="male_gender" value="1" checked>
                <label class="form-check-label" for="male_gender">Male(男性)</label>
            </div>
            <div class="form-check col-lg-6">  
                <input class="form-check-input" type="radio" name="genderSelection" id="female_gender" value="0">
                <label class="form-check-label" for="female_gender">Female(女性)</label>
            </div>
          </div>
    
          <!-- Choose Age -->
          <div class="form-group">
            <label for="age">Choose age to predict: <span class="span_article077">(予測する人の年齢)</span> </label>
            <input type="number" class="form-control" id="age" aria-describedby="ageHelp" value="21">
            <small id="ageHelp" class="form-text text-muted">Answer age to predict.</small>
          </div>  
        </div>
        
        <!-- Buttons -->
        <div class="div_article077">
          <div class="form-group">
            <button id="import" class="btn btn-primary mt-2"  pys-onClick="import_data">Import Data</button>
            <button id="train" class="btn btn-primary mt-2 disabled" disabled pys-onClick="train_model">Train Model</button>
            <button id="predict" class="btn btn-primary mt-2 disabled" disabled pys-onClick="predict">Predict</button>
            <button id="score" class="btn btn-primary mt-2 disabled" disabled pys-onClick="calculate_accuracy">Calculate Accuracy</button>   
          </div>
        </div>
    
        <hr />
        <div class="div_article077">
          <div id="output"></div>
        </div>
    
        <py-script>
    # import python libraries      
    import pandas as pd
    from pyodide.http import open_url
    
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import accuracy_score
    import joblib   
    from sklearn import tree
    import warnings
    warnings.simplefilter('ignore')
    
    # define global variables
    music_data = pd.DataFrame()
    model = DecisionTreeClassifier()
    
    def import_data(*args, **kwargs):
        # Import the data      
        global music_data      
        csv_file = 'https://raw.githubusercontent.com/akio-ak-kasai/pyscript_tutorial_001/main/music.csv'
        url_content = open_url(csv_file)
        df = pd.read_csv(url_content)
        if df.shape[0] == 18:
          document.getElementById("train").classList.remove("disabled");
          document.getElementById("train").disabled = False;    
          document.getElementById("predict").classList.remove("disabled");
          document.getElementById("predict").disabled = False; 
          document.getElementById("score").classList.remove("disabled");
          document.getElementById("score").disabled = False;       
    
          console.warn(f'df.shape: {df.shape}')
          music_data = df
          pyscript.write('output', f'import_data(): df.shape {df.shape}')     
        else:
          console.error(f'pd.read_csv() error: df.shape: {df.shape}')    
          pyscript.write('output', f'import_data(): pd.read_csv() network error df.shape {df.shape}')  
    
    def train_model(*args, **kwargs):  
        # Prepare the data
        df = music_data
        x = df.drop(columns=['genre'])  # age, gender
        y = df['genre'] # genre
        # Train the Model
        model.fit(x, y)
        console.warn('model.fit(x, y) done!')
        pyscript.write('output', f'train_model(): done!')  
    
    def predict(*args, **kwargs):  
        # Make Predictions
        gender = int(document.querySelector('input[name="genderSelection"]:checked').value); # 1-Male, 0-Female  
        console.warn(f'gender= {gender}')
        age = int(document.getElementById("age").value)
        console.warn(f'age= {age}')
        predections = model.predict([[age, gender]]) # [age, gender]
        console.warn(f'predections: {predections[0]}')
        pyscript.write('output', f'predict(): {predections[0]}')
    
    def calculate_accuracy(*args, **kwargs):
        # Calculating the Accuracy
        test_split = float(document.getElementById("test_split").value) # 0.2
        console.warn(f'test_split= {test_split:.2f}')
        df = music_data  
        x = df.drop(columns=['genre'])  
        y = df['genre'] 
        x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=test_split)
        console.warn(f'len(x_train): {len(x_train)}, len(y_train): {len(y_train)}')
        console.warn(f'len(x_test): {len(x_test)}, len(y_test): {len(y_test)}')
        model.fit(x_train, y_train)
        predections = model.predict(x_test) 
        score = accuracy_score(y_test, predections)
        console.warn(f'score: {score}')
        pyscript.write('output', f'calculate_accuracy(): score= {score}')
        </py-script>
    
    </body>
    </html>

    click image to zoom!
    図3-1
    図3-1は[Import Data]ボタンをクリックする前のWebページの状態です。 [Train Model][Predict][Calculate Accuracy]ボタンがグレーアウトされて無効になっています。 これらのボタンをクリックしてもクリック時のイベントが発生しません。


    click image to zoom!
    図3-2
    図3-2は[Import Data]ボタンをクリックしてCSVファイルを正常にインポートした後のWebページの状態です。 [Train Model][Predict][Calculate Accuracy]ボタンのグレーアウトが解除されて有効な状態に切り替わっています。 これらのボタンをクリックするとクリック時のイベントが実行されます。



Live DEMO

注:この「Live DEMO」はスマホでは正常に動作しないことがありますのでパソコンでご覧ください。 好みの音楽ジャンルを予測するには[Import Data]▶[Train Model]▶[Predict]の順にボタンをクリックしてください。 [Predict]ボタンをクリックする前に「性別」と「年齢」を入力してください。デフォルト値は「男性・21歳」になっています。