読者です 読者をやめる 読者になる 読者になる

drilldripper’s blog

機械学習とソフトウェア開発を頑張ってます

Pythonの引数を統一的に選択するためのツールを作りました

PycharmやVisual Studioなどの統合開発環境を使っていると、コマンドライン引数の指定が面倒に感じたりしませんか?

例えばPycharmではEdit configurationsを開きScript parameterを変更する必要があります。 f:id:drilldripper:20170406222203p:plain またScript parameterではGUIを使って引数を選択することができないため、パスを自分で記述しなければなりません。 f:id:drilldripper:20170406222207p:plain

そしてこのような引数の指定方法は開発環境によって異なるため、複数の環境をまたいで開発を行っているとやり方を忘れてしまうことがあります。

こういった問題を解決するために、統一的に引数を選択することができるツールを作りました。pipからインストールすることができます。

$pip install QtArgSelector

以下のようにして使います。

import sys
from qtargs import QtArgSelector  # ライブラリのimport

QtArgSelector.ShowArgumentSelector() # GUIを立ち上げる
print(sys.argv) #  引数に反映されているか確認する

スクリーンショット付きの説明はGitHubに書いてあります。

github.com

一つ前に選択した引数の履歴は保存されるので、同じ引数で実験を行いたいときはOKを押すだけ実行できます。

みなさんもお気に入りの開発環境で快適に引数を選択しましょう!

手書き風グラフを支える技術 -Matplotlibのxkcd関数とFIRフィルタ-

Pythonのグラフ描画ライブラリのMatplotlibには、手書き風のグラフを描画するための関数xkcd()があります。以下のソースコードを実行すると、手書き風のsinグラフが描画されます。

from matplotlib import pyplot as plt
import numpy as np
plt.xkcd()  # この関数を実行すると、次のグラフが手書き風グラフになる
plt.plot(np.sin(np.linspace(0, 10)))
plt.title('Handwriting sin graph')
plt.show()

f:id:drilldripper:20170324202314p:plain

温かみがあっていい感じですね。

このような手書き風グラフは、関数の名前にも使われているxkcdというサイトの画像をリスペクトしたものです。

xkcd: Color Pattern

理系的なネタが多く、エンジニアの間でもよく話題になります。また海外版空想科学読本といったテイストの本、ホワット・イフが翻訳されて話題になりました。*1

ホワット・イフ?:野球のボールを光速で投げたらどうなるか

ホワット・イフ?:野球のボールを光速で投げたらどうなるか

さて、このような手書き風グラフはコンピュータでどのように描画しているのでしょうか?

 乱数生成とローパスフィルタ

現在Matplotlibに実装されているxkcd()関数の原案となったブログ記事を参考にしながら読み解いて行きます。

XKCD-style plots in Matplotlib | Pythonic Perambulations

記事のxkcd_line()に注目してください。この関数ではグラフを描くための配列(x, y)を与えたときに、その間を補間するための点を生成します。補完する点にノイズ(ゆらぎ)を加えることによって、手書きのようなガタガタとした線を表現することができます。

この線を描画するために、補間する点数の制御やB-Spline曲線での近似などの様々な工夫がされていますが、肝となる部分はFIRフィルターのローパスフィルタによるノイズ制御と言って問題ないと思います。*2

xkcd_line()中の次のコードを見てみましょう。

# create a filtered perturbation
coeffs = mag * np.random.normal(0, 0.01, len(x_int) - 2) # mag=10
b = signal.firwin(f1, f2 * dist_tot, window=('kaiser', f3)) # f1=30, f2=0.05, f3=15
response = signal.lfilter(b, 1, coeffs)

1行目のコードは線に加えるノイズの大きさを決めています。magを変化させることによって乱数のスケールが変化し、線のガタツキの強弱が変わります。

