Aug 10, 2017

野球のポジション当てゲームをプログラムで解いてみた

一昨日、野球のポジション当てゲームというのを知った。

http://heart-quake.com/article.php?p=527より:

1.藤山選手はサードと同じアパートに住んでいるということだ。
2.センターはライトより背は高いが、足はライトの方が早い。
3.鈴木選手の妹さんはセカンドと婚約中だそうで、どうも挙式は来春だそうだ。
4.キャッチャーの長男とサードの次女は同じ小学校の同級生だそうだ。
5.ショートとサードそれに桜井選手の3人はよく揃って競馬に行くそうだ。
6.ピッチャーはとても麻雀が強く、今月も梅田選手と菊池選手から5000円ずつまきあげたそうだ。
7.外野選手のうち一人はどうも木下選手か松村選手らしい。
8.小川選手はどうも奥さんとうまくいっていないようだ。近々離婚するのではないかとの噂がとんでいる。
9.選手達はよく揃ってゴルフに行くが、梅田・藤山・桜井の3選手はどうしてもキャッチャーとセカンドには勝てないようだ。
10.ピッチャーの奥さんはサードの妹さんだそうだ。
11.松村選手はキャッチャーと、又、桜井選手はピッチャーととても仲が良いようである。
12.選手たちのうちで、独身なのは、鈴木・梅田・山田の3選手、それにセンターとライトの5人である。
13.山田選手は桜井選手より背が高く、木下選手は桜井選手より背が低い。しかし、この3人はいずれもファーストより低い。

ここからは、問題文を一部改変しております。
製品をご購入いただくと正式な問題文が閲覧可能です。

14.選手たちのうちで酒を飲まないのは、XXX選手とXXX選手。それにショートの3人だけだそうだ。
15.バッテリーと内野の全員はXXX・XXX・XXXの3選手を除くとみんな外野の小川選手より背が低い。
16.鈴木選手は外野手のX人と一緒に麻雀をよくするそうだ。
こういう論理パズルで、色々制約のあるグループワークで解くもので、何らかの研修とかで使われるものらしい。

これが、色々制約のあるグループワークだから難しいが、一人でやったら簡単に解けるということだったので、上記XXXの部分を入手して、早速その日の夜にやってみたら、1時間くらいかけても解けなかった。

次の日の夜も、前日と同様、「藤山 not 5, 8 > 9, 鈴木 not 4, 4 single, ...」と紙に書き出すと、読み易い文字で書き直した為か、20分くらいで何らか解が出たのだが、解は複数あるような感じで、出した解は別途入手した答えと違った。

本当に解は1つしかないのだろうか?と気になって、今日、次のような簡単なプログラムを書いて探させてみたら、確かに解は1つしか無かった。

#!/opt/local/bin/python3
from itertools import permutations
names = ('藤山', '鈴木', '桜井', '梅田', '菊池', '木下', '松村', '小川', '山田')

def taller(name1, name2):
    dict1 = {'山田':3, '桜井':2, '木下':1}	#13
    if name1 in dict1 and name2 in dict1:
        if dict1[name1] > dict1[name2]: return True
    if name1 in ['XXX', 'XXX', 'XXX'] and name2 == '小川': return True	#15
    return False

def single(name):
    return name in ['鈴木', '梅田', '山田']	#12

def married(name):
    return name in ['小川']	#8

def judge(position):
    name_by_pos = {v:k for k,v in position.items()}

    if position['藤山'] == 5: return False	#1
    if taller(name_by_pos[9], name_by_pos[8]): return False	#2
    if position['鈴木'] == 4 or married(name_by_pos[4]): return False	#3
    if single(name_by_pos[2]) or single(name_by_pos[5]): return False	#4
    if position['桜井'] == 5 or position['桜井'] == 6: return False	#5
    if position['梅田'] == 1 or position['菊池'] == 1: return False	#6
    if (position['木下'] >= 7 and position['松村'] >= 7) \
       or (position['木下'] <= 6 and position['松村'] <= 6): return False	#7
    #8
    if position['梅田'] in (2,4) or position['藤山'] in (2,4) \
       or position['桜井'] in (2,4): return False	#9
    if single(name_by_pos[1]): return False	#10
    if position['松村'] == 2 or position['桜井'] == 1: return False	#11
    if position['鈴木'] >= 8 or position['梅田'] >= 8 or position['山田'] >= 8 \
       or married(name_by_pos[8]) or married(name_by_pos[9]): return False	#12
    if position['山田'] == 3 or position['桜井'] == 3 \
       or position['木下'] == 3: return False	#13
    if position['XXX'] == 6 or position['XXX'] == 6: return False	#14
    if position['XXX'] >= 7 or position['XXX'] >= 7 or position['XXX'] >= 7 \
       or position['小川'] <= 6: return False	#15
    if XXXXXXXXXXXXXXXXXXXXX: return False	#16
    return True

for p in permutations(range(9)):
    position = {names[i]: p[i]+1 for i in range(9)}
    if judge(position) == True:
        print(position)
(上記問題文で伏字にされている部分がわかる部分は伏字にしている)

プログラムのデバッグ中に、次のような表を作ってこれを埋めていく形で解き直したら、10分もかからずに解けた。問題を半分くらい覚えてしまったから早く解けたということもあるが、最初からこうやれば良かったと思った。

藤山 0 00
鈴木00 00
桜井00 000
梅田00 00
菊池0
木下 0 777
松村 0 777
小川 0 00
山田000 0
(1.〜13.まで読んでマークした状態、0は偽、7は7.参照の意)

See more ...

Posted at 21:06 in 数学 | WriteBacks (0)
WriteBacks

Jul 22, 2017

4五歩早仕掛けの玉頭銀対策を考える

筆者はこの所、4五歩早仕掛けを多用している。長らく将棋の勉強を怠っており、対四間飛車の急戦はこれしか思い出せないのである。しかも、四間飛車に対して急戦の構えを見せると△4三銀と上がる人が多いので、実現しやすく、便利である。
図1:4五歩早仕掛け

今月、久々に将棋を指す機会があり、久々の4五歩早仕掛けがクリーンヒットして安心し、その次の対局でもまた4五歩早仕掛けをしたら、4三の銀を5四〜6五〜7六と斜めにスルスルと動かされ、対処できずボロボロに負けてしまった。
図2:6九金型の4五歩早仕掛けに対する玉頭銀

筆者は昔からこの△5四銀が苦手なのであるが、寡聞にして定跡書で見たことが無かった為、この手は無い手で、必ず咎められる手だと思っていた。それで、△5四銀とされれば▲5五歩から殺しにかかるのだが、成功することは5回に1回もない。(しかも、銀を殺せても良くなるとは限らない。)

