マテリアルズインフォマティクス(MI)入門⑤【特徴量エンジニアリング ― 物理記述子と「次元の呪い」】

マテリアルズインフォマティクス(MI)入門⑤【特徴量エンジニアリング ― 物理記述子と「次元の呪い」】

これまでの道のりで、私たちはMIプロジェクトの強力なワークフローを一歩ずつ踏み固めてきました。

そして今回、シリーズの中盤に位置する第5回では、いよいよAIに材料科学のドメイン知識を注入します。これまでは「どの元素がどれだけ含まれているか」という情報だけでしたが、今回は原子半径や電気陰性度といった物理記述子(Descriptor)を導入し、モデルがより本質的な物理法則に基づいて推論できるようにすることを目指します。

常識的に考えれば、より多くの、より質の高い情報を与えれば、モデルは賢くなるはずです。しかし、データサイエンスの世界は、時として私たちの直感を裏切ります。今回は、その典型例ともいえる「ドメイン知識の罠」と、そこから得られるMIにおける極めて重要な教訓を体験していきましょう。

動作検証済み環境

Google Colaboratory
Python 3.11.13
matminer==0.9.3
scikit-learn==1.6.1
pandas==2.2.2
matplotlib==3.10.0
catboost==1.2.8

この記事から学べること

  • 物理記述子の概念と作成方法: なぜ元素含有率だけでは不十分と考えられているのか、そして matminer を使って物理・化学的な特徴量を自動生成する具体的な手法をマスターできます。
  • 「次元の呪い」の実体験: 「特徴量は多ければ多いほど良い」という神話がなぜ危険なのかを、実際の性能低下という結果を通じて痛感できます。
  • 特徴量選択の重要性: 大量の特徴量の中から、予測に本当に貢献するものだけを選び出す「特徴量選択」という基本的なプロセスを学び、その効果と限界を理解できます。
  • MIプロジェクトの現実: 科学的な探求は常に右肩上がりではありません。試行錯誤の末に「最初のシンプルなモデルが最良だった」という結論に至る、MIプロジェクトのリアルな姿と、その結果から次の一手を考える科学的思考プロセスを学べます。

関連理論の解説

1. 記述子(Descriptor)とは何か?

マテリアルズインフォマティクスにおいて、記述子とは、材料をAIが理解できる数値の集合(ベクトル)に変換したものです。これまで扱ってきた「各元素の含有率」も、最もシンプルな記述子の一つです。

しかし、材料の物性は、単に元素の割合だけで決まるわけではありません。原子の大きさ(原子半径)、電子を引きつける強さ(電気陰性度)といった、より本質的な物理・化学的性質の複雑な相互作用によって支配されています。これらの性質を数値化したものが物理記述子であり、これらを特徴量としてAIに与えることで、モデルはより深く材料の挙動を学習できると期待されます。

2. matminer による特徴量生成プロセス

matminer は、この物理記述子の生成を自動化する強力なツールです。ElementProperty.from_preset("magpie") 機能は、以下の2段階のプロセスで特徴量を計算します。

  1. 元素ごとの基礎物性値を参照: matminer は、各元素の原子量、共有結合半径、電気陰性度といった多数の物理・化学的特性値を内部データベースに保持しています。
  2. 統計量を計算: 材料の化学組成(各元素の含有率)に応じて、これらの基礎物性値の加重平均加重平均偏差最大値最小値などを計算します。

例えば、MagpieData avg_dev Electronegativity という特徴量は、「その材料を構成する全元素の電気陰estring度について、含有率で重みづけした平均偏差」を意味します。これにより、1つの化学組成式から、その背後にある物理的な意味合いを多角的に捉えた132次元もの豊富な特徴量セットを生成できるのです。

3. 次元の呪い

良かれと思って特徴量の数(次元)を増やしすぎると、かえってモデルの性能を悪化させてしまう現象を「次元の呪い」と呼びます。主に以下の問題が発生します。

  • 計算コストの増大: 学習に必要な時間やメモリが増加します。
  • 過学習のリスク: モデルが訓練データに存在するノイズや偶然のパターンまで学習してしまい、未知のデータに対する予測性能(汎化性能)が著しく低下します。
  • スパーシティ: 高次元空間ではデータ点が非常にまばらに存在するため、近傍の点を見つけることが困難になり、多くのアルゴリズムがうまく機能しなくなります。