2行目のコードではFIRフィルタでローパスフィルタの設計を行っています。(FIRフィルターについては後述します)ローパスフィルタは低周波成分のみを通過させて、高周波成分をカットするフィルタです。すなわち1行目で生成した乱数の中で、しきい値を超えたものを0にする処理を行います。これにより本来のグラフから極端に外れた点を抑制することができるので、適度なガタツキを表現することができます。

3行目のコードでは、2行目で設計したローパスフィルターを実際に適応しています。

FIRフィルター

FIRフィルターは有限インパルス応答フィルタ(Finite Impulse Response Filter)とも呼ばれるディジタルフィルタの一種です。FIRフィルターの回路は次の図と式で表されます。

f:id:drilldripper:20170324205455p:plain

{} $$ y = \sum_{k=0}^{N-1} (b[k]x[n-k])
= b[0]x[n-0] + b[1]x[n-1] + b[2]x[n-3] +… b[N-1]x[n-(N-1)] $$

x[n]を入力信号、y[n]を出力、b[n]をフィルタ係数とします。

このとき上式のNを一般にタップ数と呼びます。このフィルタに入力x[n]を入れたときに必要のない周波数成分を取り除くように回路を設計することによって、ローパスフィルタやハイパスフィルタを実現することができます。またこの式から、タップ数を増やすことで入力に対して大きな応答を得ることができることがわかります。

xkcd_line()内で使われいるscipyに実装されているFIRフィルターsignal.firwin()は、第1引数にカットオフ周波数、第2引数にタップ数、第3引数に窓関数を指定する仕様になっています。*3

実験

xの入力を[-3, -2, -1, 0, 1, 2, 3]、yの入力を[9, 4, 1, 0, 1, 4, 9]として、タップ数とカットオフ周波数を変更していきながらグラフの結果を見ていきます。これは{}y = x2のプロットです。

タップ数の変更

(左から順にタップ数の係数0.05, 0.1, 0.2) タップ数の係数を大きくするに従って波の振動が細かくなっていることがわかります。

ここで注意したいのは変更した値はタップ数の「係数」で、タップ数そのものではありません。あらかじめ計算しておいた補間する点の2点間距離に係数をかけています。

カットオフ周波数の変更

(左から順にカットオフ周波数1, 30, 200) カットオフ周波数を大きくするにしたがって、波の振動が抑えられていることがわかります。

参考

SciPyのFIRフィルタの使い方 - 人工知能に関する断創録

*1:私もこの本を読みましたが、とてもおもしろかったです

*2:他にもフォントの変更など、Matplotlibに実装されているxkcd()関数はもっと凝った処理をしています

*3:窓関数の特性に応じて、信号の解析することのできる範囲を変更することができます。詳しい説明は省きますので、気になる方は各自お調べください

SVMとランダムフォレストのどちらの手法を使えばよいか?

分類や回帰の問題を扱う場合、選択する手法としてサポートベクターマシン(SVM)とランダムフォレストが候補に上がってくると思います。

しかし、どちらの手法を使うべきなのでしょうか?どのような問題に対しても、一方の手法を使い続ければ良いのでしょうか?それとも問題によって使い分ける必要があるのでしょうか?

手法の手軽さ

Python機械学習プログラミングの著者であるSebastian Raschka氏は次のように述べています。

I would say that random forests are probably THE “worry-free” approach - if such a thing exists in ML: There are no real hyperparameters to tune (maybe except for the number of trees; typically, the more trees we have the better). On the contrary, there are a lot of knobs to be turned in SVMs: Choosing the “right” kernel, regularization penalties, the slack variable

- When Does Deep Learning Work Better Than SVMs or Random Forests?

意訳 :

ランダムフォレストは安心して使える機械学習のアプローチです。ハイパーパラメータ調整も必要ありません(木の数の指定は除きます)。対してSVMは"正しい"カーネル正則化ペナルティ、スラック変数などの調整が必要になります。

