LoginSignup
6
11

More than 3 years have passed since last update.

【Python】Python/Scikit-learnで初めてのSVM

Last updated at Posted at 2020-11-16

はじめに

Pythonを触っていると機械学習のライブラリが豊富とはよく聞きます。
自分自身も存在は知っていましたが実際に自分で手を動かしてやったことがなかったです。
ただ、この記事を読んで簡単にできそう!と思ったのがきっかけで機械学習、特にSVM(Support Vector Machine)をやってみたので投稿します。

ここでは、天気のデータの取得からとても簡単なデータの処理、学習、可視化までを行います。

主に参考にしたのは以下の2つの記事です。
【Python】pythonで簡単に機械学習入門(SVM)
[python 機械学習初心者向け] scikit-learnでSVMを簡単に実装する

環境

Windows 10上のAnacondaで動かしています。

名前 バージョン
Python 3.7.3
Scikit-learn 0.23.1
Pandas 1.0.5
Numpy 1.18.5
matplotlib 3.2.2
mlxtend 0.17.3

それぞれ下記のようにpipでインストールできます。

$ pip install scikit-learn
$ pip isntall pandas
$ pip isntall numpy
$ pip install matplotlib
$ pip install mlxtend

対象読者

上に上げた2つの記事と同等レベルです。
- Python、NumpyやPandasを扱える
- 機械学習の存在くらいは知っている
- SVMの実装の一連の流れを知りたい

機械学習、SVMとは

ここでは詳しいことは省きます。参考の記事などを参考にしてください。

機械学習の分類とは、

分類
分類タスクでは、事前に定められた有限個のクラスが定められていて、各クラスには、「ネコ」、「イヌ」などのクラスラベル(もしくは単にラベル)と呼ばれるクラス名が割り振られている。分類タスクの目的は与えられた入力xがのいずれに属するかを当てる事である。
機械学習 分類 - Wikipedia

ここでは、機械学習で気温や降水量、雲量などのデータを使って、天気(ラベル)を当てます。

また、SVMとは以下になります。

サポートベクターマシン(英: support vector machine, SVM)は、教師あり学習を用いるパターン認識モデルの一つである。分類や回帰へ適用できる。
SVM - Wikipedia

流れ

ここでは、以下の流れに沿って説明します。
※コードだけみたいよ!って方はこちらです。
1. データの取得
2. データの加工
3. 学習
4. 可視化

1. データの取得

今回は天気のデータを扱うことにしたので気象庁のこのページからダウンロードしましょう。

地点、項目(気温や降水量など)、期間を選んでダウンロードしてください。気温や降水量などの項目は自由にダウンロードしてみてください。多い分には学習に使う際に取捨選択をすればいいので困らないと思います。data.csvという名前のcsvファイルがダウンロードできると思います。

※項目の、天気概況は絶対使うのでダウンロードしてください。

少し自分でやってみたところ、例えば2019年1年間のデータより2001年の10月-11月、2002年の10月-11月、2003年の10月-11月、、、の12か月のデータの方がうまく分類できるようです。(同じ時期のデータで学習した方がよさそうというのはなんとなくわかるかと思います)

2. データの加工

2-1 不要なデータの削除

ここから pandas等を使ってデータの加工をしていきます。
※説明が多くなるのですぐに試したいという方はこちら

ダウンロードしてきたファイルは1行目に
ダウンロードした時刻:2020/11/16 18:18:28
というデータがあるのでそれを避けて読み込むために header=2、また日本語を含むのでencoding="SHIFT-JIS"としています。

import numpy as np
import pandas as pd

#csvファイルの読み込み (data.csvはご自身のディレクトリ/ファイル名に合わせてください)
df = pd.read_csv("data.csv", header = 2,encoding="SHIFT-JIS")

この時点のdfは以下のようになっていると思います。
image.png

同じ列名があるので 「.1」等の列名が存在しています。これは0行目にある品質番号、均質番号などの列があるためだとわかります。今回はいらないので削除しましょう。
少々強引ですが以下のようにしました。欠損値がある行も削除しておきます。

# 0行目をdrop
df = df.drop(df.index[[0]])

# ".1", ".2", ".3" が列名の末尾についている列をdrop
df = df.drop(df.loc[:, df.columns.str.endswith(".1")], axis = 1)
df = df.drop(df.loc[:, df.columns.str.endswith(".2")], axis = 1)
df = df.drop(df.loc[:, df.columns.str.endswith(".3")], axis = 1)

# 欠損値がある行を削除
df = df.dropna(how='all')

これできれいになったと思います!
image.png

2-2 ラベルの整理

ここで、ラベル(天気概況)のユニーク数を見てみましょう。
自分のダウンロードしてきたデータはなんと64個でした。多すぎますね。

print(len(df["天気概況(昼:06時〜18時)"].unique().tolist()))

一部ですがこんな感じです。

['晴時々曇', '曇後一時雨', '曇', '晴後曇', '曇後雨', '晴後薄曇', '雨一時曇',
 '晴', '曇時々雨','曇一時晴', '雨', '曇後晴', '雨時々曇', '曇一時雨', '快晴',
 '雨後晴', '晴後一時曇', '薄曇','雨後一時晴', '雨後曇', '曇後一時晴',
'晴一時曇', '雨、雷を伴う', '晴後一時雨、雷を伴う', '大雨','曇一時雨後晴',
'曇一時霧', '薄曇一時晴', '曇時々晴', '雨後曇一時晴', '晴一時薄曇', '曇一時雨、雷を伴う']