「ドメイン知識」という質の高い情報を加えたつもりが、それ以上に大量の「ノイズ」や「冗長な情報」を加えてしまうと、モデルはこの「次元の呪い」に陥り、かえって性能が低下してしまうのです。

実装方法

以下の5つの異なる特徴量セットを準備し、それぞれの性能を公平に比較します。

  • (B) 元素含有率のみ (ベースライン)
  • (A-All) 全物理記述子のみ (132個)
  • (A-Selected) 選択された物理記述子のみ (上位15個)
  • (C​) 含有率 + 全物理記述子 (14 + 132 = 146個)
  • (D) 含有率 + 選択物理記述子 (14 + 15 = 29個)

ワークフロー

# ===================================================================
# 0. 環境構築:必要なライブラリのインストール
# 1. 必要なライブラリのインポート
# 2. データセットの読み込み & 前処理
# 3. 2種類のベース特徴量セットを生成
# 4. 重要な物理記述子を選択 (A-Selected)
# 5. 2つの新しい特徴量セットを生成
# 6. 全5モデルの学習と評価を実行する関数を定義
# 7. 全5モデルの評価を実行
# 8. 最終結果の比較
# ===================================================================

実行手順

  • 以下のコードブロック全体をコピーします。
  • Google Colaboratoryの新しいセルに貼り付けます。
  • セルが選択されていることを確認し、Shift キーと Enter キーを同時に押してコードを実行します。
# ===================================================================
# 0. 環境構築:必要なライブラリのインストール
# ===================================================================
!pip install matminer==0.9.3 pandas==2.2.2 scikit-learn==1.6.1
!pip install catboost==1.2.8

# ===================================================================
# 1. 必要なライブラリのインポート
# ===================================================================
import pandas as pd
import numpy as np
import re
from matminer.datasets import load_dataset
from matminer.featurizers.composition import ElementProperty
from pymatgen.core.composition import Composition
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, r2_score
from catboost import CatBoostRegressor
from IPython.display import display

# ===================================================================
# 2. データセットの読み込み & 前処理
# ===================================================================
print("ステップ2: データセットの読み込み...")
df = load_dataset("matbench_steels")
df["composition_obj"] = df["composition"].apply(Composition)
target_col = "yield strength"
print("完了しました。")

# ===================================================================
# 3. 2種類のベース特徴量セットを生成
# ===================================================================
print("\nステップ3: 2種類のベース特徴量セットを生成します...")
# --- 特徴量セット(B): 元素含有率 ---
elements = [
    "Fe",
    "C",
    "Mn",
    "Si",
    "Cr",
    "Ni",
    "Mo",
    "V",
    "N",
    "Nb",
    "Co",
    "W",
    "Al",
    "Ti",
]

def extract_value(composition_string, element_name):
    pattern = r"{}(\d+\.?\d*)".format(element_name)
    match = re.search(pattern, str(composition_string))
    return float(match.group(1)) if match else 0.0

X_elem = pd.DataFrame()
for element in elements:
    X_elem[element] = df["composition"].apply(lambda x: extract_value(x, element))

# --- 特徴量セット(A): 全物理記述子 ---
ep_featurizer = ElementProperty.from_preset("magpie")
df_phys_features = ep_featurizer.featurize_dataframe(
    df, col_id="composition_obj", ignore_errors=True
)
X_phys_all = df_phys_features[ep_featurizer.feature_labels()]

# NaNを含む行を削除し、全データセットでインデックスを統一
valid_indices = X_phys_all.dropna().index
X_elem = X_elem.loc[valid_indices]
X_phys_all = X_phys_all.loc[valid_indices]
y = df.loc[valid_indices, target_col]

print(f"最終的なサンプル数: {len(y)}")
print("完了しました。")

# ===================================================================
# 4. 重要な物理記述子を選択 (A-Selected)
# ===================================================================
print("\nステップ4: 重要な物理記述子を選択します...")
# 全物理記述子で一度モデルを学習
temp_model = CatBoostRegressor(random_seed=42, verbose=0)
temp_model.fit(X_phys_all, y)
importances = temp_model.get_feature_importance()
# 上位15個を選択
top_n = 15
top_indices = np.argsort(importances)[::-1][:top_n]
top_features = X_phys_all.columns[top_indices]
X_phys_selected = X_phys_all[top_features]
print(f"上位{top_n}個の物理記述子を選択しました。")
print("完了しました。")