- ディープラーニングはどんなときにSVMやランダムフォレストより勝るか?

ランダムフォレストは調整する変数がSVMに比べて少ないため、とりあえず試してみるという使い方ができます。

また記事中では言及されていませんが、ランダムフォレストは事前に学習データの正規化や標準化を行う必要のない手法です。これも手軽さの一因となっていると思います。

手軽さという面ではランダムフォレストに軍配があがると思います。

多クラス分類

データを複数のクラスに分類したい場合は、どちらの手法を選ぶのが良いでしょうか?

これもSebastian Raschka氏が書いています。

there are multi-class SVMs, the typical implementation for mult-class classification is One-vs.-All; thus, we have to train an SVM for each class – in contrast, decision trees or random forests, which can handle multiple classes out of the box.

- When Does Deep Learning Work Better Than SVMs or Random Forests?

意訳:

マルチクラスSVMの典型的な実装は、一対他分類法です。したがってSVMは各クラスごとにトレーニングを行う必要があります。逆に決定木やランダムフォレストは手法をそのままマルチクラス分類に使うことができます。

- ディープラーニングはどんなときにSVMやランダムフォレストより勝るか?

SVMの一対他分類法とは、ある1つのクラスとその他のすべてのクラスでSVMを構築する方法で、これに対応する一対一分類法は2つのクラスを選び、それを分類するSVMを構築する方法です。以下の記事の説明がわかりやすいと思います。

SVMを使いこなす!チェックポイント8つ

Sebastian氏は典型的な実装法として一対他分類法が使われるとありますが、代表的なSVMライブラリであるlibsvmには一対一分類法が実装されています。

どちらの手法を用いるかによって計算量と分類精度が変わってきます。 一方ランダムフォレストは2クラス分類とマルチクラス分類を行うとき、何か特別な処理をする必要はありません。

学習データ数

用意した学習データの数によって手法を選択することもあると思います。現在QuoraのVPエンジニアリングで元機械学習研究者のXavier Amatriain氏は以下のように述べています。

Unfortunately, the major downside of SVMs is that they can be painfully inefficient to train. So, I would not recommend them for any problem where you have many training examples. I would actually go even further and say that I would not recommend SVMs for most “industry scale” applications. Anything beyond a toy/lab problem might be better approached with a different algorithm.

What are the advantages of different classification algorithms?

意訳:

SVMの欠点は学習が非常に非効率なことです。なのでデータのサンプル数が多い場合、どのような問題でもおすすめできません。もっと言えば工業規模(industry scale)で使うことは推奨できません。研究室レベルや単純化された問題では他のアルゴリズムよりうまく動作します。

分類アルゴリズムのそれぞれの利点はなんですか?

サンプルデータ数が十分に用意できる場合は、SVMではなくランダムフォレストを使うほうが良いと言えそうです。実際、Kinectの身体部位測定の判定にランダムフォレストベースのものが使われているようです。

www.microsoft.com

まとめ

これらの調査から、次のような方針が立てられると思います。

  • ランダムフォレストかSVMか迷ったらとりあえずランダムフォレストを使ってみる
    • ハイパーパラメータ調整が少なくて手軽
    • データ数が多くても効率的に学習できる
  • データ数が少ないときは、SVMを使うことを検討する

しかしながら、以上の方針は絶対ではありません。no free lunch定理が示しているとおり、すべてを上回る手法は存在しないからです。

no free lunch定理 - 機械学習の「朱鷺の杜Wiki」

したがって、以上の方針を頭に入れつつデータの特性を考えながら手法を選択することが重要になります。

参考

初心者が将棋を楽しく続けるためのロードマップ

将棋初心者がどうしたら将棋を続けられるか、という問題が話題になっていました。

将棋ド初心者にどうすれば将棋を続けて貰えるか問題 - 誰かの場所の複数

