質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

Q&A

解決済

2回答

10648閲覧

SVMによる多クラス分類で予測すると、すべて同じクラスに分類される

pura

総合スコア7

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

0グッド

1クリップ

投稿2018/03/21 17:38

編集2018/03/21 17:40

発生している問題・エラーメッセージ

当方、農作物の研究をしております。 過去十数年にわたり国内約100か所で気象データや土壌の状態に関する指標約80種を調査した結果がexcelのinputシートに、 また同年の収穫時期(1:9月上旬、2:9月中旬・・・6:月下旬として、多クラス分類されてます)を調査した結果が 同じブック内のanswerシートにそれぞれ約2000件入力されています。 これら80種の指標と収穫時期の関係をSVMで学習して当年の収穫時期の予測に活用できないかを試しており、以下を記述したところ、 得られるtest_dataの回答がすべて同じクラスになってしまいます。

該当のソースコード

python3 import pandas as pd import numpy as np from sklearn import svm, metrics, cross_validation from sklearn.model_selection import train_test_split from sklearn.metrics import confusion_matrix from mlxtend.plotting import plot_decision_regions filename = "gloth.xlsx" input_sheet_name = "input" answer_sheet_name = "answer" input_book = pd.read_excel(filename, sheet_name=input_sheet_name) answer_book = pd.read_excel(filename, sheet_name=answer_sheet_name) new_input_book = input_book.drop(0, axis=0) #inputシートの0行目はデータ収集中のため、除外していいます。 new_answer_book = answer_book.drop(0, axis=0) #answerシートの0行目はデータ未調査で空欄のため、除外しています。 xlsx_data = new_input_book[["MAX_TEM","MIN_TEM"・・・,"SEIIKU_1","SEIIKU_2"]] #指標はinputシートに80種程度入力しています xlsx_label = new_answer_book[["Group"]] #収穫時期は多クラス分類してanswerシートに入力しています train_data, test_data, train_label, test_label = cross_validation.train_test_split(xlsx_data, xlsx_label,test_size=0.2) clf = svm.SVC(kernel='rbf', gamma=1/80, C=10.0) clf.fit(train_data, train_label.values.ravel()) pre = clf.predict(test_data) ac_score = metrics.accuracy_score(test_label, pre) print("正解率=", ac_score)

試したこと

print(pre)
でtest_dataの予測結果を確認したところ、いずれのデータの予測もすべて「1」として分類されているため、
正解率は16~20%と大変低くなってしまいます。

補足情報(FW/ツールのバージョンなど)

プログラムは、jupyter notebookで記述しています。
機械学習の勉強を始めて1か月程度の素人です。
不足している情報がありましたら
お伝えしたいと思いますので、よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

もう解決していますが…

http://scikit-learn.org/stable/modules/svm.html

sklearnのSVCはOne-vs-Oneで実装されていませんか?


簡単なIrisに対してのコード。

SVCをもうすでに使っているのならマルチクラスを分類できない理由は特にないように思いましたが…

python

