【Python】機械学習でワインの品質を判定する

 

この記事では、ワインのデータ(アルコール度数、pH、酸性度…)を学習して品質を判定するコードを書いてみたいと思います。

 

「機械学習の使い方を学びたい」

「Pythonで機械学習のコードを書いてみたい」

 

そんな方に読んでいただければと思います。

 

[toc]

使用するデータ

 

UCI Machine Learning Repositoryという機械学習向けデータセットを無料で公開しているサイトがあります。

 

このサイトの白ワインのデータセット(winequality-white.csv)を使ってみます。

 

https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/

 

CSVのカラムをみてみましょう。

 

import pandas as pd

df = pd.read_csv("data/winequality-white.csv",sep=";",encoding="utf-8")
print(df.columns)

 

Index(['fixed acidity', 'volatile acidity', 'citric acid', 'residual sugar',
       'chlorides', 'free sulfur dioxide', 'total sulfur dioxide', 'density',
       'pH', 'sulphates', 'alcohol', 'quality'],
      dtype='object')

 

酸性度(fixed acidity)や揮発性酸度(volatile acidity)などのワインのデータが11個あり、最後のカラムに品質(quality)があることが分かります。

 

品質は0〜10で評価されており、数字が高いほど良いです。

 

SVM(サポートベクターマシン)を使う

 

まずは、データのクラス分類に有効なSVMのLinearSVCを使ってみます。

 

コードの流れは以下の通り。

 

  1. pandasでデータを読み込み、データとラベルに分割する。
  2. 訓練用とテスト用にデータを分ける
  3. 学習する
  4. 予測する

 

from sklearn.model_selection import train_test_split
from sklearn import datasets,svm,metrics
from sklearn.metrics import accuracy_score
import pandas as pd

df = pd.read_csv("data/winequality-white.csv",sep=";",encoding="utf-8")

y = df['quality']
x = df.drop(columns='quality')

# データを学習用とテスト用に分割する
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2)

# データを学習
clf = svm.LinearSVC()
clf.fit(x_train, y_train)

# 予測して精度を確認する
y_pred = clf.predict(x_test)
print(accuracy_score(y_test, y_pred))

 

0.36428571428571427

 

あまり精度はよくありませんね。

 

ランダムフォレストを使う

 

では、複数の分類器を使って精度を向上させるランダムフォレスト(Random Forests)という手法を使ってみます。

 

コードの流れは全く同じで、学習器の指定の部分だけ違っています。

 

from sklearn.model_selection import train_test_split
from sklearn import metrics
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score,classification_report
import pandas as pd

df = pd.read_csv("data/winequality-white.csv",sep=";",encoding="utf-8")

y = df['quality']
x = df.drop(columns='quality')

# データを学習用とテスト用に分割する
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2)

# データを学習
clf = RandomForestClassifier()
clf.fit(x_train, y_train)

# 予測して精度を確認する
y_pred = clf.predict(x_test)
print(accuracy_score(y_test, y_pred))

 

0.6428571428571429

/home/matsu/anaconda3/envs/digits/lib/python3.6/site-packages/sklearn/metrics/classification.py:1135: 
UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in
 labels with no predicted samples.'precision', 'predicted', average, warn_for)

 

精度は大幅に改善したようです。さすがランダムフォレスト。

 

ただし、よく見るとワーニング「UndefinedMetricWarning」が出ています。これは全てのラベルにデータが分類されていないという意味です。

 

pandasのgroupbyを使って、それぞれの品質(quality)の数を数えてみます。

 

import pandas as pd

df = pd.read_csv("data/winequality-white.csv",sep=";",encoding="utf-8")

count_data = df.groupby('quality')['quality'].count()

print(count_data)

 

quality
3      20
4     163
5    1457
6    2198
7     880
8     175
9       5

 

11段階の評価と言いつつ、3から9しかありませんしデータが偏っています。これを不均衡データと言います。

 

ラベルを振り直す

 

ラベルを3つにして再度学習してみます。品質が4以下は0(悪い)、5〜7は1(普通)、8以上は2(良い)とラベルを振り直してみます。

 

import pandas as pd

df = pd.read_csv("data/winequality-white.csv",sep=";",encoding="utf-8")

y = df['quality']

new_y = []

for d in y:
    if d <= 4:
        new_y.append(0)
    elif d <= 7:
        new_y.append(1)
    elif d <= 9:
        new_y.append(2)

 

新しいラベルデータ(new_y)を使って、以下のように学習、判定してみます。

 

# データを学習用とテスト用に分割する
x_train,x_test,y_train,y_test = train_test_split(x,new_y,test_size=0.2)

# データを学習
clf = RandomForestClassifier()
clf.fit(x_train, y_train)

# 予測して精度を確認する
y_pred = clf.predict(x_test)
print(accuracy_score(y_test, y_pred))

 

0.926530612244898

 

かなり精度が向上しました。

 

学習アルゴリズムやパラメータを変更する方法の他に、ラベルを振り直す方法を学びました。かなり有効なので、覚えておきたいですね。

 

参考

ABOUTこの記事をかいた人

個人アプリ開発者。Python、Swift、Unityのことを発信します。月間2.5万PVブログ運営。 Twitter:@yamagablog