今回は、分類を簡単にするために以下のような処置をしました。
①一文字目をとってくる。
②数値におきかえる

df["天気概況(昼:06時〜18時)"] = df["天気概況(昼:06時〜18時)"].str[:1]
df["天気No"] = df["天気概況(昼:06時〜18時)"].str.replace("曇","0").replace("晴", "1").replace("大", "3").replace("雨", "3").replace("薄", "0").replace("快", "1").replace("霧","0")

置き換えた数値と天気の一覧です。今回はとても簡略化しています。気に入らない方がいればもちろん自身で変えちゃってください。

天気(1文字目) 数値 元の表記
0 曇り(一時なんとか等)
0 薄曇(一時なんとか等)
0 霧(一時なんとか等)
1 快晴(一時なんとか等)
1 晴(一時なんとか等)
2 雨(一時なんとか等)
2 大雨(一時なんとか等)

3. 学習

いよいよ学習です。今回はしっかり学習ができて訓練データにも、未知のデータにも予測ができているかを検証するためtrain_test_splitという関数を使ってデータをトレーニングデータとテストデータに分けています。

学習自体はとても簡単で、

model.fit(x_train, y_train)

この行だけです。

from sklearn import svm
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 説明変数の格納
x = df.loc[1:, ["降水量の合計(mm)","平均雲量(10分比)"]]

#目的変数の格納
y = df.loc[1:,"天気No"].astype("int64")

# トレーニングデータとテストデータに分割。
# test_size=0.3 : テストデータは30%、トレーニングデータ:70%
# random_state=None:毎回異なるデータを生成
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=None )

# SVMを選択
model = svm.SVC()

# 学習
model.fit(x_train, y_train)

# トレーニングデータに対する精度
pred_train = model.predict(x_train)
accuracy_train = accuracy_score(y_train, pred_train)
print('トレーニングデータに対する正解率: %.2f' % accuracy_train)

# テストデータに対する精度
pred_test = model.predict(x_test)
accuracy_test = accuracy_score(y_test, pred_test)
print('テストデータに対する正解率: %.2f' % accuracy_test)

以下のように結果が出れば成功です!

トレーニングデータに対する正解率: 0.81
テストデータに対する正解率: 0.82

分類はmodel.predict()で行っているので、極論以下でも分類結果が返ってきますね。

model.predict([[1,1]])

4. 可視化

最後に可視化です。
plot_decision_regionsで決定境界の可視化を行います。
plot_decision_regionsも簡単に使うことができて、データとモデルを渡せば勝手にグラフを作ってくれます。
ただここで渡すxは2次元になります。結果のグラフのx,y軸にそれぞれが当てはまります。

# 決定境界の可視化
import matplotlib.pyplot as plt
from mlxtend.plotting import plot_decision_regions

x_combined = x_test.values
y_combined = y_test.values

fig = plt.figure(figsize=(13,8))
plot_decision_regions(x_combined, y_combined, clf=model,  res=0.02)
plt.show()

自分の場合は以下のような図が出ました。いけて、、、る?
image.png

コードの全体

import numpy as np
import pandas as pd
from sklearn import svm
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
from mlxtend.plotting import plot_decision_regions

#csvファイルの読み込み (data.csvはご自身のディレクトリ/ファイル名に合わせてください)
df = pd.read_csv("data.csv", header = 2,encoding="SHIFT-JIS")

# 0行目をdrop
df = df.drop(df.index[[0]])

# ".1", ".2", ".3" が列名の末尾についている列をdrop
df = df.drop(df.loc[:, df.columns.str.endswith(".1")], axis = 1)
df = df.drop(df.loc[:, df.columns.str.endswith(".2")], axis = 1)
df = df.drop(df.loc[:, df.columns.str.endswith(".3")], axis = 1)

# 欠損値がある行を削除
df = df.dropna(how='all')

# ラベルの処理
df["天気概況(昼:06時〜18時)"] = df["天気概況(昼:06時〜18時)"].str[:1]
df["天気No"] = df["天気概況(昼:06時〜18時)"].str.replace("曇","0").replace("晴", "1").replace("大", "3").replace("雨", "3").replace("薄", "0").replace("快", "1").replace("霧","0")

# 説明変数の格納
x = df.loc[1:, ["降水量の合計(mm)","平均雲量(10分比)"]]

#目的変数の格納
y = df.loc[1:,"天気No"].astype("int64")

# トレーニングデータとテストデータに分割。
# test_size=0.3 : テストデータは30%、トレーニングデータ:70%
# random_state=None:毎回異なるデータを生成
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=None )

# SVMを選択
model = svm.SVC()

# 学習
model.fit(x_train, y_train)

# トレーニングデータに対する精度
pred_train = model.predict(x_train)
accuracy_train = accuracy_score(y_train, pred_train)
print('トレーニングデータに対する正解率: %.2f' % accuracy_train)

# テストデータに対する精度
pred_test = model.predict(x_test)
accuracy_test = accuracy_score(y_test, pred_test)
print('テストデータに対する正解率: %.2f' % accuracy_test)

# 決定境界の可視化
x_combined = x_test.values
y_combined = y_test.values

fig = plt.figure(figsize=(13,8))
plot_decision_regions(x_combined, y_combined, clf=model,  res=0.02)
plt.show()

おわりに

ほぼ初めて機械学習に触りましたが意外と簡単でした!(色々雑な部分はありましたが、、)
自分もこの記事に感化されてやってみたのでみなさんもぜひやってみてください。

6
11
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
11