1import numpy as np 2 3from sklearn.datasets import load_iris 4 5from sklearn.preprocessing import OneHotEncoder 6from sklearn.metrics import accuracy_score 7from sklearn.model_selection import StratifiedKFold 8from sklearn.model_selection import RandomizedSearchCV 9 10from sklearn.svm import SVC 11from sklearn.multiclass import OneVsRestClassifier, OneVsOneClassifier 12from sklearn.multioutput import MultiOutputClassifier 13 14def load(fonehot=False): 15 data = load_iris() 16 17 x = data['data'] 18 y = data['target'] 19 hs = y 20 21 if fonehot: 22 en = OneHotEncoder() 23 y = en.fit_transform(y.reshape(-1, 1)).toarray() 24 25 return x, y, hs 26 27def get_SVC(): 28 clf = SVC() 29 param_grid = {'kernel': ['rbf', 'linear'], 30 'C': np.logspace(-10, 1, 1000), 31 'gamma': np.logspace(-10, 1, 1000)} 32 clf = RandomizedSearchCV(clf, param_grid, cv=5, n_iter=100, random_state=2018) 33 return clf 34 35def get_OvR(): 36 clf = SVC() 37 clf = OneVsRestClassifier(clf) 38 param_grid = {'estimator__kernel': ['rbf', 'linear'], 39 'estimator__C': np.logspace(-10, 1, 1000), 40 'estimator__gamma': np.logspace(-10, 1, 1000)} 41 clf = RandomizedSearchCV(clf, param_grid, cv=5, n_iter=100, random_state=2018) 42 return clf 43 44def get_OvO(): 45 clf = SVC() 46 clf = OneVsOneClassifier(clf) 47 param_grid = {'estimator__kernel': ['rbf', 'linear'], 48 'estimator__C': np.logspace(-10, 1, 1000), 49 'estimator__gamma': np.logspace(-10, 1, 1000)} 50 clf = RandomizedSearchCV(clf, param_grid, cv=5, n_iter=100, random_state=2018) 51 return clf 52 53def get_OneHot(): 54 clf = SVC() 55 clf = MultiOutputClassifier(clf) 56 param_grid = {'estimator__kernel': ['rbf', 'linear'], 57 'estimator__C': np.logspace(-10, 1, 1000), 58 'estimator__gamma': np.logspace(-10, 1, 1000)} 59 clf = RandomizedSearchCV(clf, param_grid, cv=5, n_iter=100, random_state=2018) 60 return clf 61 62def CV(get_clf, x, y, hs, n_splits=3): 63 kf = StratifiedKFold(n_splits=n_splits, shuffle=True, random_state=2018) 64 s_s = [] 65 pss = [] 66 for tr, ts in kf.split(x, hs): 67 x_ = x[tr] 68 y_ = y[tr] 69 px = x[ts] 70 py = y[ts] 71 clf = get_clf() 72 clf.fit(x_, y_) 73 s_ = accuracy_score(y_, clf.predict(x_)) 74 ps = accuracy_score(py, clf.predict(px)) 75 s_s.append(s_) 76 pss.append(ps) 77 print('train: {0:7.4f} {1:7.4f}'.format(np.mean(s_s), np.std(s_s))) 78 print('test: {0:7.4f} {1:7.4f}'.format(np.mean(pss), np.std(pss))) 79 80if __name__ == '__main__': 81 print('SVC(Implemented with One-vs-one)') 82 CV(get_SVC, *load()) 83 print('OneVsRest') 84 CV(get_OvR, *load()) 85 print('OneVsOne') 86 CV(get_OvO, *load()) 87 print('OneHot') 88 CV(get_OneHot, *load(fonehot=True))

追記

IrisのXに2変数を使って平面上に射影したときの境界線。

広がったガウシアンの場合(gamma=0.000001)
広がったガウシアン

局在したガウシアンの場合(gamma=10000.)
局在したガウシアン

CVしたガウシアンの場合
最適化したガウシアン

投稿2018/03/22 08:29

編集2018/03/26 12:23
mkgrei

総合スコア8560

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

R.Shigemori

2018/03/22 08:41

やはり実装済みのものがあったのですね。 いつも、自力で1対他を実装してました。ありがとうございます
pura

2018/03/22 23:24

mkgrei様 Shigemori様 解決済みの質問へのご指摘、ありがとうございます。 重ね重ね勉強不足でした。実は記載したプログラムはとある書籍の記述をそのまま書いているのですが うまくいかず、悩んでおりました。 ご教示いただいたサイトを参考にしてもう一度考えてみようと思いますが、万が一それでもわからない場合は再掲させていただくと思いますので、その際はお力添えいただければ幸いです。
pura

2018/03/23 14:17 編集

すみません、朝方少しだけmkgrei様からご指摘いただいたことを見て簡単な返信だけさせていただいたのですが・・・ 仕事から戻って改めて確認したところ、大変丁寧なプログラミングのご提案をいただいていることに気が付き驚き、とても感謝しております。 いただいたプログラミングを参考とさせていただき、勉強したいと思います。 もうご覧になってはいないかもしれませんが・・・。 また、Shigemori様へは大変申し訳ありませんが、ベストアンサーを変更させていただきたいと思います。ですが、Shigemori様からいただいたご助言も、素人の自分にはとても勉強になったことは変わらず、感謝申し上げます。 今後も自分でどうしてもわからなそうなことがありましたら質問させていただくと思うのですが、目に留まった際にはアドバイスいただければ幸いです。
mkgrei

2018/03/23 15:26

One-vs-oneとOne-vs-restの差が気になってコードを書いたのですが、せっかくなので貼り付けました。 参考になれば幸いです。 LabelEncodingとOneHotEncodingの差も確かめてみました。 ただ少し気になったのが、sklearnのSVCはそれなりに多クラス分類できるはずだということです。 そこがどうしても気になってしまって… うまくいくはずなのにいかない時に、よくあるのが、 ①データをシャッフルしていないせいで学習に偏りが生じるケース、 ②モデルのパラメータがたまたま悪いケース、 で、train_test_splitはデフォルトでシャッフルをするし、元のコードのパラメータでIrisはうまくいっていました。 それを再度確認するという意図でStratifiedKFoldとRandomizedSearchCVを入れました。 これ以上はデータを見ないとわからない気がします。 なんだかR.Shigemoriさんからベストアンサーを奪ってしまったようで申し訳ないです…
R.Shigemori

2018/03/24 00:29

mkgreiさん 別に気にする必要はありません。 私自身、svmでは多クラス識別はムリと教わっていて、そこから先は自力で1対他をコードにしていたので、むしろ勉強になりました。 svcで多クラス識別が難しい原因ですが、カーネルの問題ということはないでしょうか?リニアなら線を重ね合わせることで識別できることはロジスティック回帰の多クラス識別の原理から理解できますが、rbfだとムリなのかなぁと感覚的に思っていました。この辺りは真面目にsvmの原理を探求していないので、解説付きで可能とする理由を教えていただけると助かります
mkgrei

2018/03/26 12:11

rbfの場合、近傍法に近い状況になるので、最寄りの教師データに分類されるのではないでしょうか? その際にガウシアンの減衰速度によって境界線の形が変化します。 排他的経済水域みたいになります。 図を追記します。
R.Shigemori

2018/03/26 13:08

いろいろとありがとうございます。 やはりマジメに勉強しないとなぜそうなるのかについてイメージがつかめそうにない気がしてきました。
guest

0

svmは多クラス識別ができないと記憶していて、その結果ではないかと思います。
svmを使った多クラス識別をするには1対多分類法と呼ばれるあるクラスとそれ以外のクラスという2値分類を複数回実施するものがいいかと思います。具体的にはクラス1とそれ以外の分類を実施します。次にクラス1以外と識別されたデータを対象にクラス2とそれ以外の分類を実施します。以後同様の処理を全ての分類が終わるまで実施します。
もしかすると、svmで多クラス識別する関数が既に実装されているのであれば、それを使ったほうがいいと思いますが、とりあえず、上記を試すことを検討してはいかがでしょうか

投稿2018/03/21 23:31

R.Shigemori

総合スコア3376

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pura

2018/03/22 01:11

早速のご教示をいただき、ありがとうございます。 調べてみたところ、おっしゃるとおりSVMでは多クラス識別を行えないことがわかりました。 幸い、SVMで多クラス識別する方法(One versus the OneまたはOne versus the Rest)について 解説されているサイトもありましたので、いただいたご回答とそちらのサイトを参考として 試行錯誤してみようと思います。 今週月曜から3日間、ずっとあれこれいじってもうまくいかず悩んでおりましたが、 そもそも元のSVMが多クラス分類に対応していないとは、調べ方に問題ありと痛感しており、 お恥ずかしい限りです。重ね重ね、感謝申し上げます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問