玉頭銀を殺すイメージ図
図3:歩を入手して▲7七歩とできれば銀が死ぬ

図4

図5:次に▲6六歩で銀が死ぬ

図6:このままなら次に▲7七歩で銀が死ぬ

今回も銀を殺せず、悪形だけが残り、総崩れしてしまった。
あまりにもひどかったので、一度きちんと調べておくことにした。



【結論】

  • この△5四銀〜△6五銀〜△7六銀と動く戦法には「玉頭銀」という名前が付いているらしい。
  • 玉頭銀は6九金型の4五歩早仕掛けに対して特に有効とされているらしい。
  • 4五歩早仕掛けの1手前の▲4六歩は△5四歩を待ってからにするべきらしい。
  • 従って、▲6八金直△5四歩の交換を入れてからにするべきらしい。


しかし、▲6八金直の次に△5四歩とされるとは限らない。
▲6八金直の直後に△5四銀と玉頭銀で来られれば▲5五歩△6五銀▲7五歩〜▲2六飛の筋があるし、▲3五歩△同歩▲4六銀が速いので、玉頭銀の牽制になっているとは思うが、後手には△1二香や△6四歩など、色々な手がある。△6四歩〜△5四銀〜△6三銀引と堅められることも多い。それに対して、▲6八金直は有効な待ちなのだろうか?

筆者は人生で▲6八金直にいい思い出が無い。△8四桂〜△7六桂の両取りを狙われるし、下段が空くし、5七銀の引き場所が無くなるし、▲5九香の頑張りがあまり利かなくなる。

▲6八金直が得な手でなく、次に△5四歩や△5四銀が期待できないなら、やっぱり▲6八金直と待つのではなく、さっさと▲4六歩と突きたい。それでもし△5四銀を食らっても、正確に指されれば少し悪くなる、という程度に済ませる方法は無いだろうか、と思って、懲りずに6九金型で玉頭銀を食らった場合の対策を探してみた。

△5四銀の後は(1)▲3七桂、(2)▲3八飛、(3)▲5五歩の3通りが多いようである。

(1)▲3七桂の後は、△6五銀▲4五歩△7六銀▲2四歩△同歩▲4四歩
図7
△同角▲同角△同飛▲7七歩△8七銀成
図8
▲同玉△8四飛▲8六銀△6四角▲9七角△9五歩▲同歩△9六歩▲同玉△8六角▲同角△8五銀
図9
と玉頭銀の恐ろしさを一方的に見せつけられるのが、代表的な進行である。

▲4四歩△4四同角には▲7七歩が正解だと思われる。▲4四歩に△3五歩でも▲7七歩と打つことになるらしい。(1)の▲3七桂は、銀を取れないのに形悪く▲7七歩を打つことになることが多く、いまいちである。

ただ、▲3七桂△6五銀▲4五歩△7六銀の後、▲4四歩でなく▲4四角とする手があるらしい。
△同角▲同歩△同飛なら▲6六角として、△8四飛と回るのを防げる。
図10

(2)▲3八飛は、△3二飛なら▲5五歩△6五銀▲3五歩△同歩▲同飛△7六銀▲2四歩△同歩▲5四歩(図6)のように銀を狙えそうだが、図6からでも簡単には銀が取れない。△4五歩でも助かりそうだし、△6四歩▲6六歩△6五歩▲8六歩△6六歩▲同銀△6四歩とやっても後手がなんとかなりそうである。

▲3八飛には△4五歩とする人が多いと思う。その後、▲3三角成△同桂▲8八角△4三金▲2八飛に△6四角(山崎六段)
図11
という手があり、これは先手こらえるのが大変そうである。△6四角に▲2四歩と攻め合って先手良しとする本もあるが、筆者には先手良しと理解できなかった。

▲3八飛には何と△4三銀と戻る手もあり、▲3五歩△同歩▲同飛△3二飛▲4五歩△同歩▲4四歩△2二角▲4五飛
図12
と自然に進めても、△3四銀(谷川-藤井)でうまくいかない。

やはり筆者としては、△5四銀には勝ち負けを度外視してでも(3)▲5五歩としたい。
▲5五歩の後は△6五銀▲3五歩△同歩▲3八飛
図13
とする。
そこで△4三金だと、▲3五飛△3四歩▲3六飛△7六銀▲4五歩△6五銀▲7五歩△4五歩▲8六飛(図5)のように銀挟みが成功する筋がある。

図13から△4五歩だと、▲3五飛△4六歩▲4五歩△3四歩▲同飛△4五飛▲3七桂△4四飛▲同飛△同角▲4一飛
図14
が一例で、ここで△3五角なら後手良しらしいが、アマ同士なら先手もやれそうではないだろうか。

図13から△4五歩▲3五飛△4六歩▲4五歩に△7六銀とした実戦例(森下-櫛田)もあり、▲4六銀△9五歩▲同歩△9八歩▲同香△9七歩▲同香△9六歩▲同香△8五銀
図15
と端から大暴れされたが、▲3二歩の垂らしから、と金を作って先手が勝っている。

図13から△7六銀だと、正確に指されると後手良しらしいが、▲3五飛△6五銀▲6六歩△7六銀▲5四歩△同歩▲9七角
図16
という指し方もあるかも知れない。△3二飛なら▲2四歩△同歩▲2二歩である。

1筋の突き合いが入っていると、6九金型でも玉頭銀に対して別の対策があるかも知れない。

1つには、△5四銀に対して、▲5五歩△6五銀▲3五歩△同歩▲3八飛△7六銀▲3五飛△6五銀に▲1五歩(升田-大山)という定跡がある。
図17
以下△同歩▲3四歩△2二角▲2四歩△4三飛▲5四歩△同銀▲3三歩成△同飛▲同飛成△同角▲2三歩成△5一角▲2八飛
図18
で先手優勢である。

もう1つは、△5四銀に対して、▲5五歩△6五銀▲3五歩△同歩▲3八飛△4五歩▲3五飛△4六歩の後、▲3七桂△7六銀▲4五桂が成立する。
図19
1筋の突き合いが入っていないと、ここで△1五角があり、▲5四歩△同歩▲1一角成としても△3四歩で後手良しになるが、図19だと△3四歩か△2二角しかなく、△3四歩なら▲3三桂成、△2二角なら▲2四歩でいずれも崩壊ではないだろうか。
 
