Pythonを用いた乳がんデータセットの分析と予測


## はじめに
乳がんは、世界中の女性にとって大きな問題となっており、早期発見が重要な要素です。  
データから乳がんの診断を精度高く行うことができれば、診断の主観性の排除やコスト削減等のメリットがあります。
本記事では、乳がんデータセットを用いたデータ分析の一例について説明します。

## 概要
scikit-learn付属の乳がんのデータセットを使って、機械学習の教師あり（分類）を行います。  
分析は、以下の手順で進めます。

1. ライブラリの読み込み
2. データセットの確認
3. 複数のアルゴリズムを用いた精度比較
4. パラメータチューニングによる精度向上の検証


## ライブラリの読み込み
今回比較に使用するモデルは、いずれも[scikit-learn](https://scikit-learn.org/stable/)で提供されています。
いずれのパッケージもPyPIで公開されており、簡単にインストールすることが可能です。
```python
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
import optuna
import matplotlib.pyplot as plt
import seaborn as sns
```


## データセットの確認

scikit-learnが公開しているデータは、`sklearn.datasets`のメソッドを使って読み込むことができます。
今回使用する乳がんのデータセットは、ウィスコンシン大学の乳がん診断データセット(Wisconsin Diagnostic Breast Cancer, WDBC)と呼ばれています（[参照](https://archive.ics.uci.edu/ml/datasets/breast+cancer+wisconsin+(diagnostic))）。
このデータセットは、乳がんの診断に関連する特徴量を持つ患者のデータを含んでいます。

```python
# データの読み込み
data_breast_cancer = load_breast_cancer()

df_target = pd.DataFrame(data_breast_cancer["target"], columns=["target"])
df_data = pd.DataFrame(data_breast_cancer["data"], columns=data_breast_cancer["feature_names"])
```

特徴量のデータ型を確認します。

```python
# 各columnのデータ型を表示
print(f'{df_data.dtypes} \n')
```
![](https://hackmd.io/_uploads/r1jIlEc4h.png)

本データに含まれる特徴量は、いずれも連続値であることがわかります。
次に、統計量を確認します。

```python
# データにおける、数値データの統計量を表示
display(df_data.describe())
```
![](https://hackmd.io/_uploads/Sknr0Q9Eh.png)



続いて、各特徴量の分布及び相関を確認します。
```python
# 特徴量の名前の取得
feature_names = data_breast_cancer.feature_names

# 特徴量の分布を可視化
plt.figure(figsize=(12, 24))
for i, feature in enumerate(feature_names):
    plt.subplot(10, 3, i + 1)
    sns.histplot(df_data[feature], kde=True)
    plt.title(feature)
plt.tight_layout()
plt.show()
```
![](https://hackmd.io/_uploads/r1zczE5V3.png)


```python
# 特徴量間の相関を可視化
plt.figure(figsize=(10, 8))
sns.heatmap(df_data.corr(), cmap='coolwarm')
plt.title('Feature Correlation')
plt.show()
```

![](https://hackmd.io/_uploads/SkoCgw942.png)



## 予測モデルの構築
ロジスティック回帰、サポートベクターマシン（SVM）、ランダムフォレストのモデルの精度を比較します。

```python
X = data_breast_cancer.data
y = data_breast_cancer.target

# データを訓練用とテスト用に分割
X_train, X_test, y_train, y_test = train_test_split(df_data, df_target, test_size=0.3, random_state=1)

# 特徴量の正規化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# ロジスティック回帰
log_reg = LogisticRegression(random_state=1)
log_reg.fit(X_train, y_train)
log_reg_acc = cross_val_score(log_reg, X_train, y_train, cv=5).mean()

# サポートベクターマシン
svc = SVC(kernel='linear', C=1, random_state=1)
svc.fit(X_train, y_train)
svc_acc = cross_val_score(svc, X_train, y_train, cv=5).mean()

# ランダムフォレスト
rand_forest = RandomForestClassifier(random_state=1)
rand_forest.fit(X_train, y_train)
rand_forest_acc = cross_val_score(rand_forest, X_train, y_train, cv=5).mean()

print("Logistic Regression Accuracy: {:.2f}%".format(log_reg_acc * 100))
print("SVM Accuracy: {:.2f}%".format(svc_acc * 100))
print("Random Forest Accuracy: {:.2f}%".format(rand_forest_acc * 100))
```

![](https://hackmd.io/_uploads/H1zkid943.png)


## Optunaによるパラメータチューニング
続いて、Optunaを用いてパラメータ最適化を行います。
Optunaを使うと、ベイズ最適化により、定義したハイパーパラメーターの範囲から最適なパラメータの組み合わせを探索することができます。


### SVM

```python
def objective_svm(trial):
    C = trial.suggest_loguniform('C', 1e-10, 1e10)
    gamma = trial.suggest_loguniform('gamma', 1e-10, 1e10)
    kernel = trial.suggest_categorical('kernel', ['linear', 'rbf', 'sigmoid'])
    clf = SVC(C=C, gamma=gamma, kernel=kernel)
    return cross_val_score(clf, X_train, y_train, 
                           n_jobs=-1, cv=5).mean()

study_svm = optuna.create_study(direction='maximize')
study_svm.optimize(objective_svm, n_trials=100)

best_params_svm = study_svm.best_params
best_accuracy_svm = study_svm.best_value

print("Best Parameters (SVM):", best_params_svm)
print("Best Accuracy (SVM):", best_accuracy_svm)

# Best Parameters (SVM): {'C': 1.2980731009141622, 'gamma': 0.00045010691978746915, 'kernel': 'linear'}
# Best Accuracy (SVM): 0.9824050632911392
```
![](https://hackmd.io/_uploads/Hk9Y-_cV2.png)


### Logistic Regression
```python
def objective_logreg(trial):
    C = trial.suggest_loguniform('C', 1e-10, 1e10)
    max_iter = trial.suggest_int('max_iter', 100, 1000)
    clf = LogisticRegression(C=C, max_iter=max_iter)
    return cross_val_score(clf, X_train, y_train, 
                           n_jobs=-1, cv=5).mean()

study_logreg = optuna.create_study(direction='maximize')
study_logreg.optimize(objective_logreg, n_trials=100)

best_params_logreg = study_logreg.best_params
best_accuracy_logreg = study_logreg.best_value

print("Best Parameters (Logistic Regression):", best_params_logreg)
print("Best Accuracy (Logistic Regression):", best_accuracy_logreg)
```

![](https://hackmd.io/_uploads/r1c_-d5V2.png)

## Random Forest
```python
def objective_rf(trial):
    n_estimators = trial.suggest_int('n_estimators', 100, 1000)
    max_depth = trial.suggest_int('max_depth', 5, 15)
    min_samples_split = trial.suggest_int('min_samples_split', 2, 10)
    random_state = trial.suggest_int('random_state', 0, 42)
    clf = RandomForestClassifier(n_estimators=n_estimators, max_depth=max_depth,
                                min_samples_split=min_samples_split, random_state=random_state)
    return cross_val_score(clf, X_train, y_train, 
                           n_jobs=-1, cv=5).mean()

study_rf = optuna.create_study(direction='maximize')
study_rf.optimize(objective_rf, n_trials=100)

best_params_rf = study_rf.best_params
best_accuracy_rf = study_rf.best_value

print("Best Parameters (Random Forest):", best_params_rf)
print("Best Accuracy (Random Forest):", best_accuracy_rf)
```

![](https://hackmd.io/_uploads/SyFUbdcE3.png)



# まとめ
精度評価を行った結果を表にまとめます。

| アルゴリズム | Accuracy（パラメータチューニング無し） | Accuracy（パラメータチューニングあり） |
|-----|-----|-----|
| SVM | 0.9799 | **0.9824** |
| Logistic Regression | 0.9699 | 0.9774 |
| Random Forest | 0.9548 | 0.9623 |

アルゴリズムの中では、パラメータチューニングありのSVMが最も高い精度で乳がん患者を予測することができていました。
また、いずれのアルゴリズムにおいても、Optunaによるパラメータチューニングにより、Accuracyが向上することがわかりました。