# ===================================================================
# 5. 2つの新しい特徴量セットを生成
# ===================================================================
print("\nステップ5: 2つの新しい特徴量セットを生成します...")
# --- 特徴量セット(C): 元素含有率 + 全物理記述子 ---
X_comp_all = pd.concat([X_elem, X_phys_all], axis=1)

# --- 特徴量セット(D): 元素含有率 + 選択物理記述子 ---
X_comp_selected = pd.concat([X_elem, X_phys_selected], axis=1)
print("完了しました。")

# ===================================================================
# 6. 全5モデルの学習と評価を実行する関数を定義
# ===================================================================
def evaluate_model(X, y, model_name):
    print(f"\n--- {model_name} の評価 ---")
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=42
    )

    model = CatBoostRegressor(random_seed=42, verbose=0)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)

    r2 = r2_score(y_test, y_pred)
    mae = mean_absolute_error(y_test, y_pred)

    print(f"  特徴量数: {X.shape[1]}")
    print(f"  R2スコア: {r2:.4f}")
    print(f"  MAE: {mae:.2f} MPa")

    return r2, mae, model

# ===================================================================
# 7. 全5モデルの評価を実行
# ===================================================================
print("\nステップ7: 全5モデルの評価を開始します...")
results = {}

results["B: 元素含有率のみ"] = evaluate_model(X_elem, y, "モデルB: 元素含有率のみ")
results["A-All: 全物理記述子"] = evaluate_model(
    X_phys_all, y, "モデルA-All: 全物理記述子のみ"
)
results["A-Selected: 選択物理記述子"] = evaluate_model(
    X_phys_selected, y, "モデルA-Selected: 選択物理記述子のみ"
)
results["C: 含有率 + 全記述子"] = evaluate_model(
    X_comp_all, y, "モデルC: 含有率 + 全記述子"
)
results["D: 含有率 + 選択記述子"] = evaluate_model(
    X_comp_selected, y, "モデルD: 含有率 + 選択記述子"
)

# ===================================================================
# 8. 最終結果の比較
# ===================================================================
print("\nステップ8: 最終結果を比較します...")
final_results_df = (
    pd.DataFrame(
        {
            "特徴量セット": list(results.keys()),
            "特徴量数": [
                X_elem.shape[1],
                X_phys_all.shape[1],
                X_phys_selected.shape[1],
                X_comp_all.shape[1],
                X_comp_selected.shape[1],
            ],
            "テストデータ R²スコア": [res[0] for res in results.values()],
            "テストデータ MAE (MPa)": [res[1] for res in results.values()],
        }
    )
    .sort_values("テストデータ R²スコア", ascending=False)
    .reset_index(drop=True)
)

print("\n【最終モデル性能比較】")
display(final_results_df)

実行結果と考察

結論:単純こそが最強だった

5パターンもの特徴量セットを試し、性能改善の旅を続けた結果、私たちは驚くべき、しかし極めて重要な結論にたどり着きました。

特徴量セット 特徴量数 テストデータ R²スコア テストデータ MAE (MPa)
1位 (B) 元素含有率のみ 14 0.8045 75.70
2位 (D) 含有率 + 選択記述子 29 0.7981 76.81
3位 (C​) 含有率 + 全記述子 146 0.7790 77.55
4位 (A-Selected) 選択物理記述子 15 0.7759 81.43
5位 (A-All) 全物理記述子 132 0.7557 82.90

最終的に最も高い性能を示したのは、最初に構築した「元素含有率のみ」のモデルでした。 ドメイン知識を注入し、特徴量を複雑にする試みは、いずれもベースラインを超えることができませんでした。

この結果は「失敗」ではなく、MIプロジェクトにおける最も価値ある学びの一つです。