問題はどこで1筋の突き合いを入れるかだが、▲5七銀左と上がる前に入れている実戦例が、上記の升田-大山戦を含め複数あるので、そのタイミングが良いと思う。ただ、後手が玉頭銀で来ない場合にどういう影響があるかは未確認である。

■参考文献
最強将棋21 四間飛車破り【急戦編】渡辺 明(著)

See more ...

Posted at 22:26 in 将棋 | WriteBacks (0)
WriteBacks

Jun 19, 2017

scikit-learnのナイーブベイズ分類器を使ってみる

前回のFamily Out Problemの確率モデル(下図)を題材に、ナイーブベイズ分類器を使ってみる。


Family Out Problem

この問題において、family-out以外の変数の真偽値が与えられた時にfamily-out=TRUEかどうかを判定するよう、ナイーブベイズ分類器を学習させてみる。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.naive_bayes import BernoulliNB
from sklearn.metrics import precision_recall_fscore_support
from sklearn.metrics import roc_curve, auc

def generate_sample():
    "Sample data generator of the Family Out problem"
    fo = np.random.binomial(1, 0.15)
    bp = np.random.binomial(1, 0.01)
    lo = np.random.binomial(1, (0.05, 0.6)[fo])
    do = np.random.binomial(1, ((0.3, 0.97), (0.9, 0.99))[fo][bp])
    hb = np.random.binomial(1, (0.01, 0.7)[do])
    return [fo, bp, lo, do, hb]

# Generate training data and test data
train_data = np.array([generate_sample() for _ in range(1000)])
test_data = np.array([generate_sample() for _ in range(100)])

X_train = train_data[:, 1:5]	# other than fo
y_train = train_data[:, 0]	# only fo
X_test = test_data[:, 1:5]	# other than fo
y_test = test_data[:, 0]	# only fo

# Train a Naive Bayes classifier
clf = BernoulliNB()
clf.fit(X_train, y_train)

# Evaluate with training data
y_pred = clf.predict(X_train)
metrics = precision_recall_fscore_support(y_train, y_pred)
print('Evaluation with training data')
print('Class FamilyOut=False: Precision={:.3f}, Recall={:.3f}, F-measure={:.3f}'.format(metrics[0][0], metrics[1][0], metrics[2][0]))
print('Class FamilyOut=True : Precision={:.3f}, Recall={:.3f}, F-measure={:.3f}'.format(metrics[0][1], metrics[1][1], metrics[2][1]))

# Evaluate with test data
y_pred = clf.predict(X_test)
metrics = precision_recall_fscore_support(y_test, y_pred)
print('Evaluation with test data')
print('Class FamilyOut=False: Precision={:.3f}, Recall={:.3f}, F-measure={:.3f}'.format(metrics[0][0], metrics[1][0], metrics[2][0]))
print('Class FamilyOut=True : Precision={:.3f}, Recall={:.3f}, F-measure={:.3f}'.format(metrics[0][1], metrics[1][1], metrics[2][1]))

# Draw ROC curve
y_train_post = clf.predict_proba(X_train)[:, 0]
y_test_post = clf.predict_proba(X_test)[:, 0]

fpr, tpr, thresholds = roc_curve(y_train, y_train_post, pos_label=0)
roc_auc = auc(fpr, tpr)
plt.plot(fpr, tpr, 'k-', lw=2, label='ROC for training data (area = {:.2f})'.format(roc_auc))

fpr, tpr, thresholds = roc_curve(y_test, y_test_post, pos_label=0)
roc_auc = auc(fpr, tpr)
plt.plot(fpr, tpr, 'k--', lw=2, label='ROC for test data (area = {:.2f})'.format(roc_auc))

plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC curve of BernoulliNB')
plt.legend(loc="lower right")

plt.show()

問題のモデルに従って学習用データとテストデータをランダムに生成し、sklearn.naive_bayes.BernoulliNBの分類器を学習させ、テストデータを分類させ、family-out=FALSEとfamily-out=TRUEのそれぞれについてPrecision, Recall, F値を計算している。
加えて、予測したfamily-out=FALSE/TRUEの確率から、ROC曲線とAUCを出力している。

出力例

Evaluation with training data
Class FamilyOut=False: Precision=0.936, Recall=0.983, F-measure=0.959
Class FamilyOut=True : Precision=0.847, Recall=0.589, F-measure=0.695
Evaluation with test data
Class FamilyOut=False: Precision=0.923, Recall=0.988, F-measure=0.955
Class FamilyOut=True : Precision=0.889, Recall=0.533, F-measure=0.667
ROC曲線
ROC curve
その時のtraining_dataとtest_data(.arff形式)
family_out_train.arff
family_out_test.arff

ナイーブベイズ分類器には、同じクラスのデータでは全ての特徴が独立に出現する、つまりbp,lo,do,hbに依存関係が無く、これらがTRUEになる確率はfoの値だけで決まるという仮定があるが、この問題ではbp,do,hbに依存関係があるので、ベイジアンネットワークの方がうまく学習できると考えられる。
なのでベイジアンネットワークで分類した場合の性能と比較したいが、scikit-learn(0.18)にベイジアンネットワークが無いので、代わりにWeka 3.8.1のBayesNetを用いて学習用データで学習させ、テストデータを分類した結果と比較してみる。

Wekaの操作手順

  1. Weka ExplorerのPreprocessタブでOpen file...ボタンを押し、family_out_train.arffを開く
  2. ClassifyタブでClassifierとしてBayesNetを選択する
  3. "BayesNet -D ..."とあるフィールドをクリックしてパラメーター設定画面を開き、searchAlgorithmのフィールドをクリックして、initAsNaiveBayes=False, maxNrOfParents=2に変更
  4. Test optionsのSupplied test setのボタンを押し、family_out_test.arffを開き、Classとしてfamily-outを選択
  5. クラスをfamily-outを選択し、Startボタンを押す
上記と同じデータを使った出力例
=== Run information ===

Scheme:       weka.classifiers.bayes.BayesNet -D -Q weka.classifiers.bayes.net.search.local.K2 -- -P 2 -N -S BAYES -E weka.classifiers.bayes.net.estimate.SimpleEstimator -- -A 0.5

=== Detailed Accuracy By Class ===

                 TP Rate  FP Rate  Precision  Recall   F-Measure  MCC      ROC Area  PRC Area  Class
                 0.988    0.467    0.923      0.988    0.955      0.651    0.889     0.967     0
                 0.533    0.012    0.889      0.533    0.667      0.651    0.889     0.648     1
Weighted Avg.    0.920    0.398    0.918      0.920    0.911      0.651    0.889     0.919     

