はじめての人向け機械学習【2017年度版】

キータ初心者です。
練習も兼ねて機械学習について書いてみます！

#1.はじめに
・2017年度版などと謳っておりますが内容は昔ながらのものです。
・私の技術レベルは低いです。間違った事が書いてあるかもしれません。
・環境作りも含めて1時間程度で完結する内容です。

#2.やること
入力された文章から春夏秋冬を判断して表示するウェブアプリケーションをPHPで作ります。
春夏秋冬それ自体は文章に入れずとも判断できるようになるのがミソです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/160607/056ea72f-9bdc-d9ec-1e62-fd6b2458c1e1.png)
↓
![image.png](https://qiita-image-store.s3.amazonaws.com/0/160607/eeb2f553-e24a-3307-3c94-4516ef058ba2.png)


比較的とっかかりやすい教師付き学習のベイジアンフィルタを使います。
[ベイジアンフィルタ -Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%99%E3%82%A4%E3%82%B8%E3%82%A2%E3%83%B3%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF)
簡単に言うとテキスト（教師データ）を読み込ませてそこからルールを抽出するものです。
確率論等の数学分野に突っ込みます。興味のある方は是非調べてみてください！

#3.環境構築
今回ベイジアンフィルタには[fieg/Bayes](https://packagist.org/packages/fieg/bayes)を使用します。
composerから開発フォルダにインストールしてください。

```
$ composer require fieg/bayes
```

PHPでの開発になりますのでXAMPP等で実行可能な環境を作ってください。

#4.コーディング
**今回作るものはライブラリを含め全て[ここ](https://github.com/XXXalice/fourSeasons)（Githubのリポジトリに飛びます）にあります。**
**面倒な方はこちらを利用していただければ幸いです。**

今回インストールしたライブラリでは

```php
$tokenizer = new Fieg\Bayes\Tokenizer\WhitespaceAndPunctuationTokenizer();//分割器
$classifier = new Fieg\Bayes\Classifier($tokenizer);//分類器
```

この二つを使っていきます。
$classifierから学習させたり実行したりすると考えていただければ大丈夫です。

```php
//学習
$classifier->train(ジャンル,単語もしくはスペースで区切られた文章);

//実行
$classifier->classify(判別対象);
```

これだけです。
train()ではジャンルに沿った単語及び単語の登場回数をカウントしていきます。
classify()では学習されたルールに沿って入力されたものを分類します。
単語間にスペースがある場合文章でもOKです。つまり日本語文章を入力したい場合は手を加える必要があります。
詳しく見たい方は是非ライブラリソースを読んでみてください！

前置きが長くなってしまいました。さっそくコーディングしていきましょう。
今回はそれぞれの季節をジャンルとして持たせ、それを連想させる単語を学習させていきます。
そのデータを詰めたファイルを作ります。

```php:data.php
<?php
    $spr = ['桜','暖かい','入学','卒業','花見','眠い','梅','新生活','花粉症'];
    $aug = ['暑い','蚊','海','山','夏休み','セミ','すいか','かき氷','扇風機','夏祭り'];
    $aut = ['紅葉','焼き芋','涼しい','読書','食欲','睡眠','サンマ','お月見','ハロウィン','栗'];
    $win = ['寒い','雪','正月','クリスマス','受験','大晦日','蟹','鍋','おでん','こたつ'];

    $fourSeasons = ['Spring'=>$spr,'August'=>$aug,'Autumn'=>$aut,'Winter'=>$win];
?>
```

もちろんそれぞれの配列にご自身が季節に沿って連想されるワードを加えていただいて構いません。
教師となるデータが完成したらメイン部分を書いていきます。

```php:index.php
<?php
    require_once 'vendor/autoload.php';
    require_once 'data.php';
    $tokenizer = new Fieg\Bayes\Tokenizer\WhitespaceAndPunctuationTokenizer();
    $classifier = new Fieg\Bayes\Classifier($tokenizer);

    //学習部分
    foreach($fourSeasons as $key => $season){
        foreach($season as $word){
            $classifier->train($key,$word);
        }
    }
    //学習部分終わり
```

学習部分の中ではジャンルを四季としそれぞれの配列内単語を学習していきます。
次はGUIとなる入力部分です。

```php:index.php
<!doctype html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <form method="post" action="">
            <p><label>文章を入力してください<input type="text" name="str" size="45">
            <input type="submit" value="実行"></label></p>
        </form>
    </body>
</html>
```

これをファイルの下の方に書いておいてください。
そして最後の判定部分です。

```php:index.php
//判定部分
    if(!empty($_POST["str"])){
        $json = json_decode(file_get_contents('http://yapi.ta2o.net/apis/mecapi.cgi?sentence='.urlencode($_POST["str"]).'&format=json'));
        foreach($json as $block){
            $sent[] = $block->surface;
        }
        $res = $classifier->classify(implode(' ',$sent));
        switch(array_keys($res,max($res))[0]){
            case 'Spring':$fres='春です';break;
            case 'August':$fres='夏です';break;
            case 'Autumn':$fres='秋です';break;
            case 'Winter':$fres='冬です';break;
            default:$fres='わかりませんでした';
        }
    }
    //判定部分終わり
```

判定部分では受け取った文章を形態素解析エンジンmecabのwebapiであるmecapiに掛け、解析結果のjsonファイルを貰います。
そのファイルから単語要素だけを抜き出し、implodeで単語ごとにスペースの空いたstringを作成します。
それをclassifyにかけ結果を受け取ります。
結果をvar_dumpすると分かりますが、最大1のfloat型数値を確率として持った配列になっています。
そこから最大確率のキーを取り出しswitchにかけ、季節を判別できるようにしてください。
入れ子となる$fresは最後にちょこっと追加します。

```php:index.php
//全体像

<?php

    require_once 'vendor/autoload.php';
    require_once 'data.php';
    $tokenizer = new Fieg\Bayes\Tokenizer\WhitespaceAndPunctuationTokenizer();
    $classifier = new Fieg\Bayes\Classifier($tokenizer);
    $fres = '';//追加しました！

    //学習部分
    foreach($fourSeasons as $key => $season){
        foreach($season as $word){
            $classifier->train($key,$word);
        }
    }
    //学習部分終わり

    //判定部分
    if(!empty($_POST["str"])){
        $json = json_decode(file_get_contents('http://yapi.ta2o.net/apis/mecapi.cgi?sentence='.urlencode($_POST["str"]).'&format=json'));
        foreach($json as $block){
            $sent[] = $block->surface;
        }
        $res = $classifier->classify(implode(' ',$sent));
        switch(array_keys($res,max($res))[0]){
            case 'Spring':$fres='春です';break;
            case 'August':$fres='夏です';break;
            case 'Autumn':$fres='秋です';break;
            case 'Winter':$fres='冬です';break;
            default:$fres='わかりませんでした';
        }
    }
    //判定部分終わり

?>
<!doctype html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <form method="post" action="">
            <p><label>文章を入力してください<input type="text" name="str" size="45">
            <input type="submit" value="実行"></label></p>
        </form>
            <p><?php echo $fres; ?></p> <!--追加しました！-->
    </body>
</html>
```

お疲れ様でした！これで動くようになると思います。
https://github.com/XXXalice/fourSeasons
#5.できたら
私は発想力に乏しく、考えに考えてあの単語量でした。
ご自身で単語を増やし（学習量を増やし）賢くしてみてください。
今回教師データには単語を使いましたが学習部分にも形態素解析を組み込めば日本語文章も学習できます。
もしそうする場合にはAPIではなく自前でインストールしたエンジンを用いるべきでしょう。

最後になりますが、ここまで読んでいただいてありがとうございました！