なぜ性能は向上しなかったのか?

  1. 「次元の呪い」の猛威

    最も性能が低かったのは、最多の物理記述子(132個)を持つモデル(A-All)でした。これは、データサンプルの数(312個)に対して特徴量が多すぎたためです。モデルは、予測に有用な情報(シグナル)と無関係な情報(ノイズ)の区別がつかなくなり、ノイズにまで過剰に適合しようとして学習が混乱し、未知のデータに対する予測能力を失ってしまいました。

  2. 特徴量選択の限界

    特徴量選択(モデル A-Selected)によってノイズを減らし、性能が改善したことは、このアプローチの有効性を示しています。しかし、それでもなお、単純な「元素含有率」モデルには及びませんでした。この事実は、「物理的に意味のある記述子が、必ずしも予測性能向上に直結するとは限らない」という重要な知見を与えてくれます。今回の場合、鋼材の降伏強度という特性に対しては、集約された物理情報よりも、「どの元素がどれだけ入っているか」という直接的な情報の方が、強力な予測因子だったのです。

  3. 組み合わせが常に最良とは限らない

    元素含有率と物理記述子を組み合わせる試み(モデルC, D)も、ベースラインを超えることはできませんでした。闇雲に情報を追加することが、必ずしも得策ではないことを改めて示しています。

コードの詳細解説

今回のコードは、複数の特徴量セットを体系的に比較評価する、科学的検証の「型」そのものです。重要なステップを解説します。

ステップ3: 2種類のベース特徴量セットを生成

すべての比較の出発点となる、2つの根本的に異なる特徴量セットを準備します。ここでの丁寧な準備が、後の分析の信頼性を決定づけます。

# ===================================================================
# 3. 2種類のベース特徴量セットを生成
# ===================================================================
print("\nステップ3: 2種類のベース特徴量セットを生成します...")
# --- 特徴量セット(B): 元素含有率 ---
elements = [
    "Fe",
    "C",
    "Mn",
    "Si",
    "Cr",
    "Ni",
    "Mo",
    "V",
    "N",
    "Nb",
    "Co",
    "W",
    "Al",
    "Ti",
]

def extract_value(composition_string, element_name):
    pattern = r"{}(\d+\.?\d*)".format(element_name)
    match = re.search(pattern, str(composition_string))
    return float(match.group(1)) if match else 0.0

X_elem = pd.DataFrame()
for element in elements:
    X_elem[element] = df["composition"].apply(lambda x: extract_value(x, element))

# --- 特徴量セット(A): 全物理記述子 ---
ep_featurizer = ElementProperty.from_preset("magpie")
df_phys_features = ep_featurizer.featurize_dataframe(
    df, col_id="composition_obj", ignore_errors=True
)
X_phys_all = df_phys_features[ep_featurizer.feature_labels()]

# NaNを含む行を削除し、全データセットでインデックスを統一
valid_indices = X_phys_all.dropna().index
X_elem = X_elem.loc[valid_indices]
X_phys_all = X_phys_all.loc[valid_indices]
y = df.loc[valid_indices, target_col]

print(f"最終的なサンプル数: {len(y)}")
print("完了しました。")
  • 特徴量セット(B): X_elem(元素含有率)
    • これは第2回から使用している、最もシンプルで直接的な特徴量セットです。いわば、今回の実験における「比較基準(ベースライン)」の役割を果たします。新しい複雑な特徴量が、このシンプルなベースラインを超えることができるかが、最初の焦点となります。
  • 特徴量セット(A): X_phys_all(全物理記述子)
    • ep_featurizer = ElementProperty.from_preset("magpie"): ここが、matminer ライブラリに「ドメイン知識」を注入させるための核心部分です。
      • ElementProperty: 材料の組成(どの元素がどれだけあるか)から、物理的・化学的な特性を計算するための機能群です。
      • from_preset("magpie"): “magpie” は、材料科学の分野で広く使われている、実績のある物理記述子のセットを呼び出す「プリセット名」です。これにより、原子量、電気陰性度、共有結合半径など、100を超える物理特性値を自動で扱えるようになります。
    • df_phys_features = ep_featurizer.featurize_dataframe(...): この一行で、matminer はデータフレーム内の各材料組成(composition_obj)に対して、”magpie”プリセットに含まれる全記述子を自動計算します。内部では、各材料の元素比率に応じて、物理特性値の加重平均や最大値、最小値などが計算され、132個もの新しい特徴量列が生成されます。
  • 比較の土台を揃えるためのデータクリーニング
    • valid_indices = X_phys_all.dropna().indexmatminer が物理記述子を計算した際、一部の材料では計算ができなかったり(例えば、特殊な元素が含まれる場合)、値が欠損(NaN)したりすることがあります。 dropna() は、一つでもNaNを含む行を X_phys_all から削除します。そして、.index で、有効なデータ(全ての物理記述子が計算できたサンプル)の行番号だけを取得 します。
    • X_elem = X_elem.loc[valid_indices]: ここが極めて重要な処理です。先ほど取得した「有効な行番号」だけを使い、元素含有率のデータセットからも、対応する行だけを抽出します。
    • この処理により、これから評価する全てのモデルが、完全に同一のサンプル群を使って学習・評価されることが保証されます。 もしこの処理を怠ると、モデルごとに使用するデータ数が異なってしまい、性能の公平な比較ができなくなります。