=== Confusion Matrix ===

  a  b   <-- classified as
 84  1 |  a = 0
  7  8 |  b = 1

BernoulliNBのテストデータに対する出力と、Precision, Recall, F-measureが完全に一致している。

WekaのBayesNetのデフォルト設定では正しいネットワークが学習されなかったが、上記手順の3.のように設定を変えると、大体次のように正しいネットワークになった。

BernoulliNBの性能には試行毎にばらつきがあったが、1000回の平均を取ってみたのが次の値であり、上記の結果は特別に良い例ではない。

Average with training data
Class FamilyOut=False: Precision=0.925, Recall=0.982, F-measure=0.952
Class FamilyOut=True : Precision=0.844, Recall=0.545, F-measure=0.661
Average with test data
Class FamilyOut=False: Precision=0.925, Recall=0.982, F-measure=0.952
Class FamilyOut=True : Precision=0.842, Recall=0.544, F-measure=0.651
Average of AUC with training data=0.894
Average of AUC with test data=0.895
また、計10回、同じデータでWekaのBayesNetの性能と比較した所、Precision, Recall, F-measureについては、8回は一致していた。
ROC曲線のAUCはWekaのBayesNetの方が高いことが多かったが、BernoulliNBでも大体0.85-0.90の範囲であり、十分に高かった。
従って、この確率モデルに対して、ナイーブベイズ分類器は予測性能が十分に高いと言える。

なお、ここまでの結果では、学習データに対する各種性能値とテストデータに対する値にほぼ差が無いが、これは学習データのサンプル数が1000と十分に多く、偏りが無いからである。これを100にすると、次のように、テストデータに対する成績が少し下がるが、それでも、学習データだけに対して大幅に成績が良い「過学習(overfitting)」の状態と言える程ではない。

学習データ数が100の1000試行の平均

Average with training data
Class FamilyOut=False: Precision=0.931, Recall=0.963, F-measure=0.945
Class FamilyOut=True : Precision=0.793, Recall=0.582, F-measure=0.650
Average with test data
Class FamilyOut=False: Precision=0.926, Recall=0.955, F-measure=0.938
Class FamilyOut=True : Precision=0.767, Recall=0.564, F-measure=0.620
Average of AUC with training data=0.899
Average of AUC with test data=0.890

See more ...

Posted at 22:35 in 数学 | WriteBacks (0)
WriteBacks

May 29, 2017

Wekaでベイジアンネットワークの事後確率を計算

ベイジアンネットワークの復習をしていて、確率的グラフィカルモデル‐ベイジアンネットワークとその周辺‐(オペレーションズ・リサーチ 2013年4月号)という記事を見つけた。その中に、Family Out Problemという有名な例題(下図)の紹介があり、p.194に、

表1~3で与えられたCPTの値と式(11)を利用して丹念に計算することにより P(X1=1|X3=1,X5=1)=0.7577···という結論を得る.
と書かれていたので、これを自力で計算できたらベイジアンネットワークを理解できたことにしよう、と思って、丹念に計算してみたら、その値にならなかった。


Family Out Problem

ここでは、
X1: Family Out
X2: Bowel Problem
X3: Light On
X4: Dog Out
X5: Hear Bark
(それぞれ2値の確率変数)であり、それぞれの条件付き確率は次の通りである。
P(X1=1) = 0.15
P(X2=1) = 0.01
P(X3=1 | X1=0) = 0.05
P(X3=1 | X1=1) = 0.6
P(X4=1 | X1=0, X2=0) = 0.3
P(X4=1 | X1=0, X2=1) = 0.97
P(X4=1 | X1=1, X2=0) = 0.9
P(X4=1 | X1=1, X2=1) = 0.99
P(X5=1 | X4=0) = 0.01
P(X5=1 | X4=1) = 0.7

P(X_1=1 | X_3=1, X_5=1) = \frac{\sum_{X_2}\sum_{X_4} P(X_1=1, X_2, X_3=1, X_4, X_5=1)}{\sum_{X_1}\sum_{X_2}\sum_{X_4} P(X_1, X_2, X_3=1, X_4, X_5=1)}
なので、Pythonで

P00101 = 0.85 * 0.99 * 0.05 * 0.7 * 0.01
P00111 = 0.85 * 0.99 * 0.05 * 0.3 * 0.7
P01101 = 0.85 * 0.01 * 0.05 * 0.03 * 0.01
P01111 = 0.85 * 0.01 * 0.05 * 0.97 * 0.7
P10101 = 0.15 * 0.99 * 0.6 * 0.1 * 0.01
P10111 = 0.15 * 0.99 * 0.6 * 0.9 * 0.7
P11101 = 0.15 * 0.01 * 0.6 * 0.01 * 0.01
P11111 = 0.15 * 0.01 * 0.6 * 0.99 * 0.7

P35 = P00101 + P00111 + P01101 + P01111 + P10101 + P10111 + P11101 + P11111
P135 = P10101 + P10111 + P11101 + P11111
P1_35 = P135 / P35
print(P1_35)
とすると、0.8578...という数値になった。どこか読み間違えたかと思って、
def prob(x1, x2, x3, x4, x5):
    p = 1.0
    p *= (0.85, 0.15)[x1]
    p *= (0.99, 0.01)[x2]
    p *= ((0.95, 0.05), (0.4, 0.6))[x1][x3]
    p *= (((0.7, 0.3), (0.03, 0.97)), ((0.1, 0.9), (0.01, 0.99)))[x1][x2][x4]
    p *= ((0.99, 0.01), (0.3, 0.7))[x4][x5]
    return p

P135 = sum([prob(1, x2, 1, x4, 1)
             for x2 in range(2)
             for x4 in range(2)])
P35 =  sum([prob(x1, x2, 1, x4, 1)
             for x1 in range(2)
             for x2 in range(2)
             for x4 in range(2)])
P1_35 = P135 / P35
print(P1_35)
と書いてみたが、やはり0.8578...だった。

上記の記事内の条件付き確率表に誤記があり、0.7577...というのは元の確率表で計算された値か、とも思ったが、どの文書のFamily Out Problemを見ても確率は同じだった。

正解は何なのか、何らかのツールで確認しようと思って、Pythonのベイジアンネットワーク関連のツールを探したが、適当なものがなかなか見つからなかった。

