本投稿は TECOTEC Advent Calendar 2025 の11日目の記事です。
ソリューション事業本部のゼンです。
普段はPHPを使ってバックエンド開発を行っています。
この記事では、Kaggleを通して学んだ機械学習の基礎知識を、コードを交えて共有します。
コードを聞くと難しいと思う方もいるかもしれませんが、エンジニアじゃなくてもわかるようにコメントと説明を記載していますので、どうぞご参考にしてください。
AIについて
最近、AIの進化が速いと感じませんか?
ChatGPTなどの対話型AIを初め、画像などのマルチメディアを生成できるAIも普及している今、おそらくほとんどの人は日常でAIを利用していることでしょう。
私も普段の情報収集に使っていて、業務上でコードの生成や成果物の品質チェックなどにも使っています。
もはやAIがないと楽に生きられない人間になっています。(笑)
一人のエンジニアとして、時代の流れに乗り遅れないよう、AIに関する知識とかもそろそろ身につけたいと思いました。
ただAIはどこから勉強を始めた方が良いのか迷った結果、「機械学習」という単語が目に留まったのでいろいろ調べてみました。
機械学習について
「機械学習」は簡単に言うと、機械が物事を学習する方法であり、すべてのAIの基盤です。
初めて足し算を学んだことをまだ覚えていますか。
多分ほとんどの人間は同じで、最初は1+1=2、それから1+2=3、1+3=4 ...の感じで徐々にルールを掴んで足し算の意味を理解できたのでしょう。
実は機械も人間と同じく、例を与えないと学習できません。
まあ足し算はAIがない電卓でもできますが、例えば画像認識、「丸」という形状を認識させたいならまずは円の画像をインプットします。
人間であれば、多分適当に手描きの絵2枚で『丸』の特徴をつかめるでしょう。
でもAIは人間の脳より硬く、手描きの絵2枚だけだと正円すら認識できないぐらいです。
ただいろんな円の画像をたくさんあげれば、AIはアルゴリズムを通してその大量のデータから「規則性」を見つけ出し、手描きの丸も歪んでる丸も認識できるようになります。
つまり機械学習は大量のデータを取り込んで、規則を見つける過程・方法です。
そして今流行りの生成AIはその見つけ出した「規則」を参考にして「多分これだろう」という内容を生成しています。
Kaggleとは
KaggleはGoogle社が所有している世界で一番規模が大きい機械学習オンラインプラットフォームです。
機械学習の基礎はもちろん、応用や上級者向けのコースも充実しています。
多岐にわたるテーマのコンペティションも開催されていて、全世界の機械学習エンジニア、データサイエンティストが競い合う場でもあります。
そして情報共有とディスカッションができるコミュニティもあり、問題解決も意見交換もKaggle内で完結できます。
Kaggleはウェブサイトなので、ウェブを開けるすべての端末が利用できるプラットフォームです。
そしてサイト内の学習コースは説明に合わせて、オンラインでプログラムを実行できる機能とデータセットも備えています。
自分で環境を整えなくても気軽に機械学習に着手できるので、まさに初心者フレンドリーのプラットフォームです。
ただし、Kaggleは英語ベースのサイトで、英語が苦手な方には、翻訳機能やAIなどを補助として活用することをおすすめします。
実際にプログラムを作って機械学習を実践してみる
ここからは基礎コースの一部の内容をコードにまとめて紹介します。
基礎と言っても様々なコンテンツがあるので、興味ある方はご自身でコースを受けてみてください。
まずはKaggleのアカウントを作ります。googleアカウントと連携できるのでお勧めです。
アカウント作成できたらホーム画面にアクセスできるようになります。
ホーム画面左側のメニューですが、「Learn」がコースを受ける機能で、ただ今回はそのままコードで説明しますので、自分でコードを書いて実行できる機能「Code」を利用します。
データセット:🎓 Student Scores | Kaggle
「Code」からもコード作成できますが、今回はデータセットをインポートするので、上記データセットページの右上の「︙」の中にある「New Notebook」をクリックすればデータセットをインポートした状態で作成できます。
今回使うデータセット(AIにインプットする大量の情報)は「Student Scores」という仮想の高校生たちの成績データが2000件入っています。
仮想のデータではあるが、様々な傾向の学生が含まれており、項目もわかりやすいので初めての機械学習には十分だと思います。
| id | first_name | last_name | gender | part_time_job | absence_days | extracurricular_activities | weekly_self_study_hours | career_aspiration | math_score | history_score | physics_score | chemistry_score | biology_score | english_score | geography_score | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| id | 名 | 姓 | メールアドレス | 性別 | アルバイトの有無 | 欠席日数 | 課外活動の有無 | 週の自習時間 | 進路希望 | 数学成績 | 歴史学成績 | 物理学成績 | 化学成績 | 生物学成績 | 英語成績 | 地理学成績 |
| 1 | Paul | Casey | paul.casey.1@gslingacademy.com | male | FALSE | 3 | FALSE | 27 | Lawyer | 73 | 81 | 93 | 97 | 63 | 80 | 87 |
| 2 | Danielle | Sandoval | danielle.sandoval.2@gslingacademy.com | female | FALSE | 2 | FALSE | 47 | Doctor | 90 | 86 | 96 | 100 | 90 | 88 | 90 |
| 3 | Tina | Andrews | tina.andrews.3@gslingacademy.com | female | FALSE | 9 | TRUE | 13 | Government Officer | 81 | 97 | 95 | 96 | 65 | 77 | 94 |
| 4 | Tara | Clark | tara.clark.4@gslingacademy.com | female | FALSE | 5 | FALSE | 3 | Artist | 71 | 74 | 88 | 80 | 89 | 63 | 86 |
| 5 | Anthony | Campos | anthony.campos.5@gslingacademy.com | male | FALSE | 5 | FALSE | 10 | Unknown | 84 | 77 | 65 | 65 | 80 | 74 | 76 |
事前の準備ができたので、コードのほうに移ります。
すでにコードが生成されていますが、そのまま使いますので、以下のインポート部分を後ろに追加します。
コード追加する場合は「+ Code」ボタンをクリックすれば個別で実行できるコードブロックが追加されるのでおすすめです。
#ライブラリインポート from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split from sklearn.metrics import mean_absolute_error from sklearn.feature_selection import mutual_info_regression
そして肝心なデータセットもコード側に取り込みます。
うまくデータを取れているかは先頭の5件を出力します。
#csvファイルを読み込んで、pandas(データフレーム)に変換して変数dataに保存 file_path = '/kaggle/input/student-scores/student-scores.csv' data = pd.read_csv(file_path) #先頭5件出力 print('データ先頭5件出力') print(data.head())
ここまでのコードを実行する方法は上部の「▷▷」ボタンをクリックすれば全部実行してくれます。
実行完了したら先ほど追加したコードの下に実行結果(データセットの先頭5件)が出力されます。
ここまでが導入部分です。次はデータの加工を行います。
機械学習において一つ重要なポイントがあり、それが「目的」です。
ここからは高校生の成績や活動状態などのデータを使いますが、最終的になにを学習させたいのか、学習させた成果をどこに使うのかはまだ定まっていません。
今回は基本知識を学ぶだけなので、「性別」、「アルバイトの有無」、「欠席日数」、「課外活動の有無」、「週の自習時間」、「進路希望」を利用して、「平均成績」を予測するモデルを作ることを目的にしましょう。
「平均成績」という項目がないので、ここはデータを加工して作ります。
#成績平均値のカラムを作成 data['score_mean'] = ( data['math_score'] + data['history_score'] + data['physics_score'] + data['chemistry_score'] + data['biology_score'] + data['english_score'] ) / 7
予測目標の「平均成績」ができたので、データセットを「目標データ」と「参考データ」の2グ ループに分けます。
目標データはすべての学生の「平均成績」で、参考データは「性別」、「アルバイトの有無」、「欠席日数」、「課外活動の有無」、「週の自習時間」、「進路希望」です。
#平均成績score_meanを指定して目標データtarget_dataを作成 target_data = data.score_mean #参考用カラムを指定して参考データreference_dataを作成 features = ['gender', 'part_time_job', 'absence_days', 'extracurricular_activities', 'career_aspiration', 'weekly_self_study_hours'] reference_data = data[features].copy()
上記で今回使うデータのグループ分けができました。
次は学習と予測の処理です。
予測と検証の処理自体は複雑ではありませんが、主にデータ変換やライブラリの利用が中心となるため、慣れていないと混乱しがちです。
特にpandas(データフレーム)とpythonに慣れていない人には読み辛いかもしれませんが、今回は汎用的な関数を作成したので、中身が詳しくなくてもそのまま使えます。
#文字となっている値を整数に変換する、例:TRUE→1、FALSE→2 def label_encode(X): for colname in X.select_dtypes("object"): X[colname], _ = X[colname].factorize() return X #学習と予測を行う def get_predict(X, y): #train_test_split()を使って参考データと目標データをそれぞれ、学習用と予測用に分ける train_X, val_X, train_y, val_y = train_test_split(X, y, random_state = 0) #★学習 学習用の参考データと目標データをインプットして、学習済みのモデルを作成 model = RandomForestRegressor(random_state=0) model.fit(train_X,train_y) #★予測 予測用の参考データを上記モデルに予測させて結果をpredictionに保存 prediction = model.predict(val_X) #予測した結果の先頭5件を出力 print('予測した結果の先頭5件') print(prediction[:5]) #実際先頭5件の値を出力 print('実際先頭5件の値') print(val_y.head()) #★検証 予測モデルの成果と実際の数値と比較し、平均絶対誤差を出力 print('平均絶対誤差') print(mean_absolute_error(val_y, prediction)) # 参考カラムと目標カラムの相互情報量(相関性)を出力 def get_mi_scores(X, y): discrete_features = X.dtypes == int mi_scores = mutual_info_regression(X, y, discrete_features=discrete_features) mi_scores = pd.Series(mi_scores, name="MI Scores", index=X.columns) mi_scores = mi_scores.sort_values(ascending=False) print('相関性') print(mi_scores)
各関数にコメントを記載していますが、詳細はこの後に説明します。
データに関してはほぼ用意できていますが、実はもう一工夫が必要です。
それは値が文字のデータを整数に変換することです。
テキストをプログラムが扱いやすい整数に変換しないと大量のデータを処理する際にはかなり時間がかかるので、できるだけデータを事前に軽量化することが重要です。
*目標データ(平均成績)は数字なので変換不要です。
reference_data = label_encode(reference_data)
次は機械学習のメイン処理を行います。
print('予測実行:') get_predict(reference_data, target_data)
get_predict()の内部処理は一番重要な部分なので、ここからは処理を細かく説明します。
#train_test_split()を使って参考データと目標データをそれぞれ、学習用と予測用に分ける train_X, val_X, train_y, val_y = train_test_split(X, y, random_state = 0)
ここで「一度目標データと参考データを分けたのに、なぜまたデータを分割するのだろう?」という疑問が浮かぶと思います。
今回は機械学習を中心に説明を行いますが、学習させた結果を検証しないと、ちゃんと想定した結果が出たのかどうかがわからないので、検証に一部のデータを切り離して使います。
つまり[目標、参考]→学習用[目標、参考]、検証用[目標、参考]の感じで分けます。
両グループの割合はtrain_test_split()が勝手にやってくれます。
事前に手動でデータを分割するのも良いですが、ここはライブラリに任せます。
#★学習 学習用データをインプットして、学習済みのモデルを作成 model = RandomForestRegressor(random_state=0) model.fit(train_X,train_y)
ここは学習の処理で、すごくシンプルです。
RandomForestRegressorという学習モデルを利用して、学習用の目標データと参考データをモデルにインプットするだけです。
RandomForestランダムフォレストは機械学習でよく使われているアルゴリズムです。
ここでは説明しませんが、データ分析と予測となる基盤ロジックなので気になる方はぜひ調べてみてください。
#★予測 予測用の参考データを上記のモデルに予測させて、予測結果を出力 prediction = model.predict(val_X) #予測した結果の先頭5件を出力 print(prediction[:5])
ここは予測の処理です。
先ほど切り離した予測用参考データをインプットして、それに対する予測結果を確認します。
先頭5件は以下の感じで出力されます。
予測した結果の先頭5件 [70.559 69.88914286 69.59205782 60.35511905 79.56833333]
これ見てもわからないと思うので、実際のデータセットの値も出力します。
#実際先頭5件の値 print(val_y.head())
実際先頭5件の値 405 67.285714 1190 59.571429 1132 73.714286 731 65.000000 1754 80.285714
左がIDで、右が先頭5件の本当の平均成績です。
予測結果と見比べればわかりますが、1件目の実際の値が67.285714に対して、予測結果が70.559で誤差は約3ですね。
2件目の誤差は約10で、3件目は約4、4件目は約5、5件目は約1です。
#★検証 予測モデルの成果と実際の数値と比較して、平均誤差を出力 print(mean_absolute_error(val_y, prediction))
すべてのデータの誤差を算出するのは面倒くさいですよね。
ライブラリには便利な関数mean_absolute_error()が用意されているので、平均絶対誤差 を計算してくれます。
それを出力して確認します。
平均絶対誤差
3.539802874149661
なんと平均絶対誤差はわずか3.5です。
個別で見ると誤差のムラが目立ちますが、実際は誤差がかなり抑えられていますね。
以上が学習、予測、検証の一連の流れです。
次は参考データを調整して平均誤差がどう変化するのかを検証してみましょう。
その前に、参考データのカラムと目標データのカラムがどんな関連性があるのかを調べてみます。
ライブラリには項目間の相関性を算出できる便利な関数mutual_info_regression()を用意してあるので、先ほど追加した関数get_mi_scores()を呼び出します。
今回の主旨ではないので、get_mi_scores()の内部説明は省きさせていただきます。
get_mi_scores(reference_data, target_data)
以下が各参考項目と平均成績の相関性が数値として出力され、数値が高いほど相関性が高いです。
相関性 career_aspiration 0.282735 weekly_self_study_hours 0.241538 absence_days 0.042240 part_time_job 0.025726 extracurricular_activities 0.012875 gender 0.000000
見ればわかりますが、性別は平均成績とまったく関係ないですね。(少なくともこのデータセットでは)
逆に進路希望と週の自習時間が平均成績と深く関わっており、現実でもその関連性は納得できますね。
上記の情報を利用して、参考データの項目を調整したら予測結果が変わるのかを確認してみましょう。
わかりやすいように一番相関性を持つ進路希望だけ参考データにして予測を行います。
print('予測実行(参考カラムは進路希望のみ):') get_predict(reference_data.loc[:,[ "career_aspiration" ]], target_data)
平均絶対誤差
3.345506005067886
平均絶対誤差は3.3くらいで、全参考カラムを使う時の3.5より0.2ぐらい改善されましたね。
0.2なんて少ないと思うかもしれませんが、機械学習において予測の精度を少しでも上げられればほかのモデルに勝つことができ、もしビジネスに利用されている場合は競合を勝ち抜くチャンスになるかもしれません。
改善の例を見れたので、次は改悪の例をみましょう。
print('予測実行(参考カラムは性別のみ):') prediction = get_predict(reference_data.loc[:,["gender"]], target_data)
一番相関性がない性別だけを参考データにして予測を行います。
平均絶対誤差
4.339265154833954
平均絶対誤差は4.3で、先ほどの3.3と比べると誤差が1増えて予測精度が落ちましたね。
ちなみに相関性のない性別だけでも4.3の平均絶対誤差を出せるのは、このデータセット(2000件)の平均成績のばらつきが少ないため、全学生の平均成績の平均値で予測しても同程度の平均絶対誤差が出るためと考えられます。
以上は結果がわかりやすいように一つの項目を特定して検証しました。
複数項目の組み合わせしたり、目標カラムを変更したりして違う結果を検証できるので、ぜひご自身でお試しください
まとめ
今回はシンプルな学習モデルを作って予測・検証をしました。
しかし、学習の成果(予測精度)に影響を与える要素はまだ多くあります。
機械学習において非常に興味深い部分ですので、機会があればまた紹介したいと思います。
参考
テコテックの採用活動について
テコテックでは新卒・中途採用を積極的に行っています。 採用サイトでは会社の雰囲気や福利厚生、募集ポジションをご確認いただけます。 ご興味をお持ちいただけましたら、ぜひチェックしてみてください。 tecotec.co.jp