Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

きっかけ

普段はPHPで開発をしているのですが、以前から機械学習に興味がありPythonの勉強をしてみたりしていました。
機械学習・AI=Pythonという考えがあったのですが、ふとPHPで機械学習のライブラリがあるということを聞き使って見ることにしました。

ライブラリのインストール

PHP-MLというライブラリを使います。
PHP-ML - Machine Learning library for PHP
composerでインストールします。

composer require php-ai/php-ml

実践

早速コードを書いていきます。
予めサンプルデータが何個か用意されていました。
今回は機械学習の定番中の定番、アヤメの分類をやってみようと思います。
k近傍法という手法を用いて学習をさせていきます。
機械学習の手法については下記の記事が参考になると思います。
機械学習の手法13選 ー 初級者、中級者別に解説!

データの準備

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

// 学習データ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/TEST_NUM)*100 . '%です。' . "\n";

出力結果

正答率は96.666666666667%です。

なかなか優秀ですね。。
ちなみに実行するたびに結果が少し変わります。

// 2回目
正答率は90%です。
// 3回目
正答率93.333333333333%です。
.
.

10回ほど実行して90%は超えてくるので良しとしましょう。

コード

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

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を使用しますが。。。

dip-net
ディップ株式会社は「バイトル」「はたらこねっと」などの求人情報サービスをはじめ、人工知能専門メディア「AINOW」、スタートアップ専門メディア「スタートアップタイムズ」、アニメなどの舞台を紹介するサイト「聖地巡礼マップ」といった新しい分野のサービスを自社で開発・運営しています。
https://www.dip-net.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away