アルコールとデータサイエンス -scikit-learn wine datasetの活用-

2021年10月14日
wine image

アルコールとデータサイエンス

皆さんは『データサイエンス』と聞いてどのようなことを思い浮かべるでしょうか?


近年の情報技術の向上によって得られた大量のデータと、高性能な計算機が開発されたことによる処理の能力によって、データの中から知見を引き出そうという流れが強まっています。その一連の営みのことを『データサイエンス』と呼びます。

今回から始まる、『アルコール×データサイエンス』のシリーズでは

  • アルコール飲料とデータサイエンスの関係性
  • 機械学習の大まかな分類とそれぞれの特徴
  • ユーグレナ先端技術研究課でのアルコール飲料におけるデータサイエンス研究の紹介

を三部作でお届けしたいと思います。今回は『アルコール飲料とデータサイエンス』についてお話しさせていただきます。

アルコール飲料とデータサイエンスにどのような関係があるのか?と疑問に思われる方も多いかもしれません。

しかしながら、長い間人類を魅了しているアルコール飲料を、もっと美味しいものにしたい!という考えのもと、近年そのような研究開発の重要性が高まっているという背景があります。

例えば、かの有名な『獺祭』を作っている旭酒造は、酒造りにデータサイエンスを取り入れたことで、高い品質の再現性と大量生産を確立しました。

――酒造りの中で、データをどのように活用していますか。酒造りは、伝統的に杜氏という職人文化によって支えられてきました。獺祭では杜氏がいない体制で酒造りをしており…
toyokeizai.net
獺祭の記事

酒造りは、伝統的に杜氏という職人文化によって支えられてきました。獺祭では杜氏がいない体制で酒造りをしており、優秀な杜氏がやっていたことを集団でやろうとしています。その中で、様々な形で酒造りの中でデータによる管理を行っています。

具体的に挙げると、洗米という米を水洗いする行程では、コメの重量、洗う時間、水温などをすべて数値で計測し、コメに鳩首される水分量を0.2%以下の精度で調整できるようにしています。その日の気温によって少しずつ状況は変わりますので、数値を記録しながらその日に最適な条件にできるようにしてます。

ほかにも、発酵の期間中には、さまざまなデータ(アルコール度数、日本酒度、糖度など)を毎日計測し、それぞれをすべて手書きでグラフにしています。毎日、その日に記録したデータから発行の進み具合を分析して、次の日の温度管理などを判断しています。獺祭では年間に900本当いう非常に多い本数の仕込みを行っていますので、繰り返しやっている中で「理想的な数値」がわかってきました

杜氏のいない「獺祭」、非常識経営の秘密

これもデータサイエンスであり、データを活用して物事の改善をした大変良い例であるといえます。

データサイエンスとアルコール飲料の取り組みはこれだけに限ったものではありません。データサイエンスのために使われるプログラミング言語でpythonというものがありますが、その中で公開されているライブラリにscikit-learnというものがあります。このライブラリを活用することによって、データサイエンスの一つの分野である機械学習を活用することができます。

アルコールとデータサイエンスの活用(サンプルコード)

本記事では、簡単にその中でテストデータセットとして公開されているwine datasetというものを使って、機械学習のさわりを見てみたいと思います。

Wine datasetはカルフォルニア大学アーバイン校によって公開されている、Machine Learning Repository で公開されているもので、scikit-learnを使うことによって簡単に活用することができます。この後のプログラムは、最後にリンクとしてgoogle colaboratoryで公開しますので、もし自分の環境で実行してみたい人はご自身のgoogle driveにコピーを作成して、活用してください。また、colaboratoryの説明は次をご覧ください。

colab.research.google.com

ではコードに入ります。まず最初にライブラリを読み込みます。ローカルの環境でやるといろいろ設定が必要ですが、colabではただ次のようなものを実行するだけで十分です。

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import sklearn

今回使ったpythonとそれぞれのライブラリバージョンは次のようになります。

!python --version
> Python 3.7.11

print('numpy  :', np.__version__)
print('pandas :', pd.__version__)
print('seaborn:', sns.__version__)
print('sklearn:', sklearn.__version__)
> numpy  : 1.19.5
> pandas : 1.1.5
> seaborn: 0.11.1
> sklearn: 0.22.2

データの確認・可視化

データセットを読み込みます。そしてデータセットのそれぞれの列の状況を確認しましょう。

from sklearn.datasets import load_wine
wine = load_wine()
df_x = pd.DataFrame(data=wine.data, columns=wine.feature_names)
df_x.info()

> RangeIndex: 178 entries, 0 to 177 
> Data columns (total 13 columns):
>  #    Column                        Non-Null Count Dtype
> ---  ------                         -------------- ----- 
> 0    alcohol                        178 non-null   float64
> 1    malic_acid                     178 non-null   float64
> 2    ash                            178 non-null   float64
> 3    alcalinity_of_ash              178 non-null   float64
> 4    magnesium                      178 non-null   float64
> 5    total_phenols                  178 non-null   float64
> 6    flavanoids                     178 non-null   float64
> 7    nonflavanoid_phenols           178 non-null   float64
> 8    proanthocyanins                178 non-null   float64
> 9    color_intensity                178 non-null   float64
> 10   hue                            178 non-null   float64
> 11   od280/od315_of_diluted_wines   178 non-null   float64
> 12   proline                        178 non-null   float64
> dtypes: float64(13) 
> memory usage: 18.2 KB