scikit-learnには"Naive Bayes"のAPIはあるがベイジアンネットワークは見つからない。
PyMCBayesPyは、きっとうまく使えばこの計算ができるのだろうが、ネットワークを定義して、CPT(conditional probability table、条件付き確率表)とevidence(観測値)を与えて事後確率を計算する直接的なサンプルコードが見つからなかったので、諦めた。
PBNTにはそういうサンプルコードがあったので、使ってみたが、P(X1=1|X3=1,X5=1)=0.2018...という全然違う値が出力された。P(X5=1)=0.2831と、これは正しい値が出たので、ネットワークとCPTは合ってそうであり、事後確率を計算するにはengine.marginal()でなく別のメソッドを使わないといけないのかとも思ったが、よくわからなかった。

Pythonを諦めてツールを探すと、Wekaでできることがわかった。Wekaは機械学習の勉強をするなら必修らしく、過去にインストールしていたので、やってみた。
Wekaを起動して、Tools->Bayes net editorを開くと、GUIがバグだらけ(Version 3.8.1, WindowsとMacとで確認)で使いにくいが、ノードを追加して右クリックしながらネットワークを作成し、Tools->Layoutでノードの配置を修正し、CPTを設定し、さらに保存したXMLを書き換えて色々修正し、Tools->Show Marginsを選ぶと、次のように結合確率が表示される。

さらに、右クリック->Set evidenceで LightOn=True, HearBark=True と設定すると、次のように、各ノードの事後確率が表示される。

これによると、FamilyOut=Trueの事後確率はやはり0.8578...である。筆者は何か問題を読み間違えているのだろうか?

Posted at 18:31 in 数学 | WriteBacks (0)
WriteBacks

May 21, 2017

角交換振り飛車に大ポカ一発で沈む

昨日は毎年参加している地域の将棋大会だった。
今年は2回戦敗退だったが、予選は1勝1敗で抽選で勝ち抜け(3人のブロックで3人とも1勝1敗だった)、抽選で決勝1回戦はシードだったので、昨年の1回戦敗退より悪い内容だった。通常3勝かかる所、たった1勝で2回戦まで進出するとは、何とくじ運の良かったことか。

筆者はここ1年くらい将棋の勉強をしておらず、全て忘れてしまっており、先月からたまにネット将棋を指していたが以前のレートでは全く勝てず、今年は予選突破できないと思った。
昔から記憶力が無い方であるが、たった1年休んだくらいで全て忘れてしまい、レートが200も下がるのでは、筆者は将棋に向いてないのだろうとつくづく思う。

2回戦の相手は昨年優勝のI藤さんだった。筆者が絶好調でもまず勝てない相手であるが、先手の筆者に次の局面のような感触の良い手が出た。

通常は4二の銀が4四に居るので、3四の歩を取っても響かないが、この形だと歩を取った後に3筋の歩を伸ばせる。3四の歩を受けるには△1二角と打つしかないが、形が悪いだろう。
筆者は通常、角交換振り飛車には▲6六歩のようにして角交換を拒否するのだが、1回戦で筆者が100回やっても勝てそうにないY田さんがI藤さんに対して▲6六歩と角交換を拒否して負けたのを見て、直前に何か別の展開をガラケーの自作アプリに仕込んだ棋譜の中から1つ探して、その通りに指してみたものである。そういうことをすると通常は相手の研究にはまるので、ろくなことにならないのだが、今回は功を奏した。
対して、後手のIさんは△3二飛と指した。

これを見た瞬間、チャンスだと思った。2三の地点が空いている。
その誘惑に駆られた上、一手前に長考したこともあり、じっくり考えようとは思わなかった。
▲3四角に△4五桂と両取りに跳ねられても▲同角で両方受かる、と、それ以上考えずに、10秒も使わずに▲3四角と指したら、△2五桂とされて、一発で撃沈してしまった。

あと5秒考えていればこの手に気付いただろう。有段者が何の意味もなく、△3二飛のような隙を作る手を指すはずがない、と、何故一瞬でも思わなかったのか。
△2五桂の後、▲同歩、△3四飛、▲2四歩とすれば、後手は歩切れで、と金ができて大差にはならなさそうだが、この局面では丁度△1五角があって、受かってしまう。

△3二飛の局面は激指14のPro+3でも評価値が+280であり、少しリードしていたのは間違いない。その後、▲3四角ではなく、▲2九飛 △5四歩 ▲4八金と桂馬に紐を付け、△1二角 ▲6六歩 △6四歩 ▲1六歩のように進めれば、まあまあ指しやすそうである。

ここまでの手順は激指14のPro+以上の手を続けたものであり、評価値は+228である。

まあ、相手が相手なだけに、こう進んでもまず勝てなかっただろうが…

See more ...

Posted at 22:44 in 将棋 | WriteBacks (0)
WriteBacks

MacPortsでmaximaをインストールするとエラーになるのを回避

現在、MacPortsを使って

sudo port install maxima
すると、下のようなエラーになって失敗してしまう。(macOS Sierra 10.12.4で確認)
../../doc/info//errormessages.texi:296: `Warning messages' has no Up field (perhaps incorrect sectioning?).
../../doc/info//errormessages.texi:162: Prev field of node `Operators of arguments must all be the same' not pointed to.
../../doc/info//errormessages.texi:152: This node (Only symbols can be bound) has the bad Next.
../../doc/info//errormessages.texi:152: Next field of node `Only symbols can be bound' not pointed to (perhaps incorrect sectioning?).
../../doc/info//errormessages.texi:204: This node (out of memory) has the bad Prev.
../../doc/info//errormessages.texi:8: `Error messages' has no Up field (perhaps incorrect sectioning?).
makeinfo: Removing output file `/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_macports_release_tarballs_ports_math_maxima/maxima/work/maxima-5.39.0/doc/info/maxima.info' due to errors; use --force to preserve.
make[3]: *** [maxima.info] Error 1

原因は、makeinfoのバージョンが古いからのようだ。
http://maxima-discuss.narkive.com/KeLR9qhb/can-t-install-5-39
に、makeinfoのバージョンが4.xだとこうなることが書かれている。 実際、macOS Sierraで makeinfo --version すると、(GNU texinfo) 4.8と表示される。

そこで、

sudo port install texinfo
(GNU texinfo 6.3のmakeinfoがインストールされる)してから再度
sudo port install maxima
すると、上記のエラーは出なくなった。Activationの段階で
--->  Installing maxima @5.39.0_3+xmaxima
--->  Activating maxima @5.39.0_3+xmaxima
Error: Failed to activate maxima: Image error: /opt/local/bin/maxima already exists and does not belong to a registered port.  Unable to activate port maxima. Use 'port -f activate maxima' to force the activation.
というエラーになるが、メッセージの通り、
sudo port -f activate maxima
とすると、一応wxMaximaと併用しても問題なく動いた。

See more ...

Posted at 21:22 in PC一般 | WriteBacks (0)
WriteBacks

May 06, 2017

JediにAutoCompleよりCompanyModeを優先させる

2ヶ月前にCarbon EmacsのPython環境を整備したばかりなのだが、MacのOSを10.7.5から10.12.4にバージョンアップすると、Carbon Emacsがまともに動かなくなってしまった。起動はするのだが、すぐに固まってしまう。しかも、その後distnotedというプロセスが全てのCPUを奪い続けて、Macが激重になる。
この現象はOS X 10.9+Emacs 24.3で起こるらしく、Carbon Emacs(Emacs 22)でも起こったという情報は見つけられなかったが、おそらく同じ問題である。どちらかと言うとOSのバグなのだが、現時点ではEmacsを24.4以降にバージョンアップする以外に解決方法が見当たらない。

その為、長年お世話になったCarbon Emacsを手放し、Emacsの最新版である25.2を使うことにした。

EmacsWikiのPython Programming In EmacsのページにはPythonの開発環境を便利にする方法が色々書かれているが、筆者は高機能なPythonの開発環境を使いたい時はSpyderを使っており、EmacsのPython環境はPython.elでPython3が使えて、もう少し便利な補完が効けば十分なので、Jediだけを追加インストールすることにした。

Emacs 25.2にbuilt-inのPython.elはPython3に対応しているのだが、MacPortsでpython35をインストールして、M-x customize-group -> pythonして"Python Shell Interpreter"をpython3にすると、Warningが出まくり、妙に不安定だった。M-x list-packagesしてpython packageを0.25.2にバージョンアップすると少し改善したが、完全には直らなかった。
さらに、Jediをインストールすると、これまた不安定で、時々補完候補が出る前にEmacsが固まった。(C-gで抜けることはできる)

Emacs 24の最新版である24.5.1ではこの問題は起こらなかったので、当面、EmacsでPythonのコードを書く時は24.5.1を使うことにした。

Jediのインストールは、

(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(package-initialize)
としてpackage.elにMELPAのリポジトリを登録し、M-x list-packagesしてjediをインストールし、Jedi.elのドキュメントに従ってセットアップした。

なお、Emacs25でjediをインストールすると、Emacs24で"Symbol's function is void: cl-struct-define"というエラーになった。これはjediに限らず、よくあることだそうで、Emacsの24と25を併用する場合、package.elで何かをインストールするならEmacs24でする方が良さそうだ。

さて、JediはAutoCompleteとCompanyModeの両方に対応しているが、package.elで"jedi"をインストールするとAutoCompleteが使われる。"company-jedi"をインストールするとCompanyModeが使われるのだが、"jedi"と"company-jedi"の両方をインストールすると、AutoCompleteが優先される。特にAutoCompleteに不満は無く、和製なので贔屓したいが、色々読んでいると、世界的には、日本でも現在は、CompanyModeの方が人気があるようなので、何が良いのかを知るために、これからしばらくはCompanyModeを積極的に使うべく、両方をインストールしてCompanyModeをデフォルトにすることに決めた。

しかし、.emacsや.emacs.d/init.elでCompanyModeを優先する適当な方法がわからなかった。Python modeにしてM-x auto-complete-modeとすればAutoCompleteのON/OFFが切り替わり、OFFだとCompanyModeが使われるのだが、Emacs Lispで(auto-complete-mode)としてもON/OFFが切り替わらず、auto-complete-mode関数にはOFFにする引数も無いのである。auto-complete-mode関数のソースコードを見ると、"(if auto-complete-mode ..."とあるので、

(setq auto-complete-mode nil)
(auto-complete-mode)
とすれば良さそうに思ったが、これでもOFFにならない。
但し、(setq auto-complete-mode nil)すると、即座にAutoCompleteがOFFになる。このことを使って、試行錯誤の末、.emacs等に
(add-hook 'python-mode-hook 'jedi:setup)
よりも前のどこかに
(add-hook 'python-mode-hook
(lambda () (setq auto-complete-mode nil)))
と書けば、Python mode開始時にAutoCompleteがOFFになり、CompanyModeが使われることがわかった。

See more ...

Posted at 23:32 in PC一般 | WriteBacks (0)
WriteBacks

Apr 09, 2017

ROC曲線を理解する

2値の予測(判別、識別、…)に用いる特徴量の良し悪しを評価する1つの方法として、ROC曲線というものがある。
実際は正で予測も正であるデータの数をTP(True Positive)、
実際は負で予測も負であるデータの数をTN(True Negative)、
実際は負で予測は正であるデータの数をFP(False Positive)、
実際は正で予測は負であるデータの数をFN(False Negative)、
と呼ぶ時、
TPR(True Positive Ratio)=TP/(TP+FN)を縦軸、
FPR(False Positive Ratio)=FP/(FP+TN)を横軸、
としたグラフである。

ROC曲線の例
ROC curve sample

ROC曲線は、必ず(0,0)から始まって(1,1)で終わる。
特徴量が全く予測の役に立たない、ランダムな値であれば、TPR=FPRの線になる。
ROC曲線より下の面積、AUR(Area Under ROC curve)(または単にAUC(Area Under the Curve))が大きいほど、特徴量の値の全域に渡って良い特徴量だとされる。 理想的な特徴量だと、ROC曲線はFPR=0とTPR=1の線になる。

ROC曲線は機械学習で識別器の評価によく用いられるらしいので、とりあえず覚えておこうと思ったのだが、筆者はこれの理解にえらく苦労したので、調べたことや考えたことをメモする。
統計学の検定と同様、こういう確率と論理を組み合わせたものは、人によって向き不向きがあるのだと思いたい。

TP,TN,FP,FNの関係を再度整理すると、次のようになる。

予測

TPFN (Type II error)
FP (Type I error)TN
PやNは予測がPositiveかNegativeかであり、TやFはそれが正解かどうかである。
FPは誤検出のことであり、統計学の検定でも使われる「第一種の過誤」(検定では帰無仮説を棄却できないのに棄却する条件に誤ってヒットしてしまうこと)である。
FNは検出不能であり、「第二種の過誤」(検定では帰無仮説が誤りなのに棄却する条件にヒットしないこと)である。

予測の精度に関する尺度としては、Accuracy, Presicision, Recall, F値があり、それぞれ次のように定義される。
Accuracy = (TP+TN) / (TP+TN+FP+FN)
予測の正解率。
Precision = TP / (TP+FP)
Positiveと予測される中の正解率。
Recall = TP / (TP+FN)
実際にPositiveの内、Positiveと予測される割合。検出力、Sensitivity。
F値(F-measure, F1 score) = ((Precision-1 + Recall-1)/2)-1
PrecisionとRecallの調和平均。統計学のF分布に従うF値とは関係ない。
PrecisionとRecallはトレードオフの関係にあるので、それらをバランス良く合成した尺度。

予測の精度はAccuracyで評価するのが簡単だが、実際の正のデータ数と負のデータ数に偏りがあると、データ数が少ない方の正解率が低くても、データ数が多い方の正解率が高ければAccuracyが高くなってしまうので、Accuracyだけでは適切に評価できない。
そのような場合にPrecisionやRecallが用いられるが、これらは一般に特徴量の閾値によってトレードオフの関係があり、セットで評価しないといけないので、単純比較には向かない。そこで用いられるスカラー値が、F値や、ROC曲線のAUCである。
Precision-Recall曲線のAUCも使われることがあるが、Presicionは実際の正のデータの割合に依存するので、正のデータの割合が同じでないと比較には使えない。実際の正のデータの割合が極端に小さい場合など、Precisionが大きな意味を持つ場合にはPrecision-Recall曲線が用いられる。

ROC曲線は、TPR=TP/(TP+FN)とFPR=FP/(FP+TN)のグラフである。TPRを陽性率、FPRを偽陽性率と呼ぶこともある。TPRはRecallと同じである。FPRはfall-out(副産物)と呼ばれることもある。

次の図の3つのROC曲線が、正のデータと負のデータがどのように分布する特徴量に対応するかを考えてみる。
ROC curve sample 2

例えば、次のような分布になる特徴量だと、青いROC曲線になる。
distribution of totally independent feature
横軸は特徴量、縦軸は赤い部分が正のデータの分布、青い部分が負のデータの分布を表している。このグラフでは、正のデータも負のデータも一様分布している。閾値tより右ならPositive、左ならNegativeと予測する時、tを右端から左に動かすと、TPRもFPRも0から1に向かって増大するが、常にTPR=FPRである。正のデータと負のデータの割合はグラフの形状には関係しない。

次のような、正のデータと負のデータが完全に分かれる理想的な特徴量だと、緑のROC曲線になる。
distribution of ideal feature
tを右端から左に動かすと、FPR=0のままTPRが0から1に変化し、青のゾーンに入ると、FPRが0から1に変化する。

次のような分布だと、赤いROC曲線になる。
distribution of which makes ROC curve perfect arc
tを右端から左へ動かすと、FPRよりもTPRの方が早く上昇する。なるべく正のデータと負のデータの分布が分離している良い特徴量ほどFPRが上昇する前にTPRが上昇するので、AUCが大きくなることがわかる。

AUCはどれくらいだと良いか、という基準は一般的なものも色々あるようだが、大体、最低0.7は無いと有効ではないとされるようである。

なお、特徴量の最良の閾値(cut-off)はROC曲線の(0,1)に最も近い点とする、という方法を複数の箇所で目にしたが、明確な理論的根拠がある訳ではなく、必ずしもそれに限定されないようである。そもそも、(0,1)に最も近いというのがユークリッド距離で良いのかどうかがわからない。

See more ...

Posted at 20:30 in PC一般 | WriteBacks (0)
WriteBacks

Mar 31, 2017

pandasでmergeせずにgroupbyで間接参照したい

この前、pandasを使っていて、次のような感じの、関連する2つのテーブル、access_logとchoice_logがある時に、結合したテーブルを作らずにchoice毎のtimestampの最小値を求めたかったのだが、どう書けば良いのかわからなかった。

import pandas as pd
import numpy as np
access_log = pd.DataFrame({'session': [100, 101, 102, 103, 104, 105, 106, 107, 108, 109],
                           'timestamp': [314, 159, 265, 358, 979, 323, 846, 264, 338, 327]})
choice_log = pd.DataFrame({'session': [100, 100, 101, 102, 102, 103, 104, 104, 105, 106, 106, 107, 108, 108, 109],
                           'choice':  ['A', 'B', 'C', 'D', 'E', 'A', 'B', 'C', 'D', 'E', 'A', 'B', 'C', 'D', 'E']})
>>> access_log
   session  timestamp
0      100        314
1      101        159
2      102        265
3      103        358
4      104        979
5      105        323
6      106        846
7      107        264
8      108        338
9      109        327
>>> choice_log
   choice  session
0       A      100
1       B      100
2       C      101
3       D      102
4       E      102
5       A      103
6       B      104
7       C      104
8       D      105
9       E      106
10      A      106
11      B      107
12      C      108
13      D      108
14      E      109
>>> 

結合テーブルを作るなら、次のように書ける。

merged = choice_log.merge(access_log, on='session', how='left')
result = merged.groupby('choice')['timestamp'].min()
>>> result
choice
A    314
B    264
C    159
D    265
E    265
Name: timestamp, dtype: int64
>>> 

実際にあったテーブルは巨大で、他にも列がたくさんあり、単純に結合テーブルを作るとRAMが足りなくなってメモリスワップが多発したので、結合テーブルを作らずにこれと同じことがしたかったのだが、その書き方がわからなかった。
結局access_log.set_index('session').to_dict()のようにして一時的なdictを作って、スワップを多発させながら処理してしまった。
それが心残りだったので、改めてpandasのドキュメントを拾い読みしながら方法を探してみた。

  1. 単純に、別のテーブルを参照する関数をSeries.mapに渡す
    def session_to_timestamp(session_series):
        return session_series.map(lambda x: access_log[access_log.session==x]['timestamp'].iat[0])
    
    result = choice_log.groupby('choice').agg(lambda x: session_to_timestamp(x).min())
    

    Seriesの先頭の要素を取り出す方法には、.iat[0]の他に.iloc[0]や.values[0]などがあり、筆者が試した所values[0]の方が速かったりしたが、pandasのドキュメントに書かれているのはilocとiatなので、ここでは添字が整数なら高速なiatを用いた。

  2. リスト内包表現(list comprehension)で別のテーブルを参照する
    def session_to_timestamp(session_series):
        return [access_log[access_log.session==x]['timestamp'].iat[0] for x in session_series]
    
    result = choice_log.groupby('choice').agg(lambda x: min(session_to_timestamp(x)))
    

    リストにはminメソッドが無いので、session_to_timestamp(x).min()とはできない。

  3. isinを使ったBoolean Indexingで別の表のサブセットを得る
    def session_to_timestamp(session_series):
        return access_log[access_log.session.isin(session_series.values)]['timestamp']
    
    result = choice_log.groupby('choice').agg(lambda x: session_to_timestamp(x).min())
    
  4. 別の表からSeriesを作ってSeries.mapに渡す
    def session_to_timestamp(session_series):
        return session_series.map(access_log.set_index('session').timestamp)
    
    result = choice_log.groupby('choice').agg(lambda x: session_to_timestamp(x).min())
    

    一見シンプルで美しそうだが、set_index()はコピーを返すので、timestampの一時的なdictを作るのと変わらない。しかも、グループ数だけ新たなテーブルを作るので、無駄である。

これらの処理時間を色々測ってみたが、2つのテーブルのサイズやグループの数によって変わり、どう比較すれば良いかわからなかったので、省略する。
大まかな傾向としては、1.と2.の処理時間はchoice_logのサイズに依存し、3.と4.の処理時間はsession_logのサイズに依存するようだった。4.はset_indexした中間テーブルを事前に作っておくと高速化するが、それでも、大抵の場合3.が一番速かった。
いずれの方法も最速になる場合があるようなので、場合毎に色々試してみるしかなさそうである。

肝心のメモリ使用量は、適当な測り方がわからなかった。
そもそも、スワップしながらの処理時間が問題だったので、単純にメモリ使用量では測れないと思う。

他にも、以下のような方向で書き方を考えてみたが、うまくできなかった。

  • groupbyでaggregateでなくtransformしてmin()
    transformする時に別のテーブルを参照することを考えたが、transformするとgroup解除されてしまうので、使えなかった。transformする時にmin()するのなら、min()した値を増殖させるだけ無駄なので、確実にaggregateの方が効率が良い。
  • pandas.DataFrame.lookupを使う
    引数としてindexしか受けられないので、使えなかった。
  • pandas.DataFrame.joinを使う
    pandas.DataFrame.mergeを使うのと変わらなかった。

そもそも、lambda式を使わずに書く方法は無いのだろうか。
teratailとかStack Overflowとかで聞いた方が早いか。

See more ...

Posted at 20:00 in PC一般 | WriteBacks (0)
WriteBacks

Mar 05, 2017

pandas.read_csv+numpy.bincountでエラー

ちょっと前に、はやりのAIのプログラミングでよく使われるPythonとNumPyとPandasを使い始めたのだが、PandasでCSVファイルを読み込んで、各ラベルの出現回数を得る為にNumPyのbincountメソッドを使うと、次のようなエラーが出て、困った。

TypeError: Cannot cast array data from dtype('int64') to dtype('int32') according to the rule 'safe'
その時使った環境は、Windows 7(32bit版)+Python 3.5.2(Anaconda 4.1.1 (32-bit))である。Mac OS Xでは出なかった。

これは、32bitのPythonを使っていると起こることらしい。例えば、32bit Pythonで次のプログラムを実行すると、同じエラーが出る。

import numpy as np
import pandas as pd
import io

data = np.random.randint(10, size=30)
buf = io.StringIO("\n".join(str(x) for x in data))
df = pd.read_csv(buf, header=None)
x = df[0].values
print(x)
print(np.bincount(x))	#Error on 32bit Python
これは、Pandasが32bit Pythonでもint64を使うのが原因のようである。

このエラーを回避するには、bincountに渡すデータの型をint32にすれば良い。

print(np.bincount(x.astype('int32')))	#also OK on 32bit Python
出力例
[1 0 6 7 1 7 7 6 9 5 6 2 8 0 7 6 7 8 9 7 8 9 8 0 2 1 2 6 0 3]
[4 3 3 1 0 1 5 6 4 3]

または、np.unique(return_counts=True)を使う方法があり、こちらの方が、大抵の場合はnp.bincountを使うよりも好ましいとされるようである。

print(np.unique(x, return_counts=True))
出力例
(array([0, 1, 2, 3, 5, 6, 7, 8, 9]), array([4, 3, 3, 1, 1, 5, 6, 4, 3]))
確かに、np.unique(return_counts=True)の方が、データに負の値があっても使えるし、大きな値が混ざってても配列が巨大にならないので、安全そうである。

なお、今動作しているPythonが32bitか64bitかを判定する方法は、いくつかあるようである。 例1

import platform
platform.architecture()
出力(上がMacOSX、下がWin32)
('64bit', '')
('32bit', 'WindowsPE')
例2
import sys
"%x" % sys.maxsize
出力(上がMacOSX、下がWin32)
'7fffffffffffffff'
'7fffffff'
例3(platform.architecture()の実装にも使われている方法)
import struct
struct.calcsize("P") * 8
出力(上がMacOSX、下がWin32)
64
32

See more ...

Posted at 20:47 in PC一般 | WriteBacks (0)
WriteBacks

Mar 01, 2017

Carbon EmacsにPython 3環境導入

筆者はMacで未だにEmacs 22ベースのCarbon Emacsを多用している。Emacs 24ベースのCocoa Emacsもインストールはしているのだが、色々な環境をCarbon Emacsに作ってしまっているので、移行するのが億劫なのである。

最近、Python 3を使い始めたのだが、Carbon Emacsのpython.elはPython 2にしか対応していないので、何とかPython 3に対応させる方法は無いかと探した結果、
http://www.loveshack.ukfsn.org/emacs/
から
python.el
emacs.py
sym-comp.el
の3つをダウンロードして、Emacs.app/内に置けば良いことがわかった。(python.elとemacs.pyは既にあるものを置換、sym-comp.elはpython.elと同じディレクトリに追加)
そして、Emacsを立ち上げて、M-x customize-groupとし、
"Python Default Version" = 3
"Python Python Command" = python3
にすれば完成である。

これで、C-c TABとM-TABを駆使すればシンボルの補完ができて、まあまあコーディングが楽になるのだが、やっぱり補完機能は便利にしたいので、
Pythonの補完をEmacsでシンプルに最小労力で手早く使えるようにする - 牌語備忘録 -pygo
を参考にして、auto-complete.el + ac-python.elをインストールした。
auto-complete.elは、Emacs 22で動作実績のある、auto-complete-1.3.1.tar.bz2をどこかから入手した。

そして、.emacsに次の4行を書けば完成である。

(require 'auto-complete)
(require 'auto-complete-config)
(ac-config-default)
(require 'ac-python)

これで、python-modeにして、import mathと書いてC-c TABして、math.と打つと、math.sqrtやらmath.piやらが補完候補として自動的に現れるようになった。

See more ...

Posted at 23:37 in PC一般 | WriteBacks (0)
WriteBacks