【入門】PythonでMatminerを動かしてみる

# Matminerとは？
Matminerは、材料ビッグデータを取得し、分析可能な形式に変換したり記述子(特徴量)を計算したりするための一連のツールを提供するPythonライブラリです。[以前の記事](https://qiita.com/k_t_09099/items/681ad83ac1c8f6c9592b)で紹介したPymatgenをベースにしており、材料データのワークフローを効率化することを目指して開発が進められています。

Matminerの主な特徴は以下の4点にあります。

### 1. **豊富なデータセットへのアクセス**
matminer.datasets モジュールには、ベンチマークとしてよく使われる材料物性のデータセットが組み込まれており、load_dataset 関数で簡単にロードできます。

### 2. 多様な記述子(特徴量)計算ツール (Featurizers)
matminer.featurizers モジュールには、**材料の様々な特性を表す記述子を計算するためのクラスが多数用意されています**。
    - 組成ベース: ElementProperty, Stoichiometry, YangSolidSolution など、化学組成から計算される記述子。
    - 構造ベース: SiteStatsFingerprint, StructuralHeterogeneity, BondFractions など、結晶構造や分子構造から計算される記述子。 
    - バンド構造・状態密度ベース: BandFeaturizer, DOSFeaturizer など。
その他、物性値から計算する記述子などもあります。

### 3. Pandas Dataframeとの親和性
matminerはデータの格納や操作のため Pandas DataFrame をベースにします。これにより、データのフィルタリング、集計、可視化など、Pandasの強力なデータ操作機能を活用できます。**記述子の計算もDataFrameに対して効率的に行うメソッド (featurize_dataframe) が提供されています**。

### 4. 機械学習ワークフローのサポート
計算された記述子は、scikit-learnなどの機械学習ライブラリと連携して物性予測モデルの構築などに利用できます。matminer自体は機械学習アルゴリズムを実装していませんが、その前段階であるデータ準備と特徴量エンジニアリングを簡単に行うことができるので、予測モデルの構築もスムーズに行うことが可能になります。


今回の記事では、Matminerの特徴や使い方をサンプルコードを交えながら紹介していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4006209/c11355cc-1c5b-4ecb-ad21-04dc175f5ae8.png)
> [Matminer公式サイト](https://hackingmaterials.lbl.gov/matminer/)より引用




# Matminerの使い方
## 実行環境
- Windows 11
- anaconda: 24.11.3
- python: 3.9
- jupyter notebook: 1.1

## インストール
まず、condaを使ってmatminerをインストールします。関連ライブラリも一緒にインストールされます。

```:コマンドプロンプト
conda install matminer
```

## データセットの読み込み
[Matminerのデータセットページ](https://hackingmaterials.lbl.gov/matminer/dataset_summary.html)を見ると、提供されているデータセットの一覧が公開されています。今回は材料の弾性率に関するデータセットである"**elastic_tensor_2015**"を使ってみます。

```python:python
from matminer.datasets import load_dataset
import pandas as pd

# データセットをロード (Pandas DataFrameとして返される)
df_elastic = load_dataset("elastic_tensor_2015")

# データの中身を確認
print(f"データセットの行数・列数: {df_elastic.shape}")
print("最初の5行:")
print(df_elastic.head())
print("\n主な列:")
print(df_elastic.columns)
```
これを実行すると、以下のような出力が得られます。

```:出力結果
データセットの行数・列数: (1181, 20)
最初の5行:
  material_id    formula  nsites  space_group      volume  \
0    mp-10003    Nb4CoSi      12          124  194.419802   
1    mp-10010  Al(CoSi)2       5          164   61.987320   
2    mp-10015       SiOs       2          221   25.952539   
3    mp-10021         Ga       4           63   76.721433   
4    mp-10025      SiRu2      12           62  160.300999   

                                           structure  elastic_anisotropy  \
0  [[0.94814328 2.07280467 2.5112    ] Nb, [5.273...            0.030688   
1  [[0. 0. 0.] Al, [1.96639263 1.13529553 0.75278...            0.266910   
2   [[1.480346 1.480346 1.480346] Si, [0. 0. 0.] Os]            0.756489   
3  [[0.         1.09045794 0.84078375] Ga, [0.   ...            2.376805   
4  [[1.0094265  4.24771709 2.9955487 ] Si, [3.028...            0.196930   

----------省略-----------
主な列:
Index(['material_id', 'formula', 'nsites', 'space_group', 'volume',
       'structure', 'elastic_anisotropy', 'G_Reuss', 'G_VRH', 'G_Voigt',
       'K_Reuss', 'K_VRH', 'K_Voigt', 'poisson_ratio', 'compliance_tensor',
       'elastic_tensor', 'elastic_tensor_original', 'cif', 'kpoint_density',
       'poscar'],
      dtype='object')
```

load_dataset関数を使うことで、データをpandas dataframeとして取り出すことができます。
データセットのサイズは1181で、全部で20個のカラムがあることが分かります。各カラムの意味を下の表にまとめました。このように、材料の弾性率に関わる様々な特性が格納されているようです。


| データフレームの列名      | 列の意味                                                                                                | データ型                      |
|---------------------------|---------------------------------------------------------------------------------------------------------|---------------------------------------|
| `material_id`           | Materials Projectデータベースにおける材料固有の識別子（例: "mp-1234"）                                      | `文字列 (String)`                   |
| `formula`               | 材料の化学組成式（例: "NaCl", "Si"）                                                                    | `文字列 (String)`                   |
| `nsites`                | 単位胞（unit cell）に含まれる原子（サイト）の総数                                                         | `整数 (int64)`                      |
| `space_group`           | 材料の結晶構造が属する空間群（space group）の番号 (1〜230)                                               | `整数 (int64)`                      |
| `volume`                | 単位胞の体積 (Å³)                                                                                       | `浮動小数点数 (float64)`            |
| `structure`             | 材料の結晶構造情報（格子定数、原子座標など）                                                                | `Pymatgen Structure オブジェクト`      |
| `elastic_anisotropy`    | 弾性異方性（elastic anisotropy）の指標（Universal anisotropy index, A^U）。0に近いほど等方的。               | `浮動小数点数 (float64)`            |
| `G_Reuss`               | ロイス（Reuss）平均を用いて計算された多結晶体の **せん断弾性率** (shear modulus) (GPa)。下限値を与える。       | `浮動小数点数 (float64)`            |
| `G_VRH`                 | Voigt-Reuss-Hill (VRH) 平均を用いて計算された多結晶体の **せん断弾性率** (GPa)。一般的な近似値。            | `浮動小数点数 (float64)`            |
| `G_Voigt`               | フォークト（Voigt）平均を用いて計算された多結晶体の **せん断弾性率** (GPa)。上限値を与える。                 | `浮動小数点数 (float64)`            |
| `K_Reuss`               | ロイス（Reuss）平均を用いて計算された多結晶体の **体積弾性率** (bulk modulus) (GPa)。下限値を与える。        | `浮動小数点数 (float64)`            |
| `K_VRH`                 | Voigt-Reuss-Hill (VRH) 平均を用いて計算された多結晶体の **体積弾性率** (GPa)。一般的な近似値。            | `浮動小数点数 (float64)`            |
| `K_Voigt`               | フォークト（Voigt）平均を用いて計算された多結晶体の **体積弾性率** (GPa)。上限値を与える。                 | `浮動小数点数 (float64)`            |
| `poisson_ratio`         | ポアソン比（Poisson's ratio）。無次元量。通常 `K_VRH` と `G_VRH` から計算される。                        | `浮動小数点数 (float64)`            |
| `compliance_tensor`     | コンプライアンステンソル (Compliance Tensor)。応力に対するひずみの応答 ((GPa)⁻¹)。                        | `リストのリスト (6x6数値行列)`      |
| `elastic_tensor`        | 弾性（剛性）テンソル (Elastic/Stiffness Tensor)。ひずみに対する応力の応答 (GPa)。                          | `リストのリスト (6x6数値行列)`      |
| `elastic_tensor_original` | 元計算から得られた弾性テンソル（多くの場合 `elastic_tensor` と同様）。                                       | `リストのリスト (6x6数値行列)`      |
| `cif`                   | CIF (Crystallographic Information File) フォーマットで記述された結晶構造データ。                             | `文字列 (String)`                   |
| `kpoint_density`        | 弾性特性計算に用いられた第一原理計算（DFT）におけるk点サンプリングの密度 (Å⁻³)。計算精度に関わる。         | `整数 (int64)`                      |
| `poscar`                | VASP POSCARファイル形式で記述された結晶構造データ。                                                       | `文字列 (String)`                   |

## 記述子(特徴量)の計算
### 前処理
特徴量を算出する前に前処理を行います。具体的には、composition(組成)列をデータフレームに追加します。

```python:python
from matminer.datasets import load_dataset
from matminer.featurizers.composition import ElementProperty
from pymatgen.core import Composition # 化学式からCompositionオブジェクトを作成するために必要
import pandas as pd

# データセットをロード
df_elastic = load_dataset("elastic_tensor_2015")

# 'formula' 列から Pymatgen の Composition オブジェクトを作成し、新しい列 'composition' として追加
# (注意: データセットによっては最初から 'composition' 列が存在する場合もあります)
#      'structure' 列から組成を得ることも可能です。
# df_elastic['composition'] = df_elastic['structure'].apply(lambda s: s.composition)
# ここでは 'formula' から作成します。

df_elastic['composition'] = df_elastic['formula'].apply(Composition)
```

### ElementPropertyクラスの初期化と計算
組成から計算される記述子を追加してみましょう。ここでは、元素の物性値（原子番号、電気陰性度など）の平均や標準偏差などを計算するElementProperty 記述子を使います。今回は"magpie"というプリセットを使って特徴量を生成します。詳しく調べ切れてはいませんが、他にも“deml”, “matminer”, “matscholar_el”, “megnet_el”などのプリセットが存在するようです。

```python:python
# ElementProperty 記述子計算クラスを初期化
# "magpie" プリセットを使うと、多くの一般的な元素特性に基づいた記述子が計算される
ep_featurizer = ElementProperty.from_preset("magpie")

# DataFrame に記述子を追加 (col_id で Composition オブジェクトが含まれる列を指定)
# ignore_errors=True にすると、一部の組成で計算エラーが起きても処理を続行する
df_elastic_featured = ep_featurizer.featurize_dataframe(df_elastic, col_id="composition", ignore_errors=True)

# 追加された記述子を確認
print("\n記述子計算後の行数・列数:", df_elastic_featured.shape)
print("追加された列の例:")
added_cols = set(df_elastic_featured.columns) - set(df_elastic.columns)
print(list(added_cols)[:10]) # 最初の10個を表示
```

すると、以下のような出力が得られます。

```:出力結果
記述子計算後の行数・列数: (1181, 153)
追加された列の例:
['MagpieData minimum NpValence', 'MagpieData mean Electronegativity', 'MagpieData mean Column', 'MagpieData mode Column', 'MagpieData range GSbandgap', 'MagpieData range NValence', 'MagpieData range Number', 'MagpieData mode NdValence', 'MagpieData minimum Number', 'MagpieData mode Row']
```
元の特徴量の数が20個だったので、**133個もの新しい特徴量が生成されていることが分かります**。これを自動でできるのはありがたいですね。


## 簡単な分析と可視化
追加した記述子と、元々あった物性値（例: 体積弾性率 K_VRH）の関係を可視化してみましょう。ここでは、MatplotlibとSeabornを使います。今回は平均融点 (MagpieData mean MeltingT。構成元素の融点の平均)と平均電気陰性度 (MagpieData mean Electronegativity。構成元素の電気陰性度の平均)との関係を可視化してみます。

```python:python
import matplotlib.pyplot as plt
import seaborn as sns
# (前のステップで df_elastic_featured が作成されている前提)

# 例: 平均融点 (MagpieData mean MeltingT) と 体積弾性率 (K_VRH) の散布図
plt.figure(figsize=(8, 6))
sns.scatterplot(data=df_elastic_featured, x="MagpieData mean MeltingT", y="K_VRH", alpha=0.5) # alphaで透明度調整
plt.xlabel("MagpieData mean MeltingT (Magpie Descriptor)")
plt.ylabel("Bulk Modulus (K_VRH, GPa)")
plt.title("Relationship between MagpieData mean MeltingT and Bulk Modulus")
plt.grid(True)
plt.show()

# 例: 平均電気陰性度 (MagpieData mean Electronegativity) と 体積弾性率 (K_VRH) の散布図
plt.figure(figsize=(8, 6))
sns.scatterplot(data=df_elastic_featured, x="MagpieData mean Electronegativity", y="K_VRH", alpha=0.5)
plt.xlabel("Mean Electronegativity (Magpie Descriptor)")
plt.ylabel("Bulk Modulus (K_VRH, GPa)")
plt.title("Relationship between Mean Electronegativity and Bulk Modulus")
plt.grid(True)
plt.show()
```

このコードを実行すると、以下のようなグラフが表示されます。平均融点の方は体積弾性率と明確な相関がありそうです。このように、matminerで膨大な特徴量を計算することで、データ分析を行ったり予測モデルを作っていくことが容易になり、新しい材料の物性を予測したり、特定の特性を持つ材料を探索したりする第一歩にできそうですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4006209/cc655dc6-a923-42f9-9601-9b90c43620ab.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4006209/6dbe8538-56f7-4c12-bebb-e62d6490304e.png)


# まとめ
今回はMaminerのインストールから簡単な分析までを行いました。たった数行のコードでデータセットの取得から特徴量を生成まで簡単にできるので、データ分析が捗りそうですね。まだまだ調べ切れていない部分もありますので今後も調査していきたいと思います。最後まで読んでくださりありがとうございました。

# 参考文献
- [Matminer](https://hackingmaterials.lbl.gov/matminer/)
- [Materials Project](https://next-gen.materialsproject.org/)