私の周りでも将棋を始める人が増えていますが、長続きせずにやめてしまう人が多いです。もっと将棋を続けてくれる人が増えるといいなーと思うので、私の考えを書いておこうと思います。

私の将棋の実力

元記事で将棋倶楽部24と将棋ウォーズを基準に実力を述べているので、言及しておきます。私は将棋倶楽部24では初段で、将棋ウォーズでは2段のあたりをうろうろしています。そんなに強くはないですが、それなりの時間と情熱を注ぎましたというレベルです。

ロードマップ

ハム将棋に勝てない段階でネット将棋に手をだすと負け続けることが予想されるため、モチベーションを失ってしまします。というわけで、まずハム将棋に勝つことを目標として、安定して勝てるようになってからネット将棋にデビューするのが良いと思います。

以下に示すロードマップは、効率的に強くなるにはどうすればよいかを私が考えたものです。

1. 戦法と囲いの組み合わせを一つ覚える

初心者の間は戦法と囲いを一つ決めて指すといいと思います。「棒銀 + 矢倉」や「四間飛車+ 美濃囲い」などがわかりやすい戦法です。

将棋チェスネット:千鳥銀の戦法図鑑 Flash

このサイトは戦法の概要が大量にまとめられています。駒を動かすこともできるので、符号が読むのが大変な初心者でも使いやすいと思います。

個人的に棒銀は狙いがわかりやすいのでおすすめです。

【戦法図鑑】7 棒銀戦法(相掛り型)

囲いについては以下のサイトを見るといいと思います。

将棋の囲い一覧 | 将棋研究

ちなみに穴熊囲いが強い、という話を聞いたことがあるかもしれませんが、初心者の間ははおすすめできません。穴熊囲いは本来攻めに使うはずの駒を守りに使うため、攻撃の構想を立てることが難しくなります。よく考えてささないと一方的に攻められて終わってしまうので、違う囲いから始めるのがよいと思います。

2. 簡単な詰将棋を解く

3手ぐらいの簡単な詰将棋を解いてみましょう。インターネットで検索して出て来るもので十分です。

初級詰将棋

詰将棋を解くと頭の中で駒が動かせるようになり、うっかりミスを減らすことができます。また王様が詰む形にはパターンがあるので、よくある形を覚えておくと良いでしょう。

3. ハム将棋と何度も戦う

ハム将棋はこちらが手を変えない限り、同じ手順を再現してきます。なので一度失敗した手順を避けて手を改善していくことで、ハム将棋攻略の糸口が見えてくると思います。

4. コンピュータ将棋で棋譜を解析する

将棋倶楽部24や将棋ウォーズでは、棋譜(指しての手順を示したもの)を取得することができます。この棋譜をコンピュータに読み込ませて解析することで、手の良し悪しを判定することができます。

おすすめのソフトはshogiguiです。GUIが直感的でとても使いやすいソフトです。Windows版、iPhone版、Android版が提供、無料で利用することができます。

ShogiGUI

5. 本を読む

インターネットだけでも将棋の情報を集めることができますが、やはり本は体系的にまとまっているため勉強しやすいです。もし将棋を継続しようと考えているのなら、購入を検討すると良いでしょう。以下におすすめの本のリンクを貼っておきます。

四間飛車を指しこなす本〈1〉 (最強将棋塾)

四間飛車を指しこなす本〈1〉 (最強将棋塾)

将棋の基礎がつまった戦法、四間飛車をわかりやすく学ぶことができる本です。「指しこなす本」シリーズは一問一答形式になっており、将棋盤を用意する必要がないので、気軽に読むことができます。

3手詰ハンドブック

3手詰ハンドブック

タイトルの通り3手の詰将棋がたくさん載っている本です。ハンドブックシリーズは良問が多いことで有名で、実践に役立つ問題がたくさん含まれています。

寄せの手筋200 (最強将棋レクチャーブックス)

寄せの手筋200 (最強将棋レクチャーブックス)