これでそれぞれの列の名前と数、データ型がわかります。また、nullがないことを確認することも重要です。もし欠損値があった場合には適切に処理する必要があります。
これ以外にもこれらのコードを実行すると、データを見ることができます。headで最初の5つのレコードが表示され、describeで記述統計量が表示されます。こういう基本的な確認はデータのイメージをつかむために重要です。出力は、ここでは省略させていただきます。

df_x.head()
df_x.describe()

次に各変数の相関を見てみましょう。もし仮に回帰分析をするときには、強い相関がある者同士を排除する必要があります。相関を見るためにはseabornのパッケージを使うと便利です。

plt.figure(figsize=[19,10])
sns.heatmap(df_x.corr(),annot=True)

色が明るいものと真っ黒いものは相関係数の絶対値が相対的に高いことを意味します。

ここで改めてWine datasetについて説明させていただくと、このデータセットは142種類のワインに対して物理的/化学的特徴を測定したもので、このワインたちは使われているブドウの品種で3種類に分類することができます。その3種類について、別々の色付けを各変数同士で散布図を書きます。すべての変数ですると多すぎてこのサイトに収まりきらないので、いくつか抽出したものを載せます。

data = pd.concat([df_x[['alcohol', 'malic_acid', 'flavanoids', 'proline']], df_y], axis=1)
sns.pairplot(data=data, hue='class', palette='tab10')

これを見ることによって、各変数だけでもグループ間に差異があることがわかったり、2つの変数を使うことによって、よりグループ間の傾向に差があることを確認することができることがわかります。

機械学習(決定木モデルの学習と評価)

基本的なデータの確認が済んだので、ここから機械学習を中でも決定木アルゴリズムを使った予測というものをしていきたいと思います。

決定木アルゴリズムとは何でしょうか?決定木アルゴリズムとは、多次元データをもとに目的変数を予測、分類るための木構造を持ったモデルのことを指します。

通常の回帰モデルと異なり、非線形な関係を抽出できる点において、ニューラルネットワークと同様に高い予測精度と汎化性能を持っていることが知られていますが、ニューラルネットワークよりも説明変数の取り扱いが柔軟にできます。またモデルの構築も用意です。

決定木モデルには、シンプルに一つの木構造をもつものもありますが、複数の違う木構造のモデルによってより高い予測精度と汎化性能を求めようとするものもあります。今回はその中でも大きなデータセットでも効率的に学習ができるLightGBMと呼ばれるライブラリを使って、決定木アルゴリズムでワインのデータを学習するコードを載せます。

import lightgbm as lgb
print('lightgbm:', lgb.__version__)
> lightgbm: 2.2.3

まずワインのデータセットを再読み込みして、LightGBM用に変換します。今後精度を検証するために、学習データとテストデータで分割します。テストデータに学習データと同じものが入っている場合、モデルの一般性(汎化性能)に問題が出てしまうので、検証のためにあらかじめ分けることが必要です。

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

#データの再読み込み
X1=load_wine()
df_1=pd.DataFrame(X1.data,columns=X1.feature_names)
Y_1=X1.target

#説明変数の正規化
sc_1=StandardScaler()
sc_1.fit(df_1)
X_1=pd.DataFrame(sc_1.fit_transform(df_1))

#学習データとテストデータの分割
X_train,X_test,y_train,y_test=train_test_split(X_1,Y_1,test_size=0.3,random_state=0)

#LightBGM用のデータセットに変換
d_train=lgb.Dataset(X_train, label=y_train)

これで、あとはモデルのインスタンスをつくり、パラメーターを設定してあげれば学習を始めることができます。パラメーターは、今回考えるタスクがどのようなものであるかによって適宜設定してあげる必要があります。今回は多クラス分類であるので、次のように設定しています。

#パラメーターの設定
params={}
params['learning_rate']=0.03
params['boosting_type']='gbdt'   #GradientBoostingDecisionTree
params['objective']='multiclass' #Multi-class target feature
params['metric']='multi_logloss' #metric for multi-class
params['max_depth']=10
params['num_class']=3  #no.of unique values in the target class not inclusive of the end value

これをもとに、次のコードで学習をすることができます。あらかじめ分けておいたテストデータで予測性能を評価します。

#学習
clf = lgb.train(params = params,train_set = d_train,num_boost_round = 100) 

#予測
y_pred = clf.predict(X_test)
y_pred = [np.argmax(line) for line in y_pred]

ただし、この予測スコアは3つのクラスの確率で表されていることから、それぞれのデータに対して最大の確率を示しているクラスを予測結果として扱うことが適切です。numpyのargmaxでそのような処理が書かれています。

多クラス分類の性能評価には混合行列に基づく評価を用います。それぞれの評価の意味はこちらでまとめられています。

#予測結果の評価
print('precision score:', precision_score(y_pred,y_test,average=None).mean())
print('accuracy score', accuracy_score(y_pred,y_test).mean())
> precision score: 0.9470588235294118
> accuracy score ; 0.9444444444444444

このように、テストデータでも高い予測精度をもつモデルの学習ができたことがわかります。

最後に

今回の記事では、アルコール飲料とデータサイエンスということで、wine datasetを用いたデータの可視化や購買決定木アルゴリズムの適応を紹介しました。

次回の記事では、機械学習ってどういうものがなのかという、全体像についてご紹介できればと考えています。最後までお付き合いいただきありがとうございました。今回のコードのリンクは下にあります。

colab.research.google.com
サンプルコード

<参考>

LightGBM is a gradient boosting framework that uses tree-based learning algorith…
nitin9809.medium.com