ステップ4: 重要な物理記述子を選択 (A-Selected)

「次元の呪い」という理論的課題に対する、実践的な最初の解決策が特徴量選択です。132個という大量の記述子の中から、本当に予測に役立つ「宝石」だけを選び出します。

# ===================================================================
# 4. 重要な物理記述子を選択 (A-Selected)
# ===================================================================
print("\nステップ4: 重要な物理記述子を選択します...")
# 全物理記述子で一度モデルを学習
temp_model = CatBoostRegressor(random_seed=42, verbose=0)
temp_model.fit(X_phys_all, y)
importances = temp_model.get_feature_importance()
# 上位15個を選択
top_n = 15
top_indices = np.argsort(importances)[::-1][:top_n]
top_features = X_phys_all.columns[top_indices]
X_phys_selected = X_phys_all[top_features]
print(f"上位{top_n}個の物理記述子を選択しました。")
print("完了しました。")
  • モデル自身を「評価者」として利用する
    • temp_model.fit(X_phys_all, y): ここでは、予測モデル(CatBoost)を、特徴量を評価するための「道具」として利用します。まず、132個すべての物理記述子を使って、一度モデルを学習させます。これにより、モデルはどの特徴量が予測に重要だったかを内部的に学習します。
    • importances = temp_model.get_feature_importance(): CatBoostのような決定木ベースのモデルは、学習後に各特徴量が予測にどれだけ貢献したかを「重要度」としてスコア化する機能を持っています。このスコアが高いほど、モデルが「この特徴量は予測の役に立った」と判断したことを意味します。
  • 貢献度上位の特徴量を抽出する
    • top_indices = np.argsort(importances)[::-1][:top_n]: このNumPyのコードは、重要度スコアが高い順に特徴量を並べ替えるための定石です。
      • np.argsort(importances): 重要度スコアを小さい順に並べ替えたときの、元の配列のインデックス(番号)を返します。
      • [::-1]: このスライス表記で、配列の順序を逆転させ、大きい順(=重要度が高い順)に並べ替えます。
      • [:top_n]: 先頭から top_n 個(この場合は15個)のインデックスだけを取り出します。
    • top_features = X_phys_all.columns[top_indices]: 取得した上位15個のインデックスを使い、元のデータフレームから対応する列名(特徴量名)を取得します。
    • X_phys_selected = X_phys_all[top_features]: 最後に、選び抜かれた15個の「エリート特徴量」だけで構成される、新しいデータフレームを作成します。これにより、ノイズを減らし、より少数精鋭の特徴量セット(A-Selected)が完成します。

ステップ5: 2つの新しい特徴量セットを生成

ベースとなる特徴量セット同士を組み合わせ、新たな仮説「元素含有率と物理記述子を組み合わせれば最強なのでは?」を検証するためのデータセットを準備します。

# ===================================================================
# 5. 2つの新しい特徴量セットを生成
# ===================================================================
print("\nステップ5: 2つの新しい特徴量セットを生成します...")
# --- 特徴量セット(C): 元素含有率 + 全物理記述子 ---
X_comp_all = pd.concat([X_elem, X_phys_all], axis=1)

# --- 特徴量セット(D): 元素含有率 + 選択物理記述子 ---
X_comp_selected = pd.concat([X_elem, X_phys_selected], axis=1)
print("完了しました。")
  • X_comp_all = pd.concat([X_elem, X_phys_all], axis=1):
    • pd.concat: Pandasの複数のデータフレームを連結するための強力な関数です。
    • axis=1: 「列方向(水平方向)に連結する」という指定です。これにより、X_elem(14特徴量)の右側に X_phys_all(132特徴量)が結合され、合計146特徴量を持つ巨大なデータフレームが作成されます。
  • X_comp_selected = pd.concat([X_elem, X_phys_selected], axis=1):
    • 同様に、元素含有率(14)と、先ほど選び抜いた選択物理記述子(15)を結合し、合計29特徴量のデータフレームを作成します。

ステップ6 & 7: evaluate_model 関数による公平な評価

