Congratulations!

[Valid RSS] This is a valid RSS feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: http://ynomura.dip.jp/index.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <rss version="2.0">
  3.   <channel>
  4.      <title>Weblog on mebius.tokaichiba.jp</title>
  5.      <link>http://ynomura.dip.jp/</link>
  6.      <description>かつてJR横浜線 十日市場駅近くのMebius (CPU:Pentium 150MHz)より発信していたウェブログです。</description>
  7.      <language>ja</language>
  8.      <copyright>Copyright 2017</copyright>
  9.      <lastBuildDate>Mon, 19 Jun 2017 22:35:46 +0900</lastBuildDate>
  10.      <generator>http://www.sixapart.com/movabletype/</generator>
  11.      <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  12.  
  13.            <item>
  14.         <title>scikit-learnのナイーブベイズ分類器を使ってみる</title>
  15.         <description><![CDATA[<p><a href="/archives/2017/05/weka.html">前回</a>のFamily Out Problemの確率モデル(下図)を題材に、ナイーブベイズ分類器を使ってみる。</p>
  16.  
  17. <p><img src="/archives/images/FamilyOutProblem.svg" width=400 height=300 /><br />
  18. Family Out Problem</p>
  19.  
  20. <p>この問題において、family-out以外の変数の真偽値が与えられた時にfamily-out=TRUEかどうかを判定するよう、ナイーブベイズ分類器を学習させてみる。</p>
  21.  
  22. <blockquote><pre>
  23. import numpy as np
  24. import matplotlib.pyplot as plt
  25. from sklearn.naive_bayes import BernoulliNB
  26. from sklearn.metrics import precision_recall_fscore_support
  27. from sklearn.metrics import roc_curve, auc
  28.  
  29. def generate_sample():
  30.    "Sample data generator of the Family Out problem"
  31.    fo = np.random.binomial(1, 0.15)
  32.    bp = np.random.binomial(1, 0.01)
  33.    lo = np.random.binomial(1, (0.05, 0.6)[fo])
  34.    do = np.random.binomial(1, ((0.3, 0.97), (0.9, 0.99))[fo][bp])
  35.    hb = np.random.binomial(1, (0.01, 0.7)[do])
  36.    return [fo, bp, lo, do, hb]
  37.  
  38. # Generate training data and test data
  39. train_data = np.array([generate_sample() for _ in range(1000)])
  40. test_data = np.array([generate_sample() for _ in range(100)])
  41.  
  42. X_train = train_data[:, 1:5] # other than fo
  43. y_train = train_data[:, 0] # only fo
  44. X_test = test_data[:, 1:5] # other than fo
  45. y_test = test_data[:, 0] # only fo
  46.  
  47. # Train a Naive Bayes classifier
  48. clf = BernoulliNB()
  49. clf.fit(X_train, y_train)
  50.  
  51. # Evaluate with training data
  52. y_pred = clf.predict(X_train)
  53. metrics = precision_recall_fscore_support(y_train, y_pred)
  54. print('Evaluation with training data')
  55. print('Class FamilyOut=False: Precision={:.3f}, Recall={:.3f}, F-measure={:.3f}'.format(metrics[0][0], metrics[1][0], metrics[2][0]))
  56. print('Class FamilyOut=True : Precision={:.3f}, Recall={:.3f}, F-measure={:.3f}'.format(metrics[0][1], metrics[1][1], metrics[2][1]))
  57.  
  58. # Evaluate with test data
  59. y_pred = clf.predict(X_test)
  60. metrics = precision_recall_fscore_support(y_test, y_pred)
  61. print('Evaluation with test data')
  62. print('Class FamilyOut=False: Precision={:.3f}, Recall={:.3f}, F-measure={:.3f}'.format(metrics[0][0], metrics[1][0], metrics[2][0]))
  63. print('Class FamilyOut=True : Precision={:.3f}, Recall={:.3f}, F-measure={:.3f}'.format(metrics[0][1], metrics[1][1], metrics[2][1]))
  64.  
  65. # Draw ROC curve
  66. y_train_post = clf.predict_proba(X_train)[:, 0]
  67. y_test_post = clf.predict_proba(X_test)[:, 0]
  68.  
  69. fpr, tpr, thresholds = roc_curve(y_train, y_train_post, pos_label=0)
  70. roc_auc = auc(fpr, tpr)
  71. plt.plot(fpr, tpr, 'k-', lw=2, label='ROC for training data (area = {:.2f})'.format(roc_auc))
  72.  
  73. fpr, tpr, thresholds = roc_curve(y_test, y_test_post, pos_label=0)
  74. roc_auc = auc(fpr, tpr)
  75. plt.plot(fpr, tpr, 'k--', lw=2, label='ROC for test data (area = {:.2f})'.format(roc_auc))
  76.  
  77. plt.xlabel('False Positive Rate')
  78. plt.ylabel('True Positive Rate')
  79. plt.title('ROC curve of BernoulliNB')
  80. plt.legend(loc="lower right")
  81.  
  82. plt.show()
  83. </pre></blockquote>
  84.  
  85. <p>問題のモデルに従って学習用データとテストデータをランダムに生成し、sklearn.naive_bayes.BernoulliNBの分類器を学習させ、テストデータを分類させ、family-out=FALSEとfamily-out=TRUEのそれぞれについてPrecision, Recall, F値を計算している。<br />
  86. 加えて、予測したfamily-out=FALSE/TRUEの確率から、ROC曲線とAUCを出力している。
  87. </p>
  88.  
  89. <p>出力例<br />
  90. <blockquote><pre>
  91. Evaluation with training data
  92. Class FamilyOut=False: Precision=0.936, Recall=0.983, F-measure=0.959
  93. Class FamilyOut=True : Precision=0.847, Recall=0.589, F-measure=0.695
  94. Evaluation with test data
  95. Class FamilyOut=False: Precision=0.923, Recall=0.988, F-measure=0.955
  96. Class FamilyOut=True : Precision=0.889, Recall=0.533, F-measure=0.667
  97. </pre></blockquote>
  98.  
  99. ROC曲線<br />
  100. <img src="/archives/images/naive_bayes01.png" alt="ROC curve" width=320 height=240 /><br />
  101. その時のtraining_dataとtest_data(.arff形式)<br />
  102. <a href="/archives/misc/family_out_train.arff">family_out_train.arff</a><br />
  103. <a href="archives/misc/family_out_test.arff">family_out_test.arff</a><br />
  104. </p>
  105.  
  106. <p>ナイーブベイズ分類器には、同じクラスのデータでは全ての特徴が独立に出現する、つまりbp,lo,do,hbに依存関係が無く、これらがTRUEになる確率はfoの値だけで決まるという仮定があるが、この問題ではbp,do,hbに依存関係があるので、ベイジアンネットワークの方がうまく学習できると考えられる。<br />
  107. なのでベイジアンネットワークで分類した場合の性能と比較したいが、scikit-learn(0.18)にベイジアンネットワークが無いので、代わりにWeka 3.8.1のBayesNetを用いて学習用データで学習させ、テストデータを分類した結果と比較してみる。</p>
  108.  
  109. <p>Wekaの操作手順<br />
  110. <ol>
  111. <li>Weka ExplorerのPreprocessタブでOpen file...ボタンを押し、<a href="/archives/misc/family_out_train.arff">family_out_train.arff</a>を開く</li>
  112. <li>ClassifyタブでClassifierとしてBayesNetを選択する</li>
  113. <li>"BayesNet -D ..."とあるフィールドをクリックしてパラメーター設定画面を開き、searchAlgorithmのフィールドをクリックして、initAsNaiveBayes=False, maxNrOfParents=2に変更</li>
  114. <li>Test optionsのSupplied test setのボタンを押し、<a href="archives/misc/family_out_test.arff">family_out_test.arff</a>を開き、Classとしてfamily-outを選択</li><li>クラスをfamily-outを選択し、Startボタンを押す</li>
  115. </ol>
  116.  
  117. 上記と同じデータを使った出力例<br />
  118. <blockquote><pre>
  119. === Run information ===
  120.  
  121. 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
  122.  
  123. === Detailed Accuracy By Class ===
  124.  
  125.                 TP Rate  FP Rate  Precision  Recall   F-Measure  MCC      ROC Area  PRC Area  Class
  126.                 0.988    0.467    0.923      0.988    0.955      0.651    0.889     0.967     0
  127.                 0.533    0.012    0.889      0.533    0.667      0.651    0.889     0.648     1
  128. Weighted Avg.    0.920    0.398    0.918      0.920    0.911      0.651    0.889     0.919    
  129.  
  130. === Confusion Matrix ===
  131.  
  132.  a  b   <-- classified as
  133. 84  1 |  a = 0
  134.  7  8 |  b = 1
  135. </pre></blockquote>
  136. </p>
  137.  
  138. <p>BernoulliNBのテストデータに対する出力と、Precision, Recall, F-measureが完全に一致している。</p>
  139.  
  140. <p>WekaのBayesNetのデフォルト設定では正しいネットワークが学習されなかったが、上記手順の3.のように設定を変えると、大体次のように正しいネットワークになった。<br />
  141. <img src="/archives/images/bayesnet04.png" alt="" /></p>
  142.  
  143. <p>BernoulliNBの性能には試行毎にばらつきがあったが、1000回の平均を取ってみたのが次の値であり、上記の結果は特別に良い例ではない。
  144. <blockquote><pre>
  145. Average with training data
  146. Class FamilyOut=False: Precision=0.925, Recall=0.982, F-measure=0.952
  147. Class FamilyOut=True : Precision=0.844, Recall=0.545, F-measure=0.661
  148. Average with test data
  149. Class FamilyOut=False: Precision=0.925, Recall=0.982, F-measure=0.952
  150. Class FamilyOut=True : Precision=0.842, Recall=0.544, F-measure=0.651
  151. Average of AUC with training data=0.894
  152. Average of AUC with test data=0.895
  153. </pre></blockquote>
  154. また、計10回、同じデータでWekaのBayesNetの性能と比較した所、Precision, Recall, F-measureについては、8回は一致していた。<br />
  155. ROC曲線のAUCはWekaのBayesNetの方が高いことが多かったが、BernoulliNBでも大体0.85-0.90の範囲であり、十分に高かった。<br />
  156. 従って、この確率モデルに対して、ナイーブベイズ分類器は予測性能が十分に高いと言える。</p>
  157.  
  158. <p>なお、ここまでの結果では、学習データに対する各種性能値とテストデータに対する値にほぼ差が無いが、これは学習データのサンプル数が1000と十分に多く、偏りが無いからである。これを100にすると、次のように、テストデータに対する成績が少し下がるが、それでも、学習データだけに対して大幅に成績が良い「過学習(overfitting)」の状態と言える程ではない。<br />
  159. <br />
  160. 学習データ数が100の1000試行の平均<br />
  161. <blockquote><pre>
  162. Average with training data
  163. Class FamilyOut=False: Precision=0.931, Recall=0.963, F-measure=0.945
  164. Class FamilyOut=True : Precision=0.793, Recall=0.582, F-measure=0.650
  165. Average with test data
  166. Class FamilyOut=False: Precision=0.926, Recall=0.955, F-measure=0.938
  167. Class FamilyOut=True : Precision=0.767, Recall=0.564, F-measure=0.620
  168. Average of AUC with training data=0.899
  169. Average of AUC with test data=0.890
  170. </pre></blockquote>
  171. </p>
  172. ]]></description>
  173.         <link>http://ynomura.dip.jp/archives/2017/06/scikitlearn.html</link>
  174.         <guid>http://ynomura.dip.jp/archives/2017/06/scikitlearn.html</guid>
  175.                  <category domain="http://www.sixapart.com/ns/types#category">数学</category>
  176.        
  177.        
  178.         <pubDate>Mon, 19 Jun 2017 22:35:46 +0900</pubDate>
  179.      </item>
  180.            <item>
  181.         <title>Wekaでベイジアンネットワークの事後確率を計算</title>
  182.         <description><![CDATA[<p>ベイジアンネットワークの復習をしていて、<a href="http://www.orsj.or.jp/archive2/or58-04/or58_4_191.pdf">確率的グラフィカルモデル‐ベイジアンネットワークとその周辺‐</a>(オペレーションズ・リサーチ 2013年4月号)という記事を見つけた。その中に、Family Out Problemという有名な例題(下図)の紹介があり、p.194に、
  183. <blockquote>
  184. 表1~3で与えられたCPTの値と式(11)を利用して丹念に計算することにより
  185. P(X<sub>1</sub>=1|X<sub>3</sub>=1,X<sub>5</sub>=1)=0.7577···という結論を得る.
  186. </blockquote>
  187. と書かれていたので、これを自力で計算できたらベイジアンネットワークを理解できたことにしよう、と思って、丹念に計算してみたら、その値にならなかった。</p>
  188.  
  189. <p><img src="/archives/images/FamilyOutProblem.svg" width=400 height=300 /><br />
  190. Family Out Problem</p>
  191. <p>ここでは、<br />
  192. X<sub>1</sub>: Family Out<br />
  193. X<sub>2</sub>: Bowel Problem<br />
  194. X<sub>3</sub>: Light On<br />
  195. X<sub>4</sub>: Dog Out<br />
  196. X<sub>5</sub>: Hear Bark<br />
  197. (それぞれ2値の確率変数)であり、それぞれの条件付き確率は次の通りである。<br />
  198. P(X<sub>1</sub>=1) = 0.15<br />
  199. P(X<sub>2</sub>=1) = 0.01<br />
  200. P(X<sub>3</sub>=1 | X<sub>1</sub>=0) = 0.05<br />
  201. P(X<sub>3</sub>=1 | X<sub>1</sub>=1) = 0.6<br />
  202. P(X<sub>4</sub>=1 | X<sub>1</sub>=0, X<sub>2</sub>=0) = 0.3<br />
  203. P(X<sub>4</sub>=1 | X<sub>1</sub>=0, X<sub>2</sub>=1) = 0.97<br />
  204. P(X<sub>4</sub>=1 | X<sub>1</sub>=1, X<sub>2</sub>=0) = 0.9<br />
  205. P(X<sub>4</sub>=1 | X<sub>1</sub>=1, X<sub>2</sub>=1) = 0.99<br />
  206. P(X<sub>5</sub>=1 | X<sub>4</sub>=0) = 0.01<br />
  207. P(X<sub>5</sub>=1 | X<sub>4</sub>=1) = 0.7
  208. </p>
  209. <p><img src="/archives/images/bayesnet01.png" alt="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)}" width=462 height=38 /><br />
  210. なので、Pythonで
  211. <blockquote><pre>
  212. P00101 = 0.85 * 0.99 * 0.05 * 0.7 * 0.01
  213. P00111 = 0.85 * 0.99 * 0.05 * 0.3 * 0.7
  214. P01101 = 0.85 * 0.01 * 0.05 * 0.03 * 0.01
  215. P01111 = 0.85 * 0.01 * 0.05 * 0.97 * 0.7
  216. P10101 = 0.15 * 0.99 * 0.6 * 0.1 * 0.01
  217. P10111 = 0.15 * 0.99 * 0.6 * 0.9 * 0.7
  218. P11101 = 0.15 * 0.01 * 0.6 * 0.01 * 0.01
  219. P11111 = 0.15 * 0.01 * 0.6 * 0.99 * 0.7
  220.  
  221. P35 = P00101 + P00111 + P01101 + P01111 + P10101 + P10111 + P11101 + P11111
  222. P135 = P10101 + P10111 + P11101 + P11111
  223. P1_35 = P135 / P35
  224. print(P1_35)
  225. </pre></blockquote>
  226. とすると、0.8578...という数値になった。どこか読み間違えたかと思って、
  227. <blockquote><pre>
  228. def prob(x1, x2, x3, x4, x5):
  229.    p = 1.0
  230.    p *= (0.85, 0.15)[x1]
  231.    p *= (0.99, 0.01)[x2]
  232.    p *= ((0.95, 0.05), (0.4, 0.6))[x1][x3]
  233.    p *= (((0.7, 0.3), (0.03, 0.97)), ((0.1, 0.9), (0.01, 0.99)))[x1][x2][x4]
  234.    p *= ((0.99, 0.01), (0.3, 0.7))[x4][x5]
  235.    return p
  236.  
  237. P135 = sum([prob(1, x2, 1, x4, 1)
  238.             for x2 in range(2)
  239.             for x4 in range(2)])
  240. P35 =  sum([prob(x1, x2, 1, x4, 1)
  241.             for x1 in range(2)
  242.             for x2 in range(2)
  243.             for x4 in range(2)])
  244. P1_35 = P135 / P35
  245. print(P1_35)
  246. </pre></blockquote>
  247. と書いてみたが、やはり0.8578...だった。
  248. </p>
  249. <p>上記の記事内の条件付き確率表に誤記があり、0.7577...というのは元の確率表で計算された値か、とも思ったが、どの文書のFamily Out Problemを見ても確率は同じだった。</p>
  250. <p>正解は何なのか、何らかのツールで確認しようと思って、Pythonのベイジアンネットワーク関連のツールを探したが、適当なものがなかなか見つからなかった。
  251. </p>
  252. <p><a href="http://scikit-learn.org/stable/">scikit-learn</a>には"Naive Bayes"のAPIはあるがベイジアンネットワークは見つからない。<br />
  253. <a href="https://pymc-devs.github.io/pymc/">PyMC</a>や<a href="http://bayespy.org/">BayesPy</a>は、きっとうまく使えばこの計算ができるのだろうが、ネットワークを定義して、CPT(conditional probability table、条件付き確率表)とevidence(観測値)を与えて事後確率を計算する直接的なサンプルコードが見つからなかったので、諦めた。<br />
  254. <a href="https://github.com/achille/pbnt">PBNT</a>にはそういうサンプルコードがあったので、使ってみたが、P(X<sub>1</sub>=1|X<sub>3</sub>=1,X<sub>5</sub>=1)=0.2018...という全然違う値が出力された。P(X<sub>5</sub>=1)=0.2831と、これは正しい値が出たので、ネットワークとCPTは合ってそうであり、事後確率を計算するにはengine.marginal()でなく別のメソッドを使わないといけないのかとも思ったが、よくわからなかった。
  255. </p>
  256. <p>Pythonを諦めてツールを探すと、<a href="http://www.cs.waikato.ac.nz/ml/weka/">Weka</a>でできることがわかった。Wekaは機械学習の勉強をするなら必修らしく、過去にインストールしていたので、やってみた。<br />
  257. Wekaを起動して、Tools->Bayes net editorを開くと、GUIがバグだらけ(Version 3.8.1, WindowsとMacとで確認)で使いにくいが、ノードを追加して右クリックしながらネットワークを作成し、Tools->Layoutでノードの配置を修正し、CPTを設定し、さらに保存したXMLを書き換えて色々修正し、Tools->Show Marginsを選ぶと、次のように結合確率が表示される。<br />
  258. <img src="/archives/images/bayesnet02.png" /><br />
  259. さらに、右クリック->Set evidenceで LightOn=True, HearBark=True と設定すると、次のように、各ノードの事後確率が表示される。<br />
  260. <img src="/archives/images/bayesnet03.png" />
  261. </p>
  262. <p>これによると、FamilyOut=Trueの事後確率はやはり0.8578...である。筆者は何か問題を読み間違えているのだろうか?</p>]]></description>
  263.         <link>http://ynomura.dip.jp/archives/2017/05/weka.html</link>
  264.         <guid>http://ynomura.dip.jp/archives/2017/05/weka.html</guid>
  265.                  <category domain="http://www.sixapart.com/ns/types#category">数学</category>
  266.        
  267.        
  268.         <pubDate>Mon, 29 May 2017 18:31:10 +0900</pubDate>
  269.      </item>
  270.            <item>
  271.         <title>角交換振り飛車に大ポカ一発で沈む</title>
  272.         <description><![CDATA[昨日は毎年参加している地域の将棋大会だった。
  273. 今年は2回戦敗退だったが、予選は1勝1敗で抽選で勝ち抜け(3人のブロックで3人とも1勝1敗だった)、抽選で決勝1回戦はシードだったので、<a href="/archives/2016/06/post_56.html">昨年の1回戦敗退</a>より悪い内容だった。通常3勝かかる所、たった1勝で2回戦まで進出するとは、何とくじ運の良かったことか。
  274.  
  275. 筆者はここ1年くらい将棋の勉強をしておらず、全て忘れてしまっており、先月からたまにネット将棋を指していたが以前のレートでは全く勝てず、今年は予選突破できないと思った。
  276. 昔から記憶力が無い方であるが、たった1年休んだくらいで全て忘れてしまい、レートが200も下がるのでは、筆者は将棋に向いてないのだろうとつくづく思う。
  277.  
  278. 2回戦の相手は昨年優勝のI藤さんだった。筆者が絶好調でもまず勝てない相手であるが、先手の筆者に次の局面のような感触の良い手が出た。
  279. <img src="/archives/images/20170521-1.png">
  280. 通常は4二の銀が4四に居るので、3四の歩を取っても響かないが、この形だと歩を取った後に3筋の歩を伸ばせる。3四の歩を受けるには△1二角と打つしかないが、形が悪いだろう。
  281. 筆者は通常、角交換振り飛車には▲6六歩のようにして角交換を拒否するのだが、1回戦で筆者が<a href="/archives/2011/07/3_2.html">100回やっても勝てそうにないY田さん</a>がI藤さんに対して▲6六歩と角交換を拒否して負けたのを見て、直前に何か別の展開を<a href="/archives/2013/08/post_47.html">ガラケーの自作アプリ</a>に仕込んだ棋譜の中から1つ探して、その通りに指してみたものである。そういうことをすると通常は相手の研究にはまるので、ろくなことにならないのだが、今回は功を奏した。
  282. 対して、後手のIさんは△3二飛と指した。
  283. <img src="/archives/images/20170521-2.png">
  284. これを見た瞬間、チャンスだと思った。2三の地点が空いている。
  285. その誘惑に駆られた上、一手前に長考したこともあり、じっくり考えようとは思わなかった。
  286. ▲3四角に△4五桂と両取りに跳ねられても▲同角で両方受かる、と、それ以上考えずに、10秒も使わずに▲3四角と指したら、△2五桂とされて、一発で撃沈してしまった。
  287. <img src="/archives/images/20170521-3.png">
  288. あと5秒考えていればこの手に気付いただろう。有段者が何の意味もなく、△3二飛のような隙を作る手を指すはずがない、と、何故一瞬でも思わなかったのか。
  289. △2五桂の後、▲同歩、△3四飛、▲2四歩とすれば、後手は歩切れで、と金ができて大差にはならなさそうだが、この局面では丁度△1五角があって、受かってしまう。
  290.  
  291. △3二飛の局面は激指14のPro+3でも評価値が+280であり、少しリードしていたのは間違いない。その後、▲3四角ではなく、▲2九飛 △5四歩 ▲4八金と桂馬に紐を付け、△1二角 ▲6六歩 △6四歩 ▲1六歩のように進めれば、まあまあ指しやすそうである。
  292. <img src="/archives/images/20170521-4.png">
  293. ここまでの手順は激指14のPro+以上の手を続けたものであり、評価値は+228である。
  294.  
  295. まあ、相手が相手なだけに、こう進んでもまず勝てなかっただろうが…]]></description>
  296.         <link>http://ynomura.dip.jp/archives/2017/05/post_59.html</link>
  297.         <guid>http://ynomura.dip.jp/archives/2017/05/post_59.html</guid>
  298.                  <category domain="http://www.sixapart.com/ns/types#category">将棋</category>
  299.        
  300.        
  301.         <pubDate>Sun, 21 May 2017 22:44:13 +0900</pubDate>
  302.      </item>
  303.            <item>
  304.         <title>MacPortsでmaximaをインストールするとエラーになるのを回避</title>
  305.         <description><![CDATA[<p>現在、MacPortsを使って
  306. <blockquote>
  307. sudo port install maxima
  308. </blockquote>
  309. すると、下のようなエラーになって失敗してしまう。(macOS Sierra 10.12.4で確認)
  310. <blockquote><pre>
  311. ../../doc/info//errormessages.texi:296: `Warning messages' has no Up field (perhaps incorrect sectioning?).
  312. ../../doc/info//errormessages.texi:162: Prev field of node `Operators of arguments must all be the same' not pointed to.
  313. ../../doc/info//errormessages.texi:152: This node (Only symbols can be bound) has the bad Next.
  314. ../../doc/info//errormessages.texi:152: Next field of node `Only symbols can be bound' not pointed to (perhaps incorrect sectioning?).
  315. ../../doc/info//errormessages.texi:204: This node (out of memory) has the bad Prev.
  316. ../../doc/info//errormessages.texi:8: `Error messages' has no Up field (perhaps incorrect sectioning?).
  317. 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.
  318. make[3]: *** [maxima.info] Error 1
  319. </pre></blockquote>
  320. </p>
  321. <p>原因は、makeinfoのバージョンが古いからのようだ。<br />
  322. <a href="http://maxima-discuss.narkive.com/KeLR9qhb/can-t-install-5-39">http://maxima-discuss.narkive.com/KeLR9qhb/can-t-install-5-39</a><br />
  323. に、makeinfoのバージョンが4.xだとこうなることが書かれている。
  324. 実際、macOS Sierraで<code>
  325. makeinfo --version
  326. </code>すると、(GNU texinfo) 4.8と表示される。
  327. </p>
  328. <p>そこで、
  329. <blockquote>
  330. sudo port install texinfo
  331. </blockquote>
  332. (GNU texinfo 6.3のmakeinfoがインストールされる)してから再度
  333. <blockquote>
  334. sudo port install maxima
  335. </blockquote>
  336. すると、上記のエラーは出なくなった。Activationの段階で
  337. <blockquote><pre>
  338. --->  Installing maxima @5.39.0_3+xmaxima
  339. --->  Activating maxima @5.39.0_3+xmaxima
  340. 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.
  341. </pre></blockquote>
  342. というエラーになるが、メッセージの通り、
  343. <blockquote>
  344. sudo port -f activate maxima
  345. </blockquote>
  346. とすると、一応wxMaximaと併用しても問題なく動いた。
  347. </p>]]></description>
  348.         <link>http://ynomura.dip.jp/archives/2017/05/macportsmaxima.html</link>
  349.         <guid>http://ynomura.dip.jp/archives/2017/05/macportsmaxima.html</guid>
  350.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  351.        
  352.        
  353.         <pubDate>Sun, 21 May 2017 21:22:43 +0900</pubDate>
  354.      </item>
  355.            <item>
  356.         <title>JediにAutoCompleよりCompanyModeを優先させる</title>
  357.         <description><![CDATA[2ヶ月前に<a href="/archives/2017/03/carbon_emacspyt.html">Carbon EmacsのPython環境を整備した</a>ばかりなのだが、MacのOSを10.7.5から10.12.4にバージョンアップすると、Carbon Emacsがまともに動かなくなってしまった。起動はするのだが、すぐに固まってしまう。しかも、その後distnotedというプロセスが全てのCPUを奪い続けて、Macが激重になる。
  358. この現象は<a href="http://irreal.org/blog/?p=2533">OS X 10.9+Emacs 24.3で起こる</a>らしく、Carbon Emacs(Emacs 22)でも起こったという情報は見つけられなかったが、おそらく同じ問題である。どちらかと言うとOSのバグなのだが、現時点ではEmacsを24.4以降にバージョンアップする以外に解決方法が見当たらない。
  359.  
  360. その為、長年お世話になったCarbon Emacsを手放し、Emacsの最新版である25.2を使うことにした。
  361.  
  362. EmacsWikiの<a href="https://www.emacswiki.org/emacs/PythonProgrammingInEmacs">Python Programming In Emacs</a>のページにはPythonの開発環境を便利にする方法が色々書かれているが、筆者は高機能なPythonの開発環境を使いたい時はSpyderを使っており、EmacsのPython環境はPython.elでPython3が使えて、もう少し便利な補完が効けば十分なので、Jediだけを追加インストールすることにした。
  363.  
  364. Emacs 25.2にbuilt-inのPython.elはPython3に対応しているのだが、MacPortsでpython35をインストールして、M-x customize-group -> pythonして"Python Shell Interpreter"をpython3にすると、<a href="https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22897">Warningが出まくり</a>、妙に不安定だった。M-x list-packagesしてpython packageを0.25.2にバージョンアップすると少し改善したが、完全には直らなかった。
  365. さらに、Jediをインストールすると、これまた不安定で、時々補完候補が出る前にEmacsが固まった。(C-gで抜けることはできる)
  366.  
  367. Emacs 24の最新版である24.5.1ではこの問題は起こらなかったので、当面、EmacsでPythonのコードを書く時は24.5.1を使うことにした。
  368.  
  369. Jediのインストールは、
  370. <blockquote><code>(require 'package)
  371. (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
  372. (package-initialize)</code></blockquote>としてpackage.elにMELPAのリポジトリを登録し、M-x list-packagesしてjediをインストールし、<a href="http://tkf.github.io/emacs-jedi/latest/">Jedi.elのドキュメント</a>に従ってセットアップした。
  373.  
  374. なお、Emacs25でjediをインストールすると、Emacs24で"Symbol's function is void: cl-struct-define"というエラーになった。これはjediに限らず、よくあることだそうで、Emacsの24と25を併用する場合、package.elで何かをインストールするならEmacs24でする方が良さそうだ。
  375.  
  376. さて、JediはAutoCompleteとCompanyModeの両方に対応しているが、package.elで"jedi"をインストールするとAutoCompleteが使われる。"company-jedi"をインストールするとCompanyModeが使われるのだが、"jedi"と"company-jedi"の両方をインストールすると、AutoCompleteが優先される。特にAutoCompleteに不満は無く、和製なので贔屓したいが、色々読んでいると、世界的には、日本でも現在は、CompanyModeの方が人気があるようなので、何が良いのかを知るために、これからしばらくはCompanyModeを積極的に使うべく、両方をインストールしてCompanyModeをデフォルトにすることに決めた。
  377.  
  378. しかし、.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 ..."とあるので、<blockquote>(setq auto-complete-mode nil)
  379. (auto-complete-mode)</blockquote>とすれば良さそうに思ったが、これでもOFFにならない。
  380. 但し、(setq auto-complete-mode nil)すると、即座にAutoCompleteがOFFになる。このことを使って、試行錯誤の末、.emacs等に
  381. <blockquote>(add-hook 'python-mode-hook 'jedi:setup)</blockquote>よりも前のどこかに
  382. <blockquote>(add-hook 'python-mode-hook
  383.  (lambda () (setq auto-complete-mode nil)))</blockquote>と書けば、Python mode開始時にAutoCompleteがOFFになり、CompanyModeが使われることがわかった。
  384. ]]></description>
  385.         <link>http://ynomura.dip.jp/archives/2017/05/jediautocomplet.html</link>
  386.         <guid>http://ynomura.dip.jp/archives/2017/05/jediautocomplet.html</guid>
  387.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  388.        
  389.        
  390.         <pubDate>Sat, 06 May 2017 23:32:13 +0900</pubDate>
  391.      </item>
  392.            <item>
  393.         <title>ROC曲線を理解する</title>
  394.         <description><![CDATA[<p>2値の予測(判別、識別、…)に用いる特徴量の良し悪しを評価する1つの方法として、ROC曲線というものがある。<br />
  395. 実際は正で予測も正であるデータの数をTP(True Positive)、<br />
  396. 実際は負で予測も負であるデータの数をTN(True Negative)、<br />
  397. 実際は負で予測は正であるデータの数をFP(False Positive)、<br />
  398. 実際は正で予測は負であるデータの数をFN(False Negative)、<br />
  399. と呼ぶ時、<br />
  400. TPR(True Positive Ratio)=TP/(TP+FN)を縦軸、<br />
  401. FPR(False Positive Ratio)=FP/(FP+TN)を横軸、<br />
  402. としたグラフである。
  403. </p>
  404. <p>ROC曲線の例<br />
  405. <a href="/archives/images/ROC1.png">
  406. <img src="/archives/images/ROC1.png" width="320" height="240" alt="ROC curve sample" />
  407. </a>
  408. </p>
  409.  
  410. <p>ROC曲線は、必ず(0,0)から始まって(1,1)で終わる。<br />
  411. 特徴量が全く予測の役に立たない、ランダムな値であれば、TPR=FPRの線になる。<br />
  412. ROC曲線より下の面積、AUR(Area Under ROC curve)(または単にAUC(Area Under the Curve))が大きいほど、特徴量の値の全域に渡って良い特徴量だとされる。
  413. 理想的な特徴量だと、ROC曲線はFPR=0とTPR=1の線になる。
  414. </p>
  415.  
  416. <p>ROC曲線は機械学習で識別器の評価によく用いられるらしいので、とりあえず覚えておこうと思ったのだが、筆者はこれの理解にえらく苦労したので、調べたことや考えたことをメモする。<br />
  417. <a href="/archives/2009/09/16.html">統計学の検定</a>と同様、こういう確率と論理を組み合わせたものは、人によって向き不向きがあるのだと思いたい。</p>
  418.  
  419. <p>TP,TN,FP,FNの関係を再度整理すると、次のようになる。
  420. <table border="1">
  421. <tr><th rowspan="2" colspan="2"><th colspan="2">予測</tr>
  422. <tr><th bgcolor="maroon">+<th bgcolor="navy">−</tr>
  423. <tr><th rowspan="2">実<br />際<th>+<td align="center" bgcolor="maroon">TP<td align="center" bgcolor="navy">FN (Type II error)</tr>
  424. <tr><th>−<td align="center" bgcolor="maroon">FP (Type I error)<td align="center" bgcolor="navy">TN</tr>
  425. </table>
  426. PやNは予測がPositiveかNegativeかであり、TやFはそれが正解かどうかである。<br />
  427. FPは誤検出のことであり、統計学の検定でも使われる「第一種の過誤」(検定では帰無仮説を棄却できないのに棄却する条件に誤ってヒットしてしまうこと)である。<br />
  428. FNは検出不能であり、「第二種の過誤」(検定では帰無仮説が誤りなのに棄却する条件にヒットしないこと)である。
  429. </p>
  430.  
  431. 予測の精度に関する尺度としては、Accuracy, Presicision, Recall, F値があり、それぞれ次のように定義される。
  432. <dl>
  433. <dt>Accuracy = (TP+TN) / (TP+TN+FP+FN)</dt><dd>予測の正解率。</dd>
  434. <dt>Precision = TP / (TP+FP)</dt><dd>Positiveと予測される中の正解率。</dd>
  435. <dt>Recall = TP / (TP+FN)</dt><dd>実際にPositiveの内、Positiveと予測される割合。検出力、Sensitivity。</dd>
  436. <dt>F値(F-measure, F1 score) = ((Precision<sup>-1</sup> + Recall<sup>-1</sup>)/2)<sup>-1</sup></dt><dd>PrecisionとRecallの調和平均。統計学のF分布に従うF値とは関係ない。<br />
  437. PrecisionとRecallはトレードオフの関係にあるので、それらをバランス良く合成した尺度。</dd>
  438. </dl>
  439.  
  440. <p>予測の精度はAccuracyで評価するのが簡単だが、実際の正のデータ数と負のデータ数に偏りがあると、データ数が少ない方の正解率が低くても、データ数が多い方の正解率が高ければAccuracyが高くなってしまうので、Accuracyだけでは適切に評価できない。<br />
  441. そのような場合にPrecisionやRecallが用いられるが、これらは一般に特徴量の閾値によってトレードオフの関係があり、セットで評価しないといけないので、単純比較には向かない。そこで用いられるスカラー値が、F値や、ROC曲線のAUCである。<br />
  442. Precision-Recall曲線のAUCも使われることがあるが、Presicionは実際の正のデータの割合に依存するので、正のデータの割合が同じでないと比較には使えない。実際の正のデータの割合が極端に小さい場合など、Precisionが大きな意味を持つ場合にはPrecision-Recall曲線が用いられる。
  443. </p>
  444.  
  445. <p>
  446. ROC曲線は、TPR=TP/(TP+FN)とFPR=FP/(FP+TN)のグラフである。TPRを陽性率、FPRを偽陽性率と呼ぶこともある。TPRはRecallと同じである。FPRはfall-out(副産物)と呼ばれることもある。
  447. </p>
  448. <p>
  449. 次の図の3つのROC曲線が、正のデータと負のデータがどのように分布する特徴量に対応するかを考えてみる。<br />
  450. <a href="/archives/images/ROC2.png">
  451. <img src="/archives/images/ROC2.png" width="240" height="240" alt="ROC curve sample 2" />
  452. </a><br />
  453. </p>
  454. <p>
  455. 例えば、次のような分布になる特徴量だと、青いROC曲線になる。<br />
  456. <a href="/archives/images/ROC3.png">
  457. <img src="/archives/images/ROC3.png" width="320" height="240" alt="distribution of totally independent feature" />
  458. </a><br />
  459. 横軸は特徴量、縦軸は赤い部分が正のデータの分布、青い部分が負のデータの分布を表している。このグラフでは、正のデータも負のデータも一様分布している。閾値tより右ならPositive、左ならNegativeと予測する時、tを右端から左に動かすと、TPRもFPRも0から1に向かって増大するが、常にTPR=FPRである。正のデータと負のデータの割合はグラフの形状には関係しない。
  460. </p>
  461. <p>
  462. 次のような、正のデータと負のデータが完全に分かれる理想的な特徴量だと、緑のROC曲線になる。<br />
  463. <a href="/archives/images/ROC4.png">
  464. <img src="/archives/images/ROC4.png" width="320" height="240" alt="distribution of ideal feature" />
  465. </a><br />
  466. tを右端から左に動かすと、FPR=0のままTPRが0から1に変化し、青のゾーンに入ると、FPRが0から1に変化する。
  467. </p>
  468. <p>
  469. 次のような分布だと、赤いROC曲線になる。<br />
  470. <a href="/archives/images/ROC5.png">
  471. <img src="/archives/images/ROC5.png" width="320" height="240" alt="distribution of which makes ROC curve perfect arc" />
  472. </a><br />
  473. tを右端から左へ動かすと、FPRよりもTPRの方が早く上昇する。なるべく正のデータと負のデータの分布が分離している良い特徴量ほどFPRが上昇する前にTPRが上昇するので、AUCが大きくなることがわかる。<br />
  474. </p>
  475.  
  476. <p>AUCはどれくらいだと良いか、という基準は一般的なものも色々あるようだが、大体、最低0.7は無いと有効ではないとされるようである。
  477. </p>
  478. <p>なお、特徴量の最良の閾値(cut-off)はROC曲線の(0,1)に最も近い点とする、という方法を複数の箇所で目にしたが、明確な理論的根拠がある訳ではなく、必ずしもそれに限定されないようである。そもそも、(0,1)に最も近いというのがユークリッド距離で良いのかどうかがわからない。
  479. </p>]]></description>
  480.         <link>http://ynomura.dip.jp/archives/2017/04/roc.html</link>
  481.         <guid>http://ynomura.dip.jp/archives/2017/04/roc.html</guid>
  482.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  483.        
  484.        
  485.         <pubDate>Sun, 09 Apr 2017 20:30:28 +0900</pubDate>
  486.      </item>
  487.            <item>
  488.         <title>pandasでmergeせずにgroupbyで間接参照したい</title>
  489.         <description><![CDATA[<p>この前、pandasを使っていて、次のような感じの、関連する2つのテーブル、access_logとchoice_logがある時に、結合したテーブルを作らずにchoice毎のtimestampの最小値を求めたかったのだが、どう書けば良いのかわからなかった。
  490. </p>
  491. <blockquote><pre>
  492. import pandas as pd
  493. import numpy as np
  494. access_log = pd.DataFrame({'session': [100, 101, 102, 103, 104, 105, 106, 107, 108, 109],
  495.                           'timestamp': [314, 159, 265, 358, 979, 323, 846, 264, 338, 327]})
  496. choice_log = pd.DataFrame({'session': [100, 100, 101, 102, 102, 103, 104, 104, 105, 106, 106, 107, 108, 108, 109],
  497.                           'choice':  ['A', 'B', 'C', 'D', 'E', 'A', 'B', 'C', 'D', 'E', 'A', 'B', 'C', 'D', 'E']})
  498. >>> access_log
  499.   session  timestamp
  500. 0      100        314
  501. 1      101        159
  502. 2      102        265
  503. 3      103        358
  504. 4      104        979
  505. 5      105        323
  506. 6      106        846
  507. 7      107        264
  508. 8      108        338
  509. 9      109        327
  510. >>> choice_log
  511.   choice  session
  512. 0       A      100
  513. 1       B      100
  514. 2       C      101
  515. 3       D      102
  516. 4       E      102
  517. 5       A      103
  518. 6       B      104
  519. 7       C      104
  520. 8       D      105
  521. 9       E      106
  522. 10      A      106
  523. 11      B      107
  524. 12      C      108
  525. 13      D      108
  526. 14      E      109
  527. >>>
  528. </pre></blockquote>
  529. <p>結合テーブルを作るなら、次のように書ける。
  530. </p>
  531. <blockquote><pre>
  532. merged = choice_log.merge(access_log, on='session', how='left')
  533. result = merged.groupby('choice')['timestamp'].min()
  534. >>> result
  535. choice
  536. A    314
  537. B    264
  538. C    159
  539. D    265
  540. E    265
  541. Name: timestamp, dtype: int64
  542. >>>
  543. </pre></blockquote>
  544.  
  545. <p>実際にあったテーブルは巨大で、他にも列がたくさんあり、単純に結合テーブルを作るとRAMが足りなくなってメモリスワップが多発したので、結合テーブルを作らずにこれと同じことがしたかったのだが、その書き方がわからなかった。<br />
  546. 結局access_log.set_index('session').to_dict()のようにして一時的なdictを作って、スワップを多発させながら処理してしまった。<br />
  547. それが心残りだったので、改めてpandasのドキュメントを拾い読みしながら方法を探してみた。
  548. </p>
  549. <ol>
  550. <li>単純に、別のテーブルを参照する関数をSeries.mapに渡す
  551. <blockquote><pre>
  552. def session_to_timestamp(session_series):
  553.    return session_series.map(lambda x: access_log[access_log.session==x]['timestamp'].iat[0])
  554.  
  555. result = choice_log.groupby('choice').agg(lambda x: session_to_timestamp(x).min())
  556. </pre></blockquote>
  557. <p>Seriesの先頭の要素を取り出す方法には、.iat[0]の他に.iloc[0]や.values[0]などがあり、筆者が試した所values[0]の方が速かったりしたが、pandasのドキュメントに書かれているのはilocとiatなので、ここでは添字が整数なら高速なiatを用いた。</p>
  558. </li>
  559. <li>リスト内包表現(list comprehension)で別のテーブルを参照する
  560. <blockquote><pre>
  561. def session_to_timestamp(session_series):
  562.    return [access_log[access_log.session==x]['timestamp'].iat[0] for x in session_series]
  563.  
  564. result = choice_log.groupby('choice').agg(lambda x: min(session_to_timestamp(x)))
  565. </pre></blockquote>
  566. <p>リストにはminメソッドが無いので、session_to_timestamp(x).min()とはできない。</p>
  567. </li>
  568. <li>isinを使ったBoolean Indexingで別の表のサブセットを得る
  569. <blockquote><pre>
  570. def session_to_timestamp(session_series):
  571.    return access_log[access_log.session.isin(session_series.values)]['timestamp']
  572.  
  573. result = choice_log.groupby('choice').agg(lambda x: session_to_timestamp(x).min())
  574. </pre></blockquote>
  575. </li>
  576. <li>別の表からSeriesを作ってSeries.mapに渡す
  577. <blockquote><pre>
  578. def session_to_timestamp(session_series):
  579.    return session_series.map(access_log.set_index('session').timestamp)
  580.  
  581. result = choice_log.groupby('choice').agg(lambda x: session_to_timestamp(x).min())
  582. </pre></blockquote>
  583. <p>一見シンプルで美しそうだが、set_index()はコピーを返すので、timestampの一時的なdictを作るのと変わらない。しかも、グループ数だけ新たなテーブルを作るので、無駄である。</p>
  584. </li>
  585. </ol>
  586.  
  587. <p>これらの処理時間を色々測ってみたが、2つのテーブルのサイズやグループの数によって変わり、どう比較すれば良いかわからなかったので、省略する。<br />
  588. 大まかな傾向としては、1.と2.の処理時間はchoice_logのサイズに依存し、3.と4.の処理時間はsession_logのサイズに依存するようだった。4.はset_indexした中間テーブルを事前に作っておくと高速化するが、それでも、大抵の場合3.が一番速かった。<br />
  589. いずれの方法も最速になる場合があるようなので、場合毎に色々試してみるしかなさそうである。</p>
  590. <p>肝心のメモリ使用量は、適当な測り方がわからなかった。<br />
  591. そもそも、スワップしながらの処理時間が問題だったので、単純にメモリ使用量では測れないと思う。
  592. </p>
  593.  
  594. <p>他にも、以下のような方向で書き方を考えてみたが、うまくできなかった。
  595. </p>
  596. <ul>
  597. <li>groupbyでaggregateでなくtransformしてmin()<br />
  598. transformする時に別のテーブルを参照することを考えたが、transformするとgroup解除されてしまうので、使えなかった。transformする時にmin()するのなら、min()した値を増殖させるだけ無駄なので、確実にaggregateの方が効率が良い。
  599. </li>
  600. <li>pandas.DataFrame.lookupを使う<br />
  601. 引数としてindexしか受けられないので、使えなかった。
  602. </li>
  603. <li>pandas.DataFrame.joinを使う<br />
  604. pandas.DataFrame.mergeを使うのと変わらなかった。
  605. </li>
  606. </ul>
  607.  
  608. <p>そもそも、lambda式を使わずに書く方法は無いのだろうか。<br />
  609. teratailとかStack Overflowとかで聞いた方が早いか。
  610. </p>]]></description>
  611.         <link>http://ynomura.dip.jp/archives/2017/03/pandasmergegrou.html</link>
  612.         <guid>http://ynomura.dip.jp/archives/2017/03/pandasmergegrou.html</guid>
  613.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  614.        
  615.        
  616.         <pubDate>Fri, 31 Mar 2017 20:00:01 +0900</pubDate>
  617.      </item>
  618.            <item>
  619.         <title>pandas.read_csv+numpy.bincountでエラー</title>
  620.         <description><![CDATA[<p>ちょっと前に、はやりのAIのプログラミングでよく使われるPythonとNumPyとPandasを使い始めたのだが、PandasでCSVファイルを読み込んで、各ラベルの出現回数を得る為にNumPyのbincountメソッドを使うと、次のようなエラーが出て、困った。
  621. <blockquote>
  622. TypeError: Cannot cast array data from dtype('int64') to dtype('int32') according to the rule 'safe'
  623. </blockquote>
  624. その時使った環境は、Windows 7(32bit版)+Python 3.5.2(Anaconda 4.1.1 (32-bit))である。Mac OS Xでは出なかった。
  625. </p>
  626. <p>これは、32bitのPythonを使っていると起こることらしい。例えば、32bit Pythonで次のプログラムを実行すると、同じエラーが出る。
  627. <blockquote><pre>
  628. import numpy as np
  629. import pandas as pd
  630. import io
  631.  
  632. data = np.random.randint(10, size=30)
  633. buf = io.StringIO("\n".join(str(x) for x in data))
  634. df = pd.read_csv(buf, header=None)
  635. x = df[0].values
  636. print(x)
  637. print(np.bincount(x)) #Error on 32bit Python
  638. </pre></blockquote>
  639. これは、Pandasが32bit Pythonでもint64を使うのが原因のようである。
  640. </p>
  641.  
  642. <p>このエラーを回避するには、bincountに渡すデータの型をint32にすれば良い。
  643. <blockquote><pre>print(np.bincount(x.astype('int32'))) #also OK on 32bit Python</pre></blockquote>
  644. 出力例
  645. <blockquote>
  646. [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]<br />
  647. [4 3 3 1 0 1 5 6 4 3]
  648. </blockquote>
  649. </p>
  650.  
  651. <p>または、np.unique(return_counts=True)を使う方法があり、こちらの方が、大抵の場合はnp.bincountを使うよりも好ましいとされるようである。
  652. <blockquote><pre>
  653. print(np.unique(x, return_counts=True))
  654. </pre></blockquote>
  655. 出力例
  656. <blockquote>
  657. (array([0, 1, 2, 3, 5, 6, 7, 8, 9]), array([4, 3, 3, 1, 1, 5, 6, 4, 3]))
  658. </blockquote>
  659. 確かに、np.unique(return_counts=True)の方が、データに負の値があっても使えるし、大きな値が混ざってても配列が巨大にならないので、安全そうである。
  660. </p>
  661.  
  662. <p>なお、今動作しているPythonが32bitか64bitかを判定する方法は、いくつかあるようである。
  663. <u>例1</u>
  664. <blockquote><pre>
  665. import platform
  666. platform.architecture()
  667. </pre></blockquote>
  668.  
  669. 出力(上がMacOSX、下がWin32)
  670. <blockquote>
  671. ('64bit', '')<br />
  672. ('32bit', 'WindowsPE')
  673. </blockquote>
  674.  
  675. <u>例2</u>
  676. <blockquote><pre>
  677. import sys
  678. "%x" % sys.maxsize
  679. </pre></blockquote>
  680. 出力(上がMacOSX、下がWin32)
  681. <blockquote>
  682. '7fffffffffffffff'<br />
  683. '7fffffff'
  684. </blockquote>
  685.  
  686. <u>例3</u>(platform.architecture()の実装にも使われている方法)
  687. <blockquote><pre>
  688. import struct
  689. struct.calcsize("P") * 8
  690. </pre></blockquote>
  691. 出力(上がMacOSX、下がWin32)
  692. <blockquote>
  693. 64<br />
  694. 32
  695. </blockquote>
  696. </p>
  697. ]]></description>
  698.         <link>http://ynomura.dip.jp/archives/2017/03/pandasread_csvn.html</link>
  699.         <guid>http://ynomura.dip.jp/archives/2017/03/pandasread_csvn.html</guid>
  700.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  701.        
  702.        
  703.         <pubDate>Sun, 05 Mar 2017 20:47:33 +0900</pubDate>
  704.      </item>
  705.            <item>
  706.         <title>Carbon EmacsにPython 3環境導入</title>
  707.         <description><![CDATA[<p>筆者はMacで未だにEmacs 22ベースのCarbon Emacsを多用している。Emacs 24ベースのCocoa Emacsもインストールはしているのだが、色々な環境をCarbon Emacsに作ってしまっているので、移行するのが億劫なのである。</p>
  708.  
  709. <p>最近、Python 3を使い始めたのだが、Carbon Emacsのpython.elはPython 2にしか対応していないので、何とかPython 3に対応させる方法は無いかと探した結果、<br />
  710. <a href="http://www.loveshack.ukfsn.org/emacs/">http://www.loveshack.ukfsn.org/emacs/</a><br />
  711. から<br />
  712. python.el<br />
  713. emacs.py<br />
  714. sym-comp.el<br />
  715. の3つをダウンロードして、Emacs.app/内に置けば良いことがわかった。(python.elとemacs.pyは既にあるものを置換、sym-comp.elはpython.elと同じディレクトリに追加)<br />
  716. そして、Emacsを立ち上げて、M-x customize-groupとし、<br />
  717. "Python Default Version" = 3<br />
  718. "Python Python Command" = python3<br />
  719. にすれば完成である。</p>
  720.  
  721. <p>これで、C-c TABとM-TABを駆使すればシンボルの補完ができて、まあまあコーディングが楽になるのだが、やっぱり補完機能は便利にしたいので、<br />
  722. <a href="http://cortyuming.hateblo.jp/entry/20111224/p1">Pythonの補完をEmacsでシンプルに最小労力で手早く使えるようにする - 牌語備忘録 -pygo</a><br />
  723. を参考にして、<a href="https://www.emacswiki.org/emacs/AutoComplete">auto-complete.el</a> + <a href="http://chrispoole.com/downloads/ac-python.el">ac-python.el</a>をインストールした。<br />
  724. auto-complete.elは、Emacs 22で動作実績のある、auto-complete-1.3.1.tar.bz2をどこかから入手した。</p>
  725.  
  726. <p>そして、.emacsに次の4行を書けば完成である。
  727. <blockquote><pre>(require 'auto-complete)
  728. (require 'auto-complete-config)
  729. (ac-config-default)
  730. (require 'ac-python)</pre></blockquote></p>
  731.  
  732. <p>これで、python-modeにして、<code>import math</code>と書いてC-c TABして、<code>math.</code>と打つと、math.sqrtやらmath.piやらが補完候補として自動的に現れるようになった。</p>]]></description>
  733.         <link>http://ynomura.dip.jp/archives/2017/03/carbon_emacspyt.html</link>
  734.         <guid>http://ynomura.dip.jp/archives/2017/03/carbon_emacspyt.html</guid>
  735.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  736.        
  737.        
  738.         <pubDate>Wed, 01 Mar 2017 23:37:59 +0900</pubDate>
  739.      </item>
  740.            <item>
  741.         <title>対石田流の定跡で悩む</title>
  742.         <description><![CDATA[筆者は石田流が苦手である。後手になって、初手から▲7六歩△3四歩▲7五歩とされると、これは大変なことになったな、と思ってしまう。同じぐらいの実力(アマ三段程度)同士だと、石田流にされると3局に2局は負けてると思う。
  743. 先週は将棋大会があり、石田流対策としては、▲7六歩△3四歩▲7五歩には△4二玉、下図の局面から仕掛けるなら△9二飛▲8五桂△8二飛▲8六歩△8四飛、の2つだけを覚えて臨んだら、予選の1局目から▲7六歩△3四歩▲7五歩とされ、次の図の局面を迎えてしまった。
  744. <img src="/archives/images/20161123-1.png">
  745. このような局面から△9二飛▲8五桂△8二飛▲8六歩△8四飛と飛車を端に振ってすぐ戻して浮くのは、過去に何かの本で読んだもので、多分定跡だと思う。もし△9二飛▲8五桂△8二飛の次に▲8六飛とされたらどうすればいいんだろう、と不安に思っていたが、他に何も思い付かなかったので、定跡と信じて△9二飛、▲8五桂、△8二飛と手早く指した。
  746. <img src="/archives/images/20161123-2.png">
  747. すると、ノータイムで実際に▲8六飛とされてしまい、長考に沈んでしまった。
  748. 後で調べると、ここまでは2004年のNHK杯の三浦−行方戦と全く同じ進行であり、その対局ではやはり▲8六歩と指されていた。他にも部分的に同じ形から△9二飛▲8五桂△8二飛としたプロの棋譜を4つぐらい見つけたが、次の手は全て▲8六歩△8四飛だったし、激指14で分析しても▲8六飛は評価が低いので、良くない手なのだと思うが、これの咎め方がよくわからない。
  749. <img src="/archives/images/20161123-3.png">
  750. 次に何をやっても▲7三桂成がある。それには△8六飛(次図)とする一手だが、▲同角でも△7三桂の後に先攻されてすぐ桂損を回復されるし、▲6三成桂と踏み込まれる手も気になる。
  751. <img src="/archives/images/20161123-4.png">
  752. 筆者の実戦は、▲8六飛の後、△7四歩▲7三桂成△8六飛▲同角△7三桂▲7四歩△同銀▲7一飛(次図)と先着され、△6二金と受けたら▲9一飛成から大暴れされ、なす術無く、十数手後には激指の先手の評価値が+1000という必敗の形勢になってしまった。
  753. <img src="/archives/images/20161123-5.png">
  754. 激指によると、△6二金が悪手で、ここまで来たら桂取りが銀取りにならないように△6三銀と戻るのが良いらしいが、そこまで後手を引いて駒損を回復されて龍まで作られてしまうのでは、何をやってるのかわからないと思う。
  755. ただ、△7四歩では△6五歩の方が良さそうである。▲7三桂成と歩を取られるのなら逃げておこうと思って△7四歩と避けたのだが、△7三桂と取り返した後に▲7四歩と取る手が桂取りの先手になるし、△7四歩が無くても△7三桂には▲7四歩と突き出す所なので、意味が無かった。▲8六飛の後、△6五歩▲7三桂成△8六飛▲同角△7三桂▲7四歩△同銀▲7一飛△5五角というのが激指の推奨手順である。
  756. <img src="/archives/images/20161123-6.png">
  757. 激指はこれで-400(後手少しリード)くらいの評価を示しているが、筆者にはこれで後手が指せる理由がわからない。次に△3六桂とやっても▲3九玉と引かれるので攻め方がわからないし、やはり▲9一飛成から暴れられて、筆者の実力ではその勢いを止められないように思う。
  758. ただ、もし△5五角に▲5六歩とされれば、△3六桂で一気に後手勝勢になりそうである。△3六桂に▲3九玉だと△6六角が王手で危険なので▲1七玉しか無いが、△1五歩とすれば受けが難しいと思う。
  759. <img src="/archives/images/20161123-7.png">
  760. ▲5五歩なら△1六歩▲2六玉△2八桂成である。
  761. こうなることを期待して、▲8六飛には△6五歩とするべきなのだろうか。]]></description>
  762.         <link>http://ynomura.dip.jp/archives/2016/11/post_58.html</link>
  763.         <guid>http://ynomura.dip.jp/archives/2016/11/post_58.html</guid>
  764.                  <category domain="http://www.sixapart.com/ns/types#category">将棋</category>
  765.        
  766.        
  767.         <pubDate>Sun, 27 Nov 2016 20:28:50 +0900</pubDate>
  768.      </item>
  769.            <item>
  770.         <title>980</title>
  771.         <description><![CDATA[惜しい。
  772. <a href="/archives/images/TOEICIPresult20161023.jpg"><img src="/archives/images/TOEICIPresult20161023.jpg" width="408" height="172"></a>]]></description>
  773.         <link>http://ynomura.dip.jp/archives/2016/11/980.html</link>
  774.         <guid>http://ynomura.dip.jp/archives/2016/11/980.html</guid>
  775.                  <category domain="http://www.sixapart.com/ns/types#category">雑記</category>
  776.        
  777.        
  778.         <pubDate>Tue, 08 Nov 2016 23:55:53 +0900</pubDate>
  779.      </item>
  780.            <item>
  781.         <title>psvn.el+Subversion 1.7がネストされたワーキングコピーでエラーになる件</title>
  782.         <description><![CDATA[<p>筆者は<a href="http://www.xsteve.at/prg/emacs/psvn.el">psvn.el</a>を6年くらい愛用している。仕事でSubversionを使ってるのだが、Subversionのクライアントソフトとして、周囲がTortoiseSVNを使う中、一人で頑にpsvn.elを使っている。マウス操作やトラックパッド操作が必要なく、全てがキーボード操作で完結するのが、個人的に気持ち良いのである。
  783. </p>
  784. <p>最近、仕事で使うSubversionのバージョンが1.6から1.8に変わり、それまで使っていた、2009年のバージョンのpsvn.elが動かなくなった。Subversion 1.7でワーキングコピーの形式が大幅に変わったからである。
  785. </p>
  786. <p>そこで、Subversion 1.7にも対応している、最新のpsvn.el(2015-07-20版)をダウンロードして使い始めた所、ワーキングコピーのルートディレクトリにチェックアウトしたワーキングコピーでM-x svn-statusすると、<blockquote>Wrong type argument: stringp, nil</blockquote>というエラーが出て使えなかった。つまり、<pre>
  787. svn co (URL1) aaa
  788. cd aaa
  789. svn co (URL2) bbb
  790. </pre>
  791. とした時のディレクトリbbbの下でM-x svn-statusができなかった。<br />
  792. svn coの代わりに、svn propsetでsvn:externalsを指定してbbbを取得しても同じエラーになった。<br />
  793. ディレクトリaaaの下でsvn switchして別のワーキングコピーを取得した場合は同じ問題が起こらないのだが、あいにくURL1とURL2とでSubversionのリポジトリが異なる為に、svn switchでbbbを取得することができないのである。
  794. </p>
  795. <p>これが筆者としては非常に困ったので、自力で修正してみた。<br />
  796. 変更箇所をdiff形式で示す。</p>
  797. <p>修正案1
  798. <blockquote><pre>
  799. <span class="diffold">--- psvn.el.org 2015-07-20, 21:42:00</span>
  800. <span class="diffnew">+++ psvn.el 2016-09-30</span>
  801. <span class="grayout">@@ -6063,6 +6063,7 @@
  802.         ;; it doesn't, e.g we reached / already.
  803.         (setq parent (expand-file-name (concat wc-root "..")))
  804.         (or (and (< (length parent) (length wc-root))
  805. <span class="diffnew">+                 (not (file-exists-p (concat wc-root (svn-wc-adm-dir-name))))  ;; stop if .svn or equivalent exists</span>
  806.                  (svn-status-base-dir-1 (expand-file-name (concat wc-root ".."))))
  807.             wc-root)))))</span>
  808. </pre></blockquote>
  809.  
  810. svn-status-base-dir-1関数の中で、ワーキングコピーのルートディレクトリを探すのに、できるだけ上位のディレクトリを探すようで、上に辿る途中にエラーになるので、.svnを発見したらそれ以上遡らないようにするものである。</p>
  811.  
  812. <p>修正案2
  813. <blockquote><pre>
  814. <span class="diffold">--- psvn.el.org 2015-07-20, 21:42:00</span>
  815. <span class="diffnew">+++ psvn.el 2016-10-10</span>
  816. <span class="grayout">@@ -3084,7 +3084,7 @@
  817.     (let ((svn-process-buffer-name "*svn-info-output*"))
  818.       (when (get-buffer svn-process-buffer-name)
  819.         (kill-buffer svn-process-buffer-name))
  820. <span class="diffold">-      (svn-run nil t 'parse-info "info" ".")</span>
  821. <span class="diffnew">+      (svn-run nil t 'parse-info "info" default-directory)</span>
  822.       (svn-status-parse-info-result)))
  823.   (unless (eq arg t)
  824.     (svn-status-update-buffer)))</span>
  825. </pre></blockquote>
  826.  
  827. 原因がよくわからないが、途中にワーキングコピーのルートディレクトリがあると、そこから1つ上に遡った時に、カレントディレクトリがdefault-directoryでなく、もう1つ上のディレクトリにずれてしまうようで、カレントディレクトリがワーキングコピー中でないと <code>svn info .</code> がエラーになる(*)ので、 <code>svn info</code> する時に常にdefault-directoryを使うように変えるものである。
  828. </p>
  829.  
  830. <p>どちらも適切な修正かどうかはわからないが、とりあえず筆者の環境(Linux + Subversion 1.8 + Emacs 2.4)では標記の問題は解決した。
  831. </p>]]></description>
  832.         <link>http://ynomura.dip.jp/archives/2016/10/psvnelsubversio.html</link>
  833.         <guid>http://ynomura.dip.jp/archives/2016/10/psvnelsubversio.html</guid>
  834.                  <category domain="http://www.sixapart.com/ns/types#category">UNIX</category>
  835.        
  836.        
  837.         <pubDate>Mon, 10 Oct 2016 14:11:57 +0900</pubDate>
  838.      </item>
  839.            <item>
  840.         <title>被写界深度の計算式を導いてみた</title>
  841.         <description><![CDATA[被写界深度というのは、レンズを通して見た映像の、ピントが合っているように見える、奥行き方向の範囲のことである。
  842. 昨年、フォトマスター検定という試験を受ける為に勉強した中で、被写界深度を求める式が何故このようになるのかがわからず、気になっていた。
  843. 先月、フォトマスター検定について講義する機会があったので、そのネタとして、被写界深度の式を導いてみた。
  844.  
  845. <img src="/archives/images/DoF1.svg" border="1" width="651" height="250">
  846. 図1
  847.  
  848. まず、被写界深度が何故存在するかというと、ピントが合っていない距離の点は点でなく丸になって映る(ボケる)が、その丸(錯乱円)が十分に小さいと、ほとんどボケてるように見えないからである。
  849. その十分に小さい錯乱円の直径=許容ボケをδとすると、フィルム(デジカメだとセンサー)上のδに対応して、光軸上のフィルム/センサーの前後に、その範囲に焦点を結ぶとピントが合って見える範囲=焦点深度が存在する。
  850. <img src="/archives/images/DoF2.svg" border="1" width="333" height="237">
  851. 図2
  852.  
  853. この焦点深度の幅を2εとすると、F値(絞り値)=レンズ焦点距離(f)÷レンズ口径(Φ)を使って、f >> εなのでε/δ = F、すなわちε = Fδと近似できる。
  854. この焦点深度に対応する、被写体側の範囲が、被写界深度である。
  855.  
  856. ここで、「ガウスの結像公式」(以下、単に「結像公式」)というのを用いる。結像公式とは、凸レンズからa離れた位置から発せられる光が、凸レンズを通って反対側のb離れた位置に焦点を結ぶ時、aとbの関係を、レンズ焦点距離fを用いて、
  857. <img src="/archives/images/DoF01.png" alt="\frac{1}{f}=\frac{1}{a}+\frac{1}{b}, Gaussian form of the lens equation">
  858. と表すものである。ちなみに、レンズの焦点距離とは、無限遠から来る光が焦点を結ぶ位置のことである。(上式でa=∞とするとb=fとなる)
  859.  
  860. この結像公式を用いて、焦点深度と被写界深度の関係を式にする。
  861. 図1のように、sをレンズから合焦位置までの距離、s<sub>n</sub>を被写界の近点、s<sub>f</sub>を被写界の遠点、tをレンズからフィルム/センサーまでの距離とすると、
  862. <img src="/archives/images/DoF02.png">
  863. となる。これらの連立方程式を、tを消去して、s<sub>n</sub>とs<sub>f</sub>について解く。
  864. (1)よりt=sf/(s-f)が得られるので、これを(2),(3)に代入すると、
  865. <img src="/archives/images/DoF03.png" alt="s_n=\frac{(t+\epsilon)f}{(t+\epsilon)-f}=\frac{(\frac{sf}{s-f}+\epsilon)f}{(\frac{sf}{s-f}+\epsilon)-f}=\frac{(sf+\epsilon(s-f))f}{f^2+\epsilon(s-f)}">
  866. <img src="/archives/images/DoF04.png" alt="s_f=\frac{(t-\epsilon)f}{(t-\epsilon)-f}=\frac{(\frac{sf}{s-f}-\epsilon)f}{(\frac{sf}{s-f}-\epsilon)-f}=\frac{(sf-\epsilon(s-f))f}{f^2-\epsilon(s-f)}">
  867. が得られる。
  868. ここで、s,f>>εなので、s&plusmn;ε&asymp;s, f&plusmn;ε&asymp;f, sf&plusmn;ε<sup>2</sup>&asymp;sfと近似できることを用いて、簡略化する。
  869. <img src="/archives/images/DoF05.png" alt="s_n=\frac{(sf+\epsilon(s-f))f}{f^2+\epsilon(s-f)}=\frac{((s-\epsilon)(f+\epsilon)+\epsilon^2))f}{f(f-\epsilon)+\epsilon s}\approx\frac{sf^2}{f^2+\epsilon s}">
  870. <img src="/archives/images/DoF06.png" alt="s_f=\frac{(sf-\epsilon(s-f))f}{f^2-\epsilon(s-f)}=\frac{((s+\epsilon)(f-\epsilon)+\epsilon^2))f}{f(f+\epsilon)-\epsilon s}\approx\frac{sf^2}{f^2-\epsilon s}">
  871.  
  872. これにε=Fδを代入すれば、被写界深度の近点と遠点を求める式になるのだが、フォトマスター検定の参考書では過焦点距離を用いた式になっているので、もう少し変形を進める。
  873. 過焦点距離とは、被写界深度の遠点が無限遠に届く、最短の撮影距離である。焦点深度と結像公式を用いて被写界深度の近点、遠点と同じ要領で、過焦点距離Hについても式を立てると、
  874. <img src="/archives/images/DoF07.png">
  875. となる。下の式からt=f+εが得られ、それを用いて上の式をHについて解くと、
  876. <img src="/archives/images/DoF08.png" alt="H=\frac{tf}{t-f}=\frac{(f+\epsilon)f}{\epsilon}\approx\frac{f^2}{\epsilon}=\frac{f^2}{F\delta}">
  877. すなわち<strong>過焦点距離=レンズ焦点距離<sup>2</sup>÷(絞り値×許容ボケ)</strong>と求まる。これを用いてs<sub>n</sub>, s<sub>f</sub>をさらに整理する。
  878. <img src="/archives/images/DoF09.png" alt="s_n\approx\frac{sf^2}{f^2+\epsilon s}=\frac{sf^2}{f^2+\frac{f^2}{H}s}=\frac{Hs}{H+s}">
  879. <img src="/archives/images/DoF10.png" alt="s_f\approx\frac{sf^2}{f^2-\epsilon s}=\frac{sf^2}{f^2-\frac{f^2}{H}s}=\frac{Hs}{H-s}">
  880.  
  881. 従って、
  882. 被写界近点=(過焦点距離×合焦距離)÷(過焦点距離+合焦距離)
  883. 被写界遠点=(過焦点距離×合焦距離)÷(過焦点距離−合焦距離)
  884. である。
  885.  
  886. なお、過焦点距離の計算には許容ボケが必要になるが、許容ボケは通常、フィルムやセンサーの対角線長÷1300、が用いられる。
  887. 35mmフィルムなら、√(36<sup>2</sup>+24<sup>2</sup>)/1300≒0.03328 (≒1/30) mm、
  888. フォーサーズ/マイクロフォーサーズなら√(17.3<sup>2</sup>+13<sup>2</sup>)/1300≒0.01665 (≒1/60) mm、である。
  889. ]]></description>
  890.         <link>http://ynomura.dip.jp/archives/2016/07/post_57.html</link>
  891.         <guid>http://ynomura.dip.jp/archives/2016/07/post_57.html</guid>
  892.                  <category domain="http://www.sixapart.com/ns/types#category">雑記</category>
  893.        
  894.        
  895.         <pubDate>Tue, 05 Jul 2016 19:57:23 +0900</pubDate>
  896.      </item>
  897.            <item>
  898.         <title>角換わり棒銀の定跡形で悩む</title>
  899.         <description><![CDATA[昨日は毎年参加している将棋大会だった。
  900. 昨年は<a href="/archives/2015/06/4_1.html">ベスト4まで行った</a>のだが、今年は1回戦敗退だった。
  901. 筆者はこの所公私共に多忙で、ほとんど将棋を指していなかったので、予選突破できただけで上出来である。予選敗退した場合の抽選の指導対局に備えて駒落ちの定跡本を携えていたが、出番が無かった。
  902.  
  903. 今年は、予選の2局と決勝の1局全て、筆者が苦手とする角換わりを仕掛けられ、全て棒銀で応対した。予選の2局はデタラメな攻めが都合良く炸裂して、一昨年に優勝し昨年準優勝した強敵(一昨年に1回戦で負けた相手)にも勝って大満足だったのだが、決勝の1回戦は、昨年予選で勝った相手に課題の多い負け方をしてしまった。
  904.  
  905. <img src="/archives/images/20160604-1.png" alt="" /> 図1
  906.  
  907. 図1は角換わり棒銀の定跡である。筆者は角換わりには棒銀と決めているので、この局面には何度か遭遇している。1回戦は先手を持ってこの局面になったのだが、ここから後手は△1九角、▲2七飛、△1七歩成、▲同歩、△1八銀と指してきた(図2)。よくある手らしいが、筆者は初めて見た。
  908.  
  909. <img src="/archives/images/20160604-2.png" alt="" /> 図2
  910.  
  911. これに普通に▲2六飛と応対し、△2四歩に部分的な定跡通りに▲1二角と打った(図3)。
  912.  
  913. <img src="/archives/images/20160604-3.png" alt="" /> 図3
  914.  
  915. ▲1二角と打つ時、もし△3三桂とされたらどうすれば良いんだろう、と不安に思いながら指したのだが、実際に△3三桂とされ、焦った。その後、自信無く、▲2四飛△2二歩▲1三香成と進めた。
  916.  
  917. △1九角〜△1八銀が入っていない、図1の形では、△2四同歩に▲1二角△2二金▲3四角成△3三金▲2四馬が定跡である。これだけは覚えていた。
  918. 激指14で解析すると、やはり図1からは定跡通り△2四同歩▲1二角△2二金〜▲2四馬が最善であり、▲1二角△3三桂には▲2四飛△2二歩▲2一角成として▲8三香を狙うのが良いらしい。しかし、本局の図3からはそうでなく、
  919. ・▲1二角△3三桂▲2四飛△2二歩には▲6八玉が最善(次善は▲4八金と本譜の▲1三香成)
  920. ・▲1二角△3三桂▲2四飛に△2二歩でなく△2三歩が最善
  921. ・▲1二角では▲2四飛が最善(△2三歩なら▲1四飛で飛車成りが防げない)
  922. だったようだ。前の2つは難しいが、最後のは少し考えたらわかることである。次の△3三桂ばかり気にして、▲1二角以外の手を読まなかったのが失敗だった。
  923.  
  924. それでも、▲1三香成までにそれほどひどい手はない。▲1三香成の後、△2九銀成▲同飛△3七角成▲4八金△1五馬(図4)と進んだが、ここで絶好の機会を逃した。
  925.  
  926. <img src="/archives/images/20160604-4.png" alt="" /> 図4
  927.  
  928. 香を打ったら馬が死ぬと勘違いして▲1六香と打ったら、△2五馬と寄られて空振りした。
  929. ここでは▲1六銀で馬が死んでいたし、▲2四銀でも△2五馬なら▲3三銀が馬取りでひどいので馬を切る一手だっただろう。
  930.  
  931. 実戦はこの後、お互いに怪しい手が多かったので省略するが、飛車をいじめられ、大悪手を指して挽回不能になってしまった。その攻める手は大悪手とわかっていながら、他に粘る手を全く思い付かなかったのである。激指で解析すると、色々粘る手はあったようだが、どれも筆者には理解できなかった。直接の敗因は▲6八玉を怠って飛車をいじめられたことだが、図4のチャンスを逃したのが運命の分かれ道だったと思う。
  932. △2九銀成〜△3七角成とされる前にどこかで▲4八金と防ぐべきだったかも知れないが、△4五桂の当たりが強くなるので、やるなら△3三桂の前だと思うが、△3三桂の前には別に有効な手があったので、適当なタイミングが無かったと思う。
  933.  
  934. それより、図2から▲2六飛△3五銀とされた場合にどうすれば良いのかがわからない。感想戦では後手が自信無かったと言っていたが、激指14では△3五銀が最善であり、▲5六飛に△2九銀不成でも△4二金▲2三歩成でも後手やや良しと計算される。図1から▲5六飛まで先手に変化の余地はなく、もしそうなら図1は既に先手がまずいことになる。プロの棋戦には見つからなかったが、プロが図2の△1八銀を見落とすはずがない。プロも激指14も最善としない△1八銀に対策が見つからないとはどういうことなのだろう。
  935. 激指14の最善手は、▲2六飛△3五銀▲5六飛△2九銀不成▲4八金△5四桂▲7五歩という難解な手順である。△2九銀不成に▲5三飛成は次善手で、その後△5二金▲5六龍△3七角成▲6八玉△4四桂▲6六龍△1五馬で後手やや良しだそうだが、アマチュアとしては駒損でも龍ができて気持ちが楽になるので、これを選択すべきか。]]></description>
  936.         <link>http://ynomura.dip.jp/archives/2016/06/post_56.html</link>
  937.         <guid>http://ynomura.dip.jp/archives/2016/06/post_56.html</guid>
  938.                  <category domain="http://www.sixapart.com/ns/types#category">将棋</category>
  939.        
  940.        
  941.         <pubDate>Sun, 05 Jun 2016 23:27:27 +0900</pubDate>
  942.      </item>
  943.            <item>
  944.         <title>CppUTestでテスト駆動開発(1)</title>
  945.         <description><![CDATA[<p>図書館で、「テスト駆動開発による組み込みプログラミング」という本に目を引かれ、流し読みしたら結構面白かったので、借りて帰ったのだが、筆者はこの所公私共に多忙で、ほとんど読めないまま返却期限を迎えてしまった。<br />
  946. とりあえず、その本で推薦されていた、<a href="http://cpputest.github.io">CppUTest</a>というユニットテストフレームワークを使ってみた。
  947. </p>
  948. <p>筆者は、凄まじく高コストで生産性の低い日本企業のソフトウェア開発を数年間目の当たりにした後、21世紀に入った頃にテストファーストを含むExtreme Programmingの考え方に全面的に共感し、その時にCUnitというユニットテストフレームワークを使ったことがあるのだが、その価値がわからなかった。わざわざそんなのを使わなくても、ユニットテストを駆動する短いテストドライバを自分で書けば事足りると思ったし、実際、これまでそのようにしてきて困ったことが無い。
  949. </p>
  950. <p>しかし、今回、この本でUnityやCppUTestの話を読むと、ユニットテストフレームワークには最先端の考え方が反映されており、この枠に嵌められてユニットテストを書いたりTDDをすれば、手軽に世界のトップクラスのインテリジェンスに触れられるような気がして、面白そうだと思った。
  951. </p>
  952. <p>そこで、CppUTestを使ってみることにした。
  953. </p>
  954. <p>書籍の第3章のLEDドライバの例を題材に、TDD(テスト駆動開発)方式で、まずは未実装のエラーが出る実行可能なテストを作ってみる。
  955. </p>
  956. LedDriver/LedDriverTest.cpp
  957. <blockquote><code><pre>
  958. #include "CppUTest/TestHarness.h"
  959.  
  960. TEST_GROUP(LedDriver)
  961. {
  962.  void setup()
  963.  {
  964.  }
  965.  void teardown()
  966.  {
  967.  }
  968. };
  969.  
  970. TEST(LedDriver, LedsOffAfterCreate)
  971. {
  972.  FAIL("Start here");
  973. }
  974. </pre></code></blockquote>
  975.  
  976. test_main.cpp
  977. <blockquote><code><pre>
  978. //from README.md
  979. #include &lt;CppUTest/CommandLineTestRunner.h&gt;
  980.  
  981. int main(int ac, char** av)
  982. {
  983.   return CommandLineTestRunner::RunAllTests(ac, av);
  984. }
  985. </pre></code></blockquote>
  986.  
  987. Makefile
  988. <blockquote><code><pre>
  989. CXX = g++
  990. CPPUTEST_HOME := $(HOME)/tmp/cpputest
  991.  
  992. #from README.md
  993. CPPFLAGS += -I$(CPPUTEST_HOME)/include
  994. CXXFLAGS += -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorNewMacros.h
  995. CFLAGS += -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorMallocMacros.h
  996. LD_LIBRARIES = -L$(CPPUTEST_HOME)/lib -lCppUTest -lCppUTestExt
  997.  
  998. TARGET = test_main
  999. SRCS = test_main.cpp LedDriver/LedDriverTest.cpp
  1000. OBJS = $(SRCS:.cpp=.o)
  1001.  
  1002. all: $(TARGET)
  1003.  
  1004. $(TARGET): $(OBJS)
  1005. $(CXX) -o $@ $^ $(CXXFLAGS) $(LD_LIBRARIES)
  1006.  
  1007. %.o: %.cpp
  1008. # GNU make implicit rule + "-o $@"
  1009. $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
  1010.  
  1011. .PHONY: check
  1012. check: $(TARGET)
  1013. ./$(TARGET) -v
  1014.  
  1015. .PHONY: clean
  1016. clean:
  1017. rm -f $(TARGET) $(OBJS) *.gcno *.gcov *~ */*~
  1018. find . -name "*.gcda" | xargs rm -f
  1019. </pre></code></blockquote>
  1020.  
  1021. <p>これでmake checkとすると、1つのテストが失敗し、"Start here"と表示される。<br />
  1022. 筆者は普段、テストの実行はmake testであるが、make checkが多数派らしいので、今後はそれに倣うことにした。(make testはPerlの世界に多い?)
  1023. </p>
  1024. <p>MakefileにLedDriver.cのコンパイルが無いのは、TDDの、エラーにならない限りは作らない原則に従っているからである。
  1025. </p>
  1026. <p>次に、LedDriver/LedDriverTest.cppにテストを追加し、それがpassするようにLedDriver.cを開発するのを繰り返す。<br />
  1027. 途中と詳細説明を省略するが、例えば途中段階では次のようになった。
  1028. </p>
  1029. LedDriver/LedDriverTest.cpp
  1030. <blockquote><code><pre>
  1031. #include "CppUTest/TestHarness.h"
  1032. extern "C" {
  1033. #include "LedDriver.h"
  1034. }
  1035.  
  1036. static uint16_t virtualLeds;
  1037.  
  1038. TEST_GROUP(LedDriver)
  1039. {
  1040.  void setup()
  1041.  {
  1042.    LedDriver_Create(&virtualLeds);
  1043.  }
  1044.  void teardown()
  1045.  {
  1046.  }
  1047. };
  1048.  
  1049. TEST(LedDriver, LedsOffAfterCreate)
  1050. {
  1051. uint16_t virtualLeds = 0xffff;
  1052. LedDriver_Create(&virtualLeds);
  1053. LONGS_EQUAL(0, virtualLeds);
  1054. }
  1055.  
  1056. TEST(LedDriver, TurnOnLedOne)
  1057. {
  1058. LedDriver_TurnOn(1);
  1059. LONGS_EQUAL(1, virtualLeds);
  1060. }
  1061.  
  1062. TEST(LedDriver, TurnOffLedOne)
  1063. {
  1064. LedDriver_TurnOn(1);
  1065. LedDriver_TurnOff(1);
  1066. LONGS_EQUAL(0, virtualLeds);
  1067. }
  1068.  
  1069. TEST(LedDriver, TurnOnMultipleLeds)
  1070. {
  1071. LedDriver_TurnOn(9);
  1072. LedDriver_TurnOn(8);
  1073. LONGS_EQUAL(0x0180, virtualLeds);
  1074. }
  1075.  
  1076. TEST(LedDriver, AllOn)
  1077. {
  1078. LedDriver_TurnAllOn();
  1079. LONGS_EQUAL(0xffff, virtualLeds);
  1080. }
  1081. TEST(LedDriver, TurnOffAnyLed)
  1082. {
  1083. LedDriver_TurnAllOn();
  1084. LedDriver_TurnOff(8);
  1085. LONGS_EQUAL(0xff7f, virtualLeds);
  1086. }
  1087.  
  1088. IGNORE_TEST(LedDriver, LedMemoryIsNotReadable)
  1089. {
  1090. // TODO: let LED state read-only
  1091. }
  1092. </pre></code></blockquote>
  1093.  
  1094. LedDriver/LedDriver.h
  1095. <blockquote><code><pre>
  1096. #pragma once
  1097. #include &lt;stdint.h&gt;
  1098.  
  1099. extern void LedDriver_Create(uint16_t *address);
  1100. extern void LedDriver_Destroy(void);
  1101. extern void LedDriver_TurnOn(int ledNumber);
  1102. extern void LedDriver_TurnOff(int ledNumber);
  1103. extern void LedDriver_TurnAllOn(void);
  1104. </pre></code></blockquote>
  1105.  
  1106. LedDriver/LedDriver.c
  1107. <blockquote><code><pre>
  1108. #include "LedDriver.h"
  1109.  
  1110. enum {ALL_LEDS_ON = ~0, ALL_LEDS_OFF = ~ALL_LEDS_ON};
  1111.  
  1112. static uint16_t *ledsAddress;
  1113.  
  1114. static uint16_t convertLedNumberToBit(int ledNumber)
  1115. {
  1116. return 1 << (ledNumber - 1);
  1117. }
  1118.  
  1119. void LedDriver_Create(uint16_t *address)
  1120. {
  1121. ledsAddress = address;
  1122. *ledsAddress = ALL_LEDS_OFF;
  1123. }
  1124.  
  1125. void LedDriver_Destroy(void)
  1126. {
  1127. }
  1128.  
  1129. void LedDriver_TurnOn(int ledNumber)
  1130. {
  1131. *ledsAddress |= convertLedNumberToBit(ledNumber);
  1132. }
  1133.  
  1134. void LedDriver_TurnOff(int ledNumber)
  1135. {
  1136. *ledsAddress &= ~convertLedNumberToBit(ledNumber);
  1137. }
  1138.  
  1139. void LedDriver_TurnAllOn(void)
  1140. {
  1141. *ledsAddress = ALL_LEDS_ON;
  1142. }
  1143. </pre></code></blockquote>
  1144.  
  1145. Makefile
  1146. <blockquote><code><pre>
  1147. CXX = g++
  1148. CC = gcc
  1149. CPPUTEST_HOME := $(HOME)/tmp/cpputest
  1150.  
  1151. #from README.md
  1152. CPPFLAGS += -I$(CPPUTEST_HOME)/include
  1153. CXXFLAGS += -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorNewMacros.h
  1154. CFLAGS += -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorMallocMacros.h
  1155. LD_LIBRARIES = -L$(CPPUTEST_HOME)/lib -lCppUTest -lCppUTestExt
  1156.  
  1157. TARGET = test_main
  1158. SRCS = test_main.cpp LedDriver/LedDriverTest.cpp
  1159. CSRCS = LedDriver/LedDriver.c
  1160. OBJS = $(SRCS:.cpp=.o) $(CSRCS:.c=.o)
  1161.  
  1162. all: $(TARGET)
  1163.  
  1164. $(TARGET): $(OBJS)
  1165. $(CXX) -o $@ $^ $(CXXFLAGS) $(LD_LIBRARIES)
  1166.  
  1167. %.o: %.cpp
  1168. # GNU make implicit rule + "-o $@"
  1169. $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
  1170.  
  1171. %.o: %.c
  1172. # GNU make implicit rule + "-o $@"
  1173. $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
  1174.  
  1175. .PHONY: check
  1176. check: $(TARGET)
  1177. ./$(TARGET) -v
  1178.  
  1179. .PHONY: clean
  1180. clean:
  1181. rm -f $(TARGET) $(OBJS) *.gcno *.gcov *~ */*~
  1182. find . -name "*.gcda" | xargs rm -f
  1183. </pre></code></blockquote>
  1184.  
  1185. <p>make checkすると、"OK (7 tests, 6 ran, 6 checks, 1 ignored, ...)"となる。<br />
  1186. ignoredなのは「実行可能なリマインダ」である。
  1187. </p>
  1188.  
  1189. <p>ところで、CppUTestには簡単なメモリリーク検出機能がある。各TEST()の実行前にTEST_GROUPのsetup()が、実行後にteardown()が呼び出されるが、そのsetup()前とteardown()後とでメモリ確保状態を比較するようである。<br />
  1190. 試しに、LedDriver/LedDriver.cのLedDriver_TurnAllOn()を
  1191. <blockquote><code><pre>
  1192. #include &lt;stdlib.h&gt;
  1193. void LedDriver_TurnAllOn(void)
  1194. {
  1195. void *p = malloc(1);
  1196. *ledsAddress = ALL_LEDS_ON;
  1197. }
  1198. </pre></code></blockquote>
  1199. に変えてmake checkとすると、次のエラーメッセージが出た。
  1200. <blockquote><samp><pre>
  1201. TEST(LedDriver, AllOn)
  1202. LedDriver/LedDriverTest.cpp:46: error: Failure in TEST(LedDriver, AllOn)
  1203. Memory leak(s) found.
  1204. Alloc num (6) Leak size: 1 Allocated at: LedDriver/LedDriver.c and line: 35. Type: "malloc"
  1205. </pre></samp></blockquote>
  1206. </p>
  1207. <p>うまく使えば便利そうである。<br />
  1208. CppUTestに触れてみて、TDDをきちんと勉強しようと思った。
  1209. </p>]]></description>
  1210.         <link>http://ynomura.dip.jp/archives/2016/05/cpputest1.html</link>
  1211.         <guid>http://ynomura.dip.jp/archives/2016/05/cpputest1.html</guid>
  1212.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  1213.        
  1214.        
  1215.         <pubDate>Sun, 29 May 2016 18:22:12 +0900</pubDate>
  1216.      </item>
  1217.      
  1218.   </channel>
  1219. </rss>
  1220.  

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid RSS" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.feedvalidator.org/check.cgi?url=http%3A//ynomura.dip.jp/index.xml

Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda