RBFカーネルのハイパーパラメータは何物か?
はじめに
今回の記事は、下記の質問に答えるものです。
RBFカーネルとは?
RBFカーネル(Radial basis function kernel)は下記のように定義される関数のことです。
ただしはユークリッド空間上の距離の2乗、です。
RBFカーネルはカーネル関数の一つで、機械学習の文脈では、サポートベクターマシン(SVM)など内積のみを扱う線形のアルゴリズムを非線形化する際に登場します*1。
RBFカーネルを用いたSVM
RBFカーネルのハイパーパラメータが何物かを知るには、実際にRBFカーネルを用いたSVMが(RBFカーネルの)ハイパーパラメータの違いでどのような挙動を示すかを見るのが分かりやすいかと思います。
そしてscikit-learnの公式ページに、ズバリそのものの項目があるので、該当部分を引用します。
RBF SVM parameters — scikit-learn 0.22 documentation
Intuitively, the gamma parameter defines how far the influence of a single training example reaches, with low values meaning ‘far’ and high values meaning ‘close’. The gamma parameters can be seen as the inverse of the radius of influence of samples selected by the model as support vectors.
日本語訳:
直感的には、ハイパーパラメータは「一つの訓練データが与える影響の範囲」を意味します。小さいほど「遠く」、大きいほど「近く」まで影響します。ハイパーパラメータはサポートベクトルモデルとして選ばれた訓練データの影響範囲の半径の逆数(インバース)としても見なすことができます。
つまり、ハイパーパラメータが小さいほど個々の訓練データが「存在を主張」し、大きいほど「おとなしく」なります。そのためハイパーパラメータが小さい場合には青・赤の訓練データがお互いに存在を大きく主張するので、互いの境界で識別曲線が引かれます。一方で大きい場合には青・赤の訓練データがお互いに自分の周りしか存在を主張しないため、歪な形の識別曲線が引かれるといった具合です。
上の画像を生成したPythonコード
SVM(RBFカーネル)のハイパーパラメータを変えると何が起こるの? - Qiitaを参考に作成しました。
# -*- coding: utf-8 -*- import numpy as np from sklearn import svm, datasets import matplotlib.pyplot as plt from itertools import product if __name__ == '__main__': iris = datasets.load_iris() #特徴量は最初の2つ, クラスラベルも最初の2つを使う X = iris.data[:100, :2] #特徴量にノイズを加える E = np.random.uniform(0, 1.0, size=np.shape(X)) X += E y = iris.target[:100] #meshのステップサイズ h = 0.02 #コストパラメータ Cs = [2 ** -5, 2 ** 15] #RBFカーネルのパラメータ gammas = [2 ** -9, 2 ** -6, 2** -3, 2 ** 3, 2 ** 6, 2 ** 9] svms = [svm.SVC(C=C, gamma=gamma).fit(X, y) for C, gamma in product(Cs, gammas)] titles = ["C: small, gamma: 2**-3", "C: small, gamma: 2**-2", "C: small, gamma: 2**-1", "C: small, gamma: 2**1", "C: small, gamma: 2**2", "C: small, gamma: 2**3", "C: large, gamma: 2**-3", "C: large, gamma: 2**-2", "C: large, gamma: 2**-1", "C: large, gamma: 2**1", "C: large, gamma: 2**2", "C: large, gamma: 2**3"] x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h)) for i, clf in enumerate(svms): plt.subplot(4, 3, i + 1) plt.subplots_adjust(wspace=0.4, hspace=1) Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) plt.contourf(xx, yy, Z, cmap=plt.cm.Paired, alpha=0.8) plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired) plt.xlabel("Sepal length", fontsize=8) plt.ylabel("Sepal width", fontsize=8) plt.xlim(xx.min(), xx.max()) plt.ylim(yy.min(), yy.max()) plt.xticks(()) plt.yticks(()) plt.title(titles[i], fontsize=8) plt.show()
おわりに
質問に立ち返ると、RBFカーネルのハイパーパラメータは「個々の訓練データをどれだけ重要視するか」の設定と捉えられそうです。訓練データからRBFカーネルを用いて分布を推定するという文脈では「(RBFカーネル)関数の広がり(やすさ)を制御する」というような解釈になるかと思います。
*1:「イラストで学ぶ機械学習」杉山将、講談社、p.84
【Python&遊戯王】文章類似度の計算手法”Doc2vec”は「コンマイ語」にも通用するのか
はじめに
要するにやること
本記事では
遊戯王カードの効果テキストは、あまりの複雑さや特殊な解釈のために「コンマイ語」と揶揄されることもあるのですが、今回の記事はそんなコンマイ語に対してもDoc2vecが通用するのかの検証の意味合いも持っています。
動機
下記の記事を発見し、次のような記載があったので、やってみることにしました。
qiita.com
余談ですが遊戯王のカードでもやってみたのですが、自分が遊戯王に詳しくないので似ているかどうかピンと来なかったのでやめました。
Githubにソースとモデル一式をUPしておくので、興味がある方がいましたらやってみてください。
https://github.com/GuiltyMorishita/card2vec
ソースコードの修正
↑のGithubからデータを取得し、Windowsならではの"UnicodeEncodeError"を回避するためにコードを修正しました。修正の過程などはGithubでご確認ください。
gensimのDoc2vecは以前に下記の記事で触れていたこともあり、自分のやりやすい書き方にザックリと変更している箇所もあります。
実行
card2vec.py(先駆者のこの命名センス、素晴らしいと思います)を実行すると、下記のような形式のデータを保持します。"names"はカード名、"texts"は効果テキストをそれぞれテキスト型で持っています。
類似カードの出力
学習が終了したら、いよいよ類似カードを出力してみます。
# 類似カードを求めたいカード名 TARGET_CARD_NAME = names[random.randint(0, len(names))] # 直接指定も可能 # TARGET_CARD_NAME = "xxxxxxxxxxxxxx" card_index = names.index(TARGET_CARD_NAME) # 類似カードと類似度のタプル(類似度上位10件)のリストを受け取る similar_docs = model.docvecs.most_similar(card_index) print(names[card_index]) print(texts[card_index]) print("--------------------is similar to--------------------\n") for similar_doc in similar_docs: print(names[similar_doc[0]] + " " + str(similar_doc[1])) print(texts[similar_doc[0]], "\n")
例えば「ソーラー・エクスチェンジ」に関する類似カードは、以下のような結果になりました。きちんと、ライトロード関連のカードが出力されています。
ソーラー・エクスチェンジ 手札から「ライトロード」と名のついたモンスターカード1枚を捨てて発動する。自分のデッキからカードを2枚ドローし、その後デッキの上からカードを2枚墓地に送る。 --------------------is similar to-------------------- 閃光のイリュージョン 0.7759238481521606 自分の墓地から「ライトロード」と名のついたモンスター1体を選択し、攻撃表示で特殊召喚する。自分のエンドフェイズ毎に、デッキの上からカードを2枚墓地に送る。このカードがフィールド上から離れた時、そのモンスターを破壊する。そのモンスターがフィールド上から離れた時このカードを破壊する。 ライトロード・ドルイド オルクス 0.7378130555152893 このカードがフィールド上に表側表示で存在する限り、「ライトロード」と名のついたモンスターを魔法・罠・効果モンスターの効果の対象にする事はできない。このカードが自分フィールド上に表側表示で存在する限り、自分のエンドフェイズ毎に、自分のデッキの上からカードを2枚墓地に送る。 ライトロード・スピリット シャイア 0.7361984252929688 このカードの攻撃力は、自分の墓地に存在する「ライトロード」と名のついたモンスターの種類×300ポイントアップする。このカードが自分フィールド上に表側表示で存在する限り、自分のエンドフェイズ毎に、自分のデッキの上からカードを2枚墓地へ送る。 ライトロード・ドラゴン グラゴニス 0.7135570049285889 このカードの攻撃力と守備力は、自分の墓地に存在する「ライトロード」と名のついたモンスターカードの種類×300ポイントアップする。このカードが守備表示モンスターを攻撃した時、その守備力を攻撃力が超えていれば、その数値だけ相手ライフに戦闘ダメージを与える。このカードが自分フィールド上に表側表示で存在する場合、自分のエンドフェイズ毎に、デッキの上からカードを3枚墓地に送る。 ライト・バニッシュ 0.7092658877372742 自分フィールド上に存在する「ライトロード」と名のついたモンスター1体をリリースして発動する。モンスターの召喚・反転召喚・特殊召喚を無効にし破壊する。 ライトロード・エンジェル ケルビム 0.703083872795105 このカードが「ライトロード」と名のついたモンスターを生け贄にして生け贄召喚に成功した時、デッキの上からカードを4枚墓地に送る事で相手フィールド上のカードを2枚まで破壊する。 光の援軍 0.6913601756095886 自分のデッキの上からカードを3枚墓地へ送って発動する。自分のデッキからレベル4以下の「ライトロード」と名のついたモンスター1体を手札に加える。 マイン・ゴーレム 0.6905478835105896 このカードが戦闘によって墓地に送られた時、相手ライフに500ポイントダメージを与える。 ライトロード・レイピア 0.6747479438781738 「ライトロード」と名のついたモンスターにのみ装備可能。装備モンスターの攻撃力は700ポイントアップする。このカードがデッキから墓地に送られた時、このカードを自分フィールド上に存在する「ライトロード」と名のついたモンスター1体に装備する事ができる。 魔法再生 0.6690211296081543 手札の魔法カードを2枚墓地に送る。自分の墓地から魔法カードを1枚選択し、手札に加える。
【論文メモ】Aggregated knowledge from a small number of debates outperforms the wisdom of large crowds
論文名
Aggregated knowledge from a small number of debates outperforms the wisdom of large crowds
Joaquin Navajas et. al.
Nature Human Behaviour, 2018
https://www.nature.com/articles/s41562-017-0273-4
概要
【平均の平均は平均より強し】エッフェル塔の高さは? FIFA南ア大会の総ゴール数は? そんな質問を1000人に訊いた平均値より、5名ずつに分かれてグループ討議した結果を平均した方が、正答に近い値が得られるそうです。今朝の『ネイチャー人間行動』誌より→ https://t.co/LyW0zvqWeb
— 池谷裕二 (@yuji_ikegaya) 2018年1月16日
Abstractの要約は上記ツイート。正しくは5,180人っぽい。話し合いによって、明らかな間違いが是正されていくということか。
お台場の水陸両用バス「TOKYO NO KABA(KABA3)」に乗ってきた
土日は基本予定がなく意識的に外出しないと引きこもりになるので、お台場の水陸両用バス「TOKYO NO KABA(KABA3)」に乗ってきました。
予約
上記のホームページから予約します。大人3,500円です。完了するとメールが送られてきて、記載されたURLからチケット確認用のQRコードが取得できます。当日でも空いていれば予約可能らしいです(その場合の予約方法は電話?)。
搭乗
当日は発車時刻の15分前までに、アクアシティお台場の1階にある集合場所に行き、上記のQRコードを提示して搭乗口に並びます。早めに手続を済ませ待っていたところ、発車時刻の15分前ごろに、ひと目でそれと分かる大型バスがやってきました。
「どこから乗るのかな?」と思っていたら、男心くすぐる変形!
このような柄の座席で、可愛らしいです。定員38人ですが、昨年11月27日に運行開始したばかりで認知度がまだまだ低いのか、乗客は5組20人弱でした。
若干気になる注意書きも……。
運転席には当然のことながらハンドルと舵の両方がありました。
運行
公式サイト(http://www.kaba-bus.com/tokyo/)より引用。
運行時間は約45分。最初の15分は地上でお台場の観光地を巡ります。バスツアーのごとく、ガイドのお姉さんが名所を紹介してくれました。
地上のコースを終えた後は、いよいよ東京湾へ突入です。
乗客全員で「3、2、1、カバ~」と掛け声を掛けながら、バスが東京湾へ進んでいきます。
※この瞬間の動画を撮ったのですが、ぜひご自身で体験していただきたいので掲載しないことにしました
水中パートでは、窓を開けて解放感あるクルージングを体験できます。レインボーブリッジを下から望むこともでき、少々寒かったですが非常に良い時間を過ごしました。
おわりに
貴重な体験ができ、とても満足です。最初は大人1人3,500円は若干高い気もしましたが、お台場をガイドさん付きで観光できるオプションもありますし、悪くない額だと思います。また運転手さん(キャプテン)は、大型バスの運転免許と船舶の免許を両方持っている稀有な人材なので、人件費がかかるのではないかと。ひさしぶりに充実した休日を過ごした気がしました。
【Python, sklearn】モデル名の表示
documentation読んでも上手く見つけられず、他人のコードを読み漁って発見したのでメモ。
from sklearn.linear_model import LogisticRegression # ロジスティック回帰 model = LogisticRegression() clf = model.fit(X_train,y_train) print(clf.__class__.__name__)
文字列型で"LogisticRegression"が返る。
Google Homeで「室内留学」のすゝめ
用途:「室内留学」
僕の場合の用途は、自宅(※独り暮らし)で英会話ができる「室内留学」環境の構築です。
Google Homeを利用する利点は、以下のようなものが挙げられます。
音声操作のため、半強制的かつ手軽に英語を話す/聞く環境下を構築できる
- 例えば目覚まし時計のアラームを止めるためにも、英語を話す必要が生じます
- 朝には身支度をしながら「Tell me 'MyDay'」と言うだけで、今日の天気・最新のニュースを英語で流してくれます
- "How can I get to the office"と聞くと、何時の電車に乗れそうかを教えてくれます
- 何か調べたいときにも、わざわざスマホやPCを立ち上げることなく音声で処理しようとして英語を発するようになります
英会話教室や実際の留学と違って相手が「忖度」してくれない
- Google Homeさんは発音が悪いと全く相手にしてくれません
- 向こうから助け舟を出してくれることも、ほとんどありません
- 目的語が足りないなど一定の条件下で聞き返してくれることも
- 一方で生身の人間と違い、何回も話しかけても嫌な顔をしないという利点もあります
取りあえず一日稼働させただけですが、結構な量の英語を話す/聞くことができたので、今後も続けていきたいと思っています。
「Google Home」か「Google Home Mini」か
店頭で店員に確認したところ
機能的に「できること」の違いはない
マイクとスピーカーの性能が違う
- Miniはマイクが1個で、通常版は2個。通常版は高さがある分、聞き取る可能性が高くなる
- スピーカーとしての音質/音域が違う
とのことでした。
スピーカーについては想定用途にも依りますが、店頭で確認すべきかと思います。個人的には結構違いました。
今回の用途はGoogle Homeとのやり取りが大切になるため、コミュニケーションの障害になりうる要素は極力排除したいと思い、倍の値段にはなりますが通常版を選択しました。
諸設定(参考までに)
- Google Homeのデフォルト初期設定
- マニュアルに沿って設定します。この初期設定の終了時点では言語設定が日本語になっています。もちろん英語で話しかけても理解してくれません。
- 言語設定の変更
- スマホのGoogle Homeアプリから、言語を"English"に変更します
- ニュースの設定
- スマホのGoogle Homeアプリから、英語のニュースを追加し、(必要に応じて日本語のニュースを外し)流す順番を整備します
- 音楽の設定
- Google Home - Spotifyのアカウントを作成しGoogle Homeと連携すると、洋楽を好きなだけ楽しめます
- spotifyのスマホアプリで歌詞を確認しながら聞くと、ヒアリングの勉強になるかなとも思います
PythonでRFM分析(任意のクラスタ数にK-meansクラスタリング)
やったこと
サンプル
想定データ構造
UserID | Recency | Frequency | Monetary | (K-meansResult) |
---|---|---|---|---|
000000 | 123 | 456 | 789 | 0 |
000001 | 378 | 764 | 924 | 0 |
000002 | 578 | 267 | 532 | 1 |
Pythonコード
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import pandas as pd df = pd.read_csv('df.csv') import numpy as np from sklearn.cluster import KMeans import matplotlib.pyplot as plt from matplotlib import cm from mpl_toolkits.mplot3d import Axes3D df.iloc[:,2] = np.log10(df.iloc[:,2]+1) df.iloc[:,3] = np.log10(df.iloc[:,3]+1) CLUSTERS_NUM = 5 pred = KMeans(n_clusters=CLUSTERS_NUM).fit_predict(df.iloc[:,1:4]) df = pd.concat([df, pd.DataFrame(pred)], axis=1) fig = plt.figure() ax = Axes3D(fig) ax.set_xlabel("Recency") ax.set_ylabel("Log10(Frequency)") ax.set_zlabel("Log10(Monetary)") d = [] for cluster_i in range(CLUSTERS_NUM): d.append(df[df.iloc[:,4]==cluster_i]) c = cm.hot(float(cluster_i) / CLUSTERS_NUM) ax.plot(d[cluster_i].iloc[:,1], d[cluster_i].iloc[:,2], d[cluster_i].iloc[:,3], "o", color=c, ms=2, mew=0.5) plt.show()