詰将棋を解けるようにはなったけど、そもそも相手の王様を追い詰められないから詰将棋が役立たないんだけど?」という人が読む本です。上記二冊よりは難易度が高いですが、学習効果は非常に高いです。

駒落ちは効率的な上達法か?

元記事では駒落ちの是非について問われていました。駒落ちが将棋の上達に役立つか、というのは意見が分かれる問題だと思います。私が今まで見聞きした意見をまとめると、以下のような感じになると思います。

駒落ち効率的な上達法派だ

駒落ちは駒の効率的な動かし方を理解する上で役に立ちます。代表的な飛車角落ちの定跡として、銀多伝定跡二歩突っ切り定跡があります。これらの定跡は非常に洗練されていて、定跡を学ぶことによって金や銀を効率的に動かすコツが分かります。また駒の落とす数が徐々に減っていくことで、上達を感じることができます。

駒落ちは非効率的な上達法だ

駒落ちで学んだことは平手の将棋に活かしにくいです。駒落ちの定跡は平手の勝負では出現しませんし、玉の囲いも通常とは異なります。将棋はただでさえ最初に覚えることが多いのに、いちいち駒落ちの定跡を覚えていたら、平手の定跡を覚えることに時間をかけられないので、上達が遅れます。

個人的には駒落ちはあまり好きではありません。平手で使わない定跡を覚えるのは負担に感じてしまいます。また私は飛車角を落として負けると、いくら相手が自分より強くてもモチベーションが下がってしまいます。ネット将棋ではレーティングシステムのおかげで自分と近い実力の人と勝負ができるようになったので、あえて駒落ちをやる必要はないと私は考えています。

そもそも、駒落ちってハンデとしてどうなんですかね?盤上に最初から駒が足りていないわけで、大駒を取られたりしたら、戦力が簡単に逆転してしまうので、駒ボロボロ取られて嫌な思いをし続けるだけな気がします。

将棋ド初心者にどうすれば将棋を続けて貰えるか問題 - 誰かの場所の複数

まったくそのとおりだと思います。

終わりに

ロードマップと題して偉そうにいろいろ書きましたが、基本的に自分の好きなようにやればいいと思います。いろいろな戦法が試したいのであれば、一つの戦法に固定することをこだわる必要もないですし、対人戦から始めるのもいいと思います。面白い、と思って将棋を続けてくれる人が増えるといいですね。

AnacondaのJupyter NotebookがPycharmで動作しない問題の解決方法

Jupyter Notebook(Ipython Notebook)は基本的にブラウザ上で動作するソフトウェアですが、Pycharmでから動かすこともできます。使い慣れているキーバインドやかしこい補完が使えるので、Pycharmで動かすメリットは大きいと思います。

しかし現在Anacondaを使って整えたJupyter Notebook環境だと、Pycharmからはエラーが発生して起動することができません。以下のメッセーが含まれるエラーが発生します。

KeyError: 'python3' jupyter

これはAnacondがPython[Root]という名前でエンジンを登録しているにも関わらず、Pycharmはデフォルトでpython3を探しに行ってしまうことが原因です。

このエラーはAnacondaの新しいカーネルでは修正されていますが、現在conda update condaの本体アップデートでは修正が適応されません。次のコマンドでアップデートを行いましょう

conda update nb_conda nb_conda_kernels nb_anacondacloud

The following packages will be UPDATED:

    anaconda:         4.1.1-np111py35_0 --> custom-py35_0
    conda:            4.2.12-py35_0     --> 4.2.13-py35_0
    nb_anacondacloud: 1.1.0-py35_0      --> 1.2.0-py35_0
    nb_conda:         1.1.0-py35_0      --> 2.0.0-py35_0
    nb_conda_kernels: 1.0.3-py35_0      --> 2.0.0-py35_0

これでPycharmからJupyter Notebookが使えるようになります。

参考

github.com

