PHPでアヤメの分類（機械学習）【PHP-ML】

# きっかけ
普段はPHPで開発をしているのですが、以前から機械学習に興味がありPythonの勉強をしてみたりしていました。
機械学習・AI=Pythonという考えがあったのですが、ふとPHPで機械学習のライブラリがあるということを聞き使って見ることにしました。
# ライブラリのインストール
PHP-MLというライブラリを使います。
[PHP-ML - Machine Learning library for PHP](https://php-ml.readthedocs.io/en/latest/)
composerでインストールします。

```
composer require php-ai/php-ml
```
# 実践
早速コードを書いていきます。
予めサンプルデータが何個か用意されていました。
今回は機械学習の定番中の定番、**アヤメの分類**をやってみようと思います。
**k近傍法**という手法を用いて学習をさせていきます。
機械学習の手法については下記の記事が参考になると思います。
[機械学習の手法13選 ー 初級者、中級者別に解説！](https://ainow.ai/2020/06/04/222969/)

### データの準備
データが用意されていると言ってもそのまま使用できるわけではありません。
そのため、学習させるためにデータを加工してあげる必要があります。（機械学習はこれが一番大変らしい）


```php
// 学習データ120,テストデータ30(8:2)
// 学習させるためのデータと学習させた物のテストをするためのデータに分ける
const LERNING_NUM = 120;
const TEST_NUM = 30;

// データ取得
$dataset = new IrisDataset();
$samples = $dataset->getSamples();
$targets = $dataset->getTargets();

// データを加工
// ラベルと数値データが別々の配列になっているので、同じ配列にする
for ($i=0; $i < count($samples); $i++) { 
    $processedData[] = [
        'label' => $targets[$i],
        $columns[0] => (float)$samples[$i][0],
        $columns[1] => (float)$samples[$i][1],
        $columns[2] => (float)$samples[$i][2],
        $columns[3] => (float)$samples[$i][3],
    ];
}
// 同じ種類のデータで固まっているのでシャッフル
shuffle($processedData);

// 学習用データとテストデータを分割
$splitDatas = array_chunk($processedData, LERNING_NUM);

// 学習用データ
for ($i=0; $i < LERNING_NUM; $i++) {
    $learningSamples[] = [
        $splitDatas[0][$i]['sepal_length'],
        $splitDatas[0][$i]['sepal_width'],
        $splitDatas[0][$i]['petal_length'],
        $splitDatas[0][$i]['petal_width'],
    ];
    $learningTargets[] = $splitDatas[0][$i]['label'];
}

// テスト用データ
for ($i=0; $i < TEST_NUM; $i++) {
    $testSamples[] = [
        $splitDatas[1][$i]['sepal_length'],
        $splitDatas[1][$i]['sepal_width'],
        $splitDatas[1][$i]['petal_length'],
        $splitDatas[1][$i]['petal_width'],
    ];
    $testTargets[] = $splitDatas[1][$i]['label'];
    ;
}
```

### 学習
学習に必要なコードはこれだけです。
先ほど加工したデータを渡してあげるだけ。（楽ちん）

```php
$classifier = new KNearestNeighbors();
$classifier->train($learningSamples, $learningTargets);
```

### テスト
実際にしっかり分類できるのかをテストします。

```php
$results = $classifier->predict($testSamples);
```

### 答え合わせ
ちゃんと答え合わせもしてみます。

```php
$correctResult = 0;
// 正答数抽出
foreach ($results as $key => $result) {
    // 正答数
    if ($result === $testTargets[$key]) {
        $correctResult++;
    }
}
 
echo '正答率は' . ($correctResult/TEST_NUM)*100 . '%です。' . "\n";
```

### 出力結果
```
正答率は96.666666666667%です。
```
なかなか優秀ですね。。
ちなみに実行するたびに結果が少し変わります。

```
// 2回目
正答率は90%です。
// 3回目
正答率93.333333333333%です。
.
.
```
10回ほど実行して９０%は超えてくるので良しとしましょう。

### コード
全体のコードはこんな感じです。

```php:Iris.php
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Phpml\Dataset\Demo\IrisDataset;
use Phpml\Classification\KNearestNeighbors;

// 学習データ120,テストデータ30(8:2)
const LERNING_NUM = 120;
const TEST_NUM = 30;

// データ取得
$dataset = new IrisDataset();
$samples = $dataset->getSamples();
$targets = $dataset->getTargets();

// データを加工
for ($i=0; $i < count($samples); $i++) { 
    $processedData[] = [
        'label' => $targets[$i],
        $columns[0] => (float)$samples[$i][0],
        $columns[1] => (float)$samples[$i][1],
        $columns[2] => (float)$samples[$i][2],
        $columns[3] => (float)$samples[$i][3],
    ];
}
// データをシャッフル
shuffle($processedData);

// 学習用データとテストデータを分割
$splitDatas = array_chunk($processedData, LERNING_NUM);

// 学習用データ
for ($i=0; $i < LERNING_NUM; $i++) {
    $learningSamples[] = [
        $splitDatas[0][$i]['sepal_length'],
        $splitDatas[0][$i]['sepal_width'],
        $splitDatas[0][$i]['petal_length'],
        $splitDatas[0][$i]['petal_width'],
    ];
    $learningTargets[] = $splitDatas[0][$i]['label'];
}

// テスト用データ
for ($i=0; $i < TEST_NUM; $i++) {
    $testSamples[] = [
        $splitDatas[1][$i]['sepal_length'],
        $splitDatas[1][$i]['sepal_width'],
        $splitDatas[1][$i]['petal_length'],
        $splitDatas[1][$i]['petal_width'],
    ];
    $testTargets[] = $splitDatas[1][$i]['label'];
    ;
}
 
// 学習させる
$classifier = new KNearestNeighbors();
$classifier->train($learningSamples, $learningTargets);

// テスト
$results = $classifier->predict($testSamples);

$correctResult = 0;
// 正答率抽出
foreach ($results as $key => $result) {
    // 正答数
    if ($result === $testTargets[$key]) {
        $correctResult++;
    }
}

echo '正答率は' . ($correctResult/30)*100 . '%です。' . "\n";
```

# さいごに
PHPに機械学習のライブラリがあると聞いてやってみましたが、なかなか面白いですね。
もちろんPythonなどで使用できるライブラリと比べてしまうと劣ってしまうとは思いますが、お試し程度にできるのはいいですね。
まあ、本気で機械学習の勉強をしようと思ったらPythonを使用しますが。。。