科学的検証において最も重要な「再現性」と「公平性」を担保するための仕組みです。

# ===================================================================
# 6. 全5モデルの学習と評価を実行する関数を定義
# ===================================================================
def evaluate_model(X, y, model_name):
    print(f"\n--- {model_name} の評価 ---")
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=42
    )

    model = CatBoostRegressor(random_seed=42, verbose=0)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)

    r2 = r2_score(y_test, y_pred)
    mae = mean_absolute_error(y_test, y_pred)

    print(f"  特徴量数: {X.shape[1]}")
    print(f"  R2スコア: {r2:.4f}")
    print(f"  MAE: {mae:.2f} MPa")

    return r2, mae, model

# ===================================================================
# 7. 全5モデルの評価を実行
# ===================================================================
print("\nステップ7: 全5モデルの評価を開始します...")
results = {}

results["B: 元素含有率のみ"] = evaluate_model(X_elem, y, "モデルB: 元素含有率のみ")
results["A-All: 全物理記述子"] = evaluate_model(
    X_phys_all, y, "モデルA-All: 全物理記述子のみ"
)
results["A-Selected: 選択物理記述子"] = evaluate_model(
    X_phys_selected, y, "モデルA-Selected: 選択物理記述子のみ"
)
results["C: 含有率 + 全記述子"] = evaluate_model(
    X_comp_all, y, "モデルC: 含有率 + 全記述子"
)
results["D: 含有率 + 選択記述子"] = evaluate_model(
    X_comp_selected, y, "モデルD: 含有率 + 選択記述子"
)
  • 評価プロセスを関数に封じ込める
    • def evaluate_model(...): 5つの異なる特徴量セットに対して、全く同じ手順(データ分割→学習→予測→評価)を何度も繰り返す必要があります。この一連のプロセスを一つの関数にまとめることで、コードの重複をなくし、たった一度の修正で全てのモデルの評価方法を変更できるなど、メンテナンス性が飛躍的に向上します。何よりも、「すべてのモデルが全く同じ条件で評価されている」という信頼性を保証します。
  • random_state=42 の重要性
    • train_test_splitCatBoostRegressor の両方で random_state を固定していることが、この実験の科学的な正当性を支える最後の砦です。
    • train_test_splitrandom_state : これを固定することで、5つのモデルすべてが、全く同じ訓練データで学習し、全く同じテストデータで評価されることになります。もしこれがなければ、偶然「簡単なテストデータ」が割り振られたモデルのスコアが高く出てしまうなど、運の要素が結果を左右してしまい、特徴量の優劣を正しく比較できません。
    • この関数のおかげで、我々は自信を持って「各モデルの性能差は、純粋に特徴量セットの違いだけに起因する」と結論付けることができるのです。
  • 結果の集約
    • results[model_name] = evaluate_model(...): ループ処理の中で、evaluate_model 関数を各特徴量セットに対して実行し、その返り値(R²スコア、MAE、学習済みモデル)を**results** という辞書に格納していきます。これにより、すべての実験結果が一箇所に整理され、最後の比較・考察が容易になります。

最後に

この5回にわたるシリーズを通じて、私たちはMIプロジェクトのリアルな姿を体験しました。仮説を立て、実験し、結果を考察し、次のアクションを決定するという、科学的な探求のプロセスそのものです。そして最終的に、「あらゆる改善策を試した結果、最初のシンプルなモデルが最良だった」という、データサイエンスの世界では頻繁に起こり得る結論に至りました。

この結果を受け入れ、次の戦略を立てることが科学者には求められます。もしこれが実際の研究プロジェクトであれば、次のアクションは以下のようになるでしょう。

  1. 最良モデルの採用: 現時点では、モデルB「元素含有率のみ」を最も信頼できるモデルとして採用します。
  2. さらなるチューニング: モデルBに対して、第4回で学んだOptunaによるハイパーパラメータチューニングを改めて実施し、性能をさらに引き出せないか試みます。
  3. 新たな特徴量の探求: 今回使用したmagpie以外の記述子や、全く異なるアプローチを試し、性能向上に寄与する特徴量を探す旅を続けます。

次回は、モデルの予測がどれほど確からしいのか、信頼区間を評価する技術に挑戦します。予測の「当たり外れ」だけでなく、「自信の度合い」まで評価することで、AIをより安全で信頼性の高いツールへと進化させていきましょう。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です