ハサミでMico SIMカードをカットしてをNano SIMカードとして扱う

最近のスマートフォンSIMカードの規格はNanoSIMが使われることが増えてきましたが、一昔前のスマートフォンは一回りサイズの大きいMicro SIMカードが使われています。これまで使っていたLGのNexus5はMicro SIMカードが採用されていますが、今回私が購入したHuaweiのP9ではNano SIMカードが採用されています。

アダプタを使ってNano SIMカードをMicroSIMカードに変換することはできますが、その逆のMicroSIMカードをNanoSIMカードに変換することはできません。

多くのキャリアはSIMカードのサイズを手数料を支払うことで変更することができますが、契約によってはサイズの変更を受け付けていない場合があります。

私が契約しているY!mobileでは、SIMカードのサイズ変更は機種変更の扱いになってしまうので違約金なしにサイズ変更をすることができません。

他社が販売する携帯電話をワイモバイルで利用する|その他のサービス|サービス|Y!mobile(ワイモバイル)

しがたって、現在使用しているNanoSIMカードをMicroSIMカードで使うには、Micro SIMカードをNano SIMカードに加工する必要があります。

MicroSIMカードをNanoSIMカードにダウンサイズする

MicroSIMをNanoSIMとして使うための方法は主に2つあります。

専用のSIMカッターでカットする方法は、以下のようなツールを購入してSIMカードをカットします。

SIMカッターは紙をパンチするように簡単にSIMカードをカットすることができますが、品質のバラツキがあるためかAmazonのレビューでは失敗の報告がいくつかあげられています。

また多くの人はSIMカードを頻繁にカットすが、1枚のSIMをカットするために専用のツールを買うのはもったいないような気がしてしまいます。*1

というわけで、今回はハサミでMicroSIMカードをNanoSIMカードに変換したいと思います。

ハサミを使ってMicroSIMカードをNanoSIMカードに変換する

まずSIMカードをカットするための型紙を以下のサイトのnanosima4.pdfというファイルからダウンロードして、A4サイズで印刷します。

Nano-SIM cutting guide

型紙には以下のものが必要とされているので用意します。

  • 定規
  • セロテープ
  • ハサミ(よく切れるもの)
  • ヤスリ
  • サインペン

ヤスリに関しては爪切りについているもので十分だと思います。

まず型紙にSIMカードをセロテープで貼り付けます。

f:id:drilldripper:20161211164402j:plain

次にサインペンで型紙のラインにそって線を引きます。

f:id:drilldripper:20161211164414j:plain

あとは線にそってSIMを切っていくだけです。じわじわと切っていくとSIMカードが傷んでしまう原因となるので、思い切ってハサミを入れましょう。また小さめに切ると取り返しがつきませんが、大きめに切ればあとでヤスリで整形することができるので、自信がなければ少し大きめに切るほうが良いと思います。

f:id:drilldripper:20161211164426j:plain

最後に切り終わったSIMカードをヤスリで整形します。私はカットしたSIMカードがちょうどよいサイズになったので、この工程は省きました。

少し切り口が歪んでしまいましたが、スマートフォンのSIMスロットにぴったりと収まり、SIMカードを認識することができました。

*1:少なくとも私は一度使ったらもう使うことはないと思います。

MacOS SierraにHomebrewでOpenCVをインストールする際のエラー回避

Homebrewを使ってOpenCVを導入する場合、以下のコマンドを実行してインストールを行います。

brew tap homebrew/science
brew install opencv3

しかし11/10日現在、MacOS SierraではMakeの部分でエラーが発生してインストールすることができません。

QTKit/QTKit.h' file not found"

このエラーはHomebrewのissueに報告されており、--HEADオプションをつけることで回避することができます。

https://github.com/Homebrew/homebrew-science/issues/4303

brew install opencv3 --HEAD

私の環境では上記のコマンドでOpenCV3をインストールすることができました。