<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5771870301252721821</id><updated>2011-08-31T22:36:39.067+09:00</updated><category term='C++'/><category term='scheme'/><category term='NLP'/><category term='python'/><category term='STL'/><category term='mecab'/><category term='haskell'/><title type='text'>TekTekBLOG</title><subtitle type='html'>PythonやC++のメモ</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://hiroshiykw.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default?start-index=101&amp;max-results=100'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>135</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6138177758419078014</id><published>2011-05-01T07:21:00.003+09:00</published><updated>2011-05-01T07:54:33.928+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>pypyで何も考えずにpythonを高速化する</title><content type='html'>&lt;a href="http://python.org/"&gt;Python公式&lt;/a&gt;のCPythonよりも高速という噂の&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/"&gt;pypy&lt;/a&gt;が&lt;a href="http://morepypy.blogspot.com/2011/04/pypy-15-released-catching-up.html"&gt;Python2.7.1相当の機能を実装した&lt;/a&gt;というので、その実行速度を測定しました。&lt;br/&gt;&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;■インストール（OSX）&lt;/b&gt;&lt;br/&gt;&lt;br /&gt;pypyのインストールは非常に簡単で、&lt;a href="http://pypy.org/download.html#default-with-a-jit-compiler"&gt;本家からbzipをダウンロード&lt;/a&gt;して解凍したらできあがりです。&lt;br/&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ tar xjvf pypy-1.5-osx64.tar.bz2&lt;br /&gt;$ cd pypy-c-jit-43780-b590cf6de419-osx64&lt;br /&gt;$ ls&lt;br /&gt;LICENSE  README  bin  include  lib-python lib_pypy site-packages&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;binの中にpypyというコマンドがありますので、それを実行すると起動します。&lt;br/&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ bin/pypy&lt;br /&gt;&lt;br /&gt;Python 2.7.1 (b590cf6de419, Apr 30 2011, 03:30:00)&lt;br /&gt;[PyPy 1.5.0-alpha0 with GCC 4.0.1] on darwin&lt;br /&gt;Type "help", "copyright", "credits" or "license" for more information.&lt;br /&gt;And now for something completely different: ``how to construct the blackhole&lt;br /&gt;interpreter: we reuse the tracing one, add lots of ifs and pray''&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&amp;gt;が３つではなく４つ出てくるところが、公式CPythonよりも強そうですよね！&lt;br/&gt;&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;■実測&lt;/b&gt;&lt;/br&gt;&lt;br /&gt;実際にPython標準のパフォーマンス測定ツール&lt;a href="http://www.python.jp/doc/2.4/lib/module-timeit.html"&gt;timeit&lt;/a&gt;で、実行速度を比較してみました。&lt;br/&gt;&lt;br /&gt;比較のため、OSX上のCPython2.6.1, 2.7,1とpypyを使いました。&lt;br/&gt;&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;まずは単純に配列を作る処理。&lt;br/&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-------  CPython 2.6.1&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import timeit&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; t = timeit.Timer(stmt="[x*x for x in xrange(1000)]")&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)&lt;br /&gt;184.11 usec/pass&lt;br /&gt;&lt;br /&gt;-------  CPython 2.7.1&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import timeit&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; t = timeit.Timer(stmt="[x*x for x in xrange(1000)]")&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)&lt;br /&gt;153.30 usec/pass&lt;br /&gt;&lt;br /&gt;------- pypy 1.5&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; import timeit&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; t = timeit.Timer(stmt="[x*x for x in xrange(1000)]")&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)&lt;br /&gt;120.95 usec/pass&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;CPython2.7は2.6よりもだいぶ速いですが、それをさらにpypyが上回る速度です。&lt;br/&gt;&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;次に、集合(set)の中の検索&lt;br/&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-------  CPython 2.6.1&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; t = timeit.Timer(setup="a=set([x*x for x in xrange(100)])", stmt="[(x in a) for x in xrange(100)]")&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)&lt;br /&gt;23.41 usec/pass&lt;br /&gt;&lt;br /&gt;-------  CPython 2.7.1&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; t = timeit.Timer(setup="a=set([x*x for x in xrange(100)])", stmt="[(x in a) for x in xrange(100)]")&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)&lt;br /&gt;19.59 usec/pass&lt;br /&gt;&lt;br /&gt;-------  pypy1.5&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; t = timeit.Timer(setup="a=set([x*x for x in xrange(100)])", stmt="[(x in a) for x in xrange(100)]")&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)&lt;br /&gt;11.97 usec/pass&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;これも結果は同様に圧倒的にpypyが高速。(2.7の２倍に迫る速度！）&lt;br/&gt;&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;こんなに簡単に高速化できるなら、どこかで試しに使ってみたくなりますよね。&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6138177758419078014?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6138177758419078014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6138177758419078014'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2011/05/pypypython.html' title='pypyで何も考えずにpythonを高速化する'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-2442516226620332423</id><published>2011-02-08T20:39:00.007+09:00</published><updated>2011-02-08T21:40:24.411+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Ajaxを補足するためのPythonによる手軽なマルチスレッド処理</title><content type='html'>Webアプリの開発で、重い処理はAjaxで別途処理して取得するという手段が取れない場合があります。&lt;br /&gt;&lt;br /&gt;「画面の一部で矢印がぐるぐる回って待たせるのではなく、本当に一瞬で全部表示したい」&lt;br /&gt;&lt;br /&gt;などの場合です。&lt;br /&gt;&lt;br /&gt;そんなときにお手軽に使えるテクニックとして、サーバー処理のマルチスレッドによる並列化があります。&lt;br /&gt;Pythonのマルチスレッドでは、高度なCPUの並列処理はできませんが（グローバルインタプリタロックと言います）、少なくともI/O待ちの間別の処理を流す程度の事は可能です。[&lt;a href="http://www.python.jp/doc/2.4/api/threads.html"&gt;参考&lt;/a&gt;]&lt;br /&gt;その特徴を生かして、Webアプリのレスポンスを速めることができます。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;これを使う場面ですが、たとえば、以下のようなものがあります。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_TlQ68V-OBvk/TVE4pnU_ifI/AAAAAAAACYc/HriSwniX09Y/s1600/biz.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 227px;" src="http://1.bp.blogspot.com/_TlQ68V-OBvk/TVE4pnU_ifI/AAAAAAAACYc/HriSwniX09Y/s320/biz.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5571296501616839154" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;この画面はうちの会社で作っている&lt;a href="http://www.patentresult.co.jp/lp-biz.html"&gt;特許分析WEBアプリのBiz Cruncher&lt;/a&gt;というもので、特許の詳細な内容を表示しているところです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;特許の閲覧というのは企業知財部では古来から「手めくり」と呼ばれ、いかに速く大量の特許の内容を把握するかに心血を注ぎます。&lt;br /&gt;そのため、図などは一瞬で見れるべきだし、電子的な画面であろうと、一瞬で次々表示されなければストレスを感じるものです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;そういう場合は付属情報はAjax化で別リクエストにするにしても、必須の要素だけは泣く泣く１リクエストに押し込んで、極限まで速度を向上させる必要があります。&lt;br /&gt;&lt;br /&gt;たとえば、上の特許詳細画面では時間のかかる処理として、テキストマイニング、画像の生成、詳細テキスト（長文）の取得、引用情報・経過情報の取得　etc.をそれこそ一瞬で行う必要がありました。&lt;br /&gt;&lt;br /&gt;改良前はこの表示に2.8秒かかっていたのですが、それでも不満ということで、冒頭のマルチスレッド化を行って0.7秒にまで縮めることができました。&lt;br /&gt;&lt;br /&gt;具体的には以下の関数 call_async を使います。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;import threading&lt;br /&gt;def call_async(target, args=None, kwargs=None):&lt;br /&gt;    u"""&lt;br /&gt;    関数非同期呼び出しツール。&lt;br /&gt;    関数を別スレッドで呼び出して、その後結果を取得できます。&lt;br /&gt;&lt;br /&gt;    #使用例&lt;br /&gt;    r = call_async(f,args=(5,))&lt;br /&gt;        #ここで別の処理を片付けます。&lt;br /&gt;    r["thread"].join()  #スレッドが終わるのを待ちます。&lt;br /&gt;    if "result" in r:&lt;br /&gt;        print "RESULT", r["result"]&lt;br /&gt;    else:&lt;br /&gt;        print "ERROR", str(r["exception"])&lt;br /&gt;    """&lt;br /&gt;    res = {}&lt;br /&gt;    def f(*inargs, **inkwargs):&lt;br /&gt;        try:&lt;br /&gt;            inargs[-1]["result"] = target(*(inargs[:-1]), **inkwargs)&lt;br /&gt;        except Exception, e:&lt;br /&gt;            inargs[-1]["exception"] = e&lt;br /&gt;    res["thread"] = threading.Thread(target=f, args=(args+(res,)), kwargs=kwargs)&lt;br /&gt;    res["thread"].start()&lt;br /&gt;    return res&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;この関数を使うと、関数呼び出しを別スレッドにしながら、その返り値を取得することもできます。&lt;br /&gt;使用方法は上記関数のコメント内にありますが、以下のように、先に遅い処理を実行開始しておき、平行してその他の処理を済ませたあとで、ゆっくりと結果を取得します。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    #使用例 slow1～3という遅い処理の関数がある場合&lt;br /&gt;&lt;br /&gt;    #まず冒頭で遅い処理を別スレッドで実行開始しておきます。&lt;br /&gt;    r1 = call_async(slow1,args=(5,))     #遅い処理1を開始！&lt;br /&gt;    r2 = call_async(slow2,args=("ABC","DEF"))     #遅い処理2を開始！&lt;br /&gt;    r3 = call_async(slow3,args=([1,2,3,4]))     #遅い処理3を開始！&lt;br /&gt;&lt;br /&gt;        #ここでその他の処理を片付けます。&lt;br /&gt;&lt;br /&gt;    r1["thread"].join()  #スレッドが終わるのを待ちます。&lt;br /&gt;    r2["thread"].join()  #スレッドが終わるのを待ちます。&lt;br /&gt;    r3["thread"].join()  #スレッドが終わるのを待ちます。&lt;br /&gt;&lt;br /&gt;    if "result" in r1:   #slow1の結果を使う処理&lt;br /&gt;        print "RESULT 1", r1["result"]&lt;br /&gt;    else:&lt;br /&gt;        print "ERROR 1", str(r1["exception"])&lt;br /&gt;&lt;br /&gt;    if "result" in r2:   #slow2の結果を使う処理&lt;br /&gt;        print "RESULT 2", r2["result"]&lt;br /&gt;    else:&lt;br /&gt;        print "ERROR 2", str(r2["exception"])&lt;br /&gt;&lt;br /&gt;    if "result" in r3:   #slow3の結果を使う処理&lt;br /&gt;        print "RESULT 3", r3["result"]&lt;br /&gt;    else:&lt;br /&gt;        print "ERROR 3", str(r3["exception"])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;こうすることで、I/O待ちの発生する処理をいくつも並列で実行でき、実行時間の効果的な短縮を実現できます。&lt;br /&gt;&lt;br /&gt;こうした手段としてPython標準のmultiprocessingが検討にあがりますが、あれはより高度な分散処理用ですので、関数の結果を取得しようとすると、とたんに大仰なものになります。&lt;br /&gt;&lt;br /&gt;また、もちろんですが、この秒数の短縮で効果的なのはJavascriptの最適化もあるわけです。&lt;br /&gt;それをした後に、さらにどうしてもサーバー側も高速化しないといけない場合は、このお手軽なマルチスレッド化も考慮するとよいと思います。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-2442516226620332423?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2442516226620332423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2442516226620332423'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2011/02/ajaxpython.html' title='Ajaxを補足するためのPythonによる手軽なマルチスレッド処理'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_TlQ68V-OBvk/TVE4pnU_ifI/AAAAAAAACYc/HriSwniX09Y/s72-c/biz.png' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-1039529895057807388</id><published>2010-12-04T16:45:00.003+09:00</published><updated>2010-12-04T16:50:48.727+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>PythonのUnicode-&gt;UTF-8変換はSJISやEUCへの変換よりもちょっと速い</title><content type='html'>想像していた通りですが、UnicodeをUTF-8に変換するのは、SJISやEUCに変換するよりもちょっと速いことがわかった。&lt;br/&gt;&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import timeit&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; def unicode_henkan(c):&lt;br /&gt;...     t = timeit.Timer("a.encode('%s')" % c, "a=u'\u3042'*10000")&lt;br /&gt;...     print t.timeit(number=1000)&lt;br /&gt;... &lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; unicode_henkan("utf-8")&lt;br /&gt;0.075012922287&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; unicode_henkan("sjis")&lt;br /&gt;0.19597196579&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; unicode_henkan("eucjp")&lt;br /&gt;0.146716833115&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; unicode_henkan("cp932")&lt;br /&gt;0.21554517746&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ちなみに、timeitは与えられた計測対象のプログラムを内部でpythonのプログラムとして解釈する際に、文字コードのことをあまり考えてくれないようなので、&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;t = timeit.Timer("a.encode('%s')" % c, "a=u'あ'*10000")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;のように書くとUnicodeErrorになります。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-1039529895057807388?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1039529895057807388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1039529895057807388'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2010/12/pythonunicode-utf-8sjiseuc.html' title='PythonのUnicode-&gt;UTF-8変換はSJISやEUCへの変換よりもちょっと速い'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8222029618941416851</id><published>2010-09-14T11:16:00.002+09:00</published><updated>2010-09-14T11:26:56.544+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>関数呼び出しをタプル形式にして遅延させる関数</title><content type='html'>関数呼び出しをタプルの情報にして保存するしくみを作った。&lt;br /&gt;これを使えばWEBアプリでリクエストをまたいで関数呼び出しを遅延させることができるようになります。&lt;br /&gt;関数呼び出しをタプル形式にして、memcacheなどに保存しておき、次に来たときに本当に呼び出したり。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;# coding: utf-8&lt;br /&gt;import inspect&lt;br /&gt;import imp&lt;br /&gt;&lt;br /&gt;def freeze_func(func, *args, **kwargs):&lt;br /&gt;    u"""&lt;br /&gt;    関数呼び出しを保存可能なタプル形式に変換する。&lt;br /&gt;    """&lt;br /&gt;    m = inspect.getmodule(func)&lt;br /&gt;    return m.__name__, func.__name__, args, kwargs&lt;br /&gt;&lt;br /&gt;def __importer(m, path):&lt;br /&gt;    a = imp.find_module(m[0], path)&lt;br /&gt;    b = imp.load_module(m[0], *a)&lt;br /&gt;    if len(m) &amp;gt; 1:&lt;br /&gt;        return __importer(m[1:], b.__path__)&lt;br /&gt;    else:&lt;br /&gt;        return b&lt;br /&gt;&lt;br /&gt;def _importer(modname):&lt;br /&gt;    modname = modname.split(".")&lt;br /&gt;    return __importer(modname, None)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def unfreeze_func(info):&lt;br /&gt;    u"""&lt;br /&gt;    タプル形式で保存された関数呼び出しを関数に復元して実行する。&lt;br /&gt;    """&lt;br /&gt;    b = _importer(info[0])&lt;br /&gt;    f = getattr(b, info[1])&lt;br /&gt;    args = info[2]&lt;br /&gt;    kwargs = info[3]&lt;br /&gt;    return f(*args, **kwargs)&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    import re&lt;br /&gt;    info = freeze_func(re.sub, r"[A-Za-z]", "*", "5-3-1 Asakusabashi")&lt;br /&gt;    print info     # -&amp;gt; ('re', 'sub', ('[A-Za-z]', '*', '5-3-1 Asakusabashi'), {})&lt;br /&gt;    print unfreeze_func(info)  # -&amp;gt; "5-3-1 ************"&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8222029618941416851?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8222029618941416851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8222029618941416851'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2010/09/blog-post.html' title='関数呼び出しをタプル形式にして遅延させる関数'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-7058561712734152745</id><published>2008-05-24T03:51:00.003+09:00</published><updated>2008-05-24T03:55:11.986+09:00</updated><title type='text'>Djangoでblogっぽいのを作ったので移動します</title><content type='html'>Djangoでblogっぽいのを作ったので移動します。RSSも吐いておりますので宜しくお願いします。&lt;br /&gt;→&lt;a href="http://www.tektek.in/d/blog/"&gt;新TekTekBlog&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;移動の理由:&lt;br /&gt; 1. このBloggerでは一切のJavascriptなどが貼れないので不便。アクセス解析の類も一切無理。&lt;br /&gt; 2. データのエクスポート機能もないので、書き溜めても外部に効率的に持ち出せない。&lt;br /&gt; 3. 自分で作って自分で設置するほうが面白い。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-7058561712734152745?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7058561712734152745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7058561712734152745'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/djangoblog.html' title='Djangoでblogっぽいのを作ったので移動します'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-2408040234060352995</id><published>2008-05-23T02:04:00.005+09:00</published><updated>2008-05-23T02:18:16.434+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>はてブのホットエントリをなんとなーく分類するPythonスクリプトサンプル</title><content type='html'>昨日作った、&lt;a href="http://hiroshiykw.blogspot.com/2008/05/wardpython.html"&gt;Ward法のPythonバインディング&lt;/a&gt;を使って、はてなブックマークのホットエントリをなんとなーく分類するPythonスクリプトのサンプルを書いてみた。&lt;br /&gt;&lt;br /&gt;サンプルプログラムは例によって、&lt;a href="http://coderepos.org/share/browser/lang/cplusplus/misc/clustercpp/python/wardcluster/hatenasample.py"&gt;CodeReposに置きました。&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;試しに今の時点(5/23 深夜2:06)のホットエントリを分類した結果は以下のような感じです。&lt;br /&gt;なんとなーく、分類されているような雰囲気。&lt;br /&gt;もっと各エントリの情報を取得すれば精度は上がるんでしょうが、今の所はホットエントリのRSS一枚から取得できる情報(今の所タイトル中の名詞と、タグの単語)だけを使って分類しています。&lt;br /&gt;&lt;br /&gt;-----  以下、その結果 -----&lt;br /&gt;&lt;div style="line-height:1.2em;"&gt;Group [ 50 ] --------------------&lt;br /&gt;&lt;a href='http://business.nikkeibp.co.jp/article/tech/20080520/157860/?P=1'&gt;「トレードオフの概念は日本に無いのか」 三菱東京UFJ銀のシステム一本化報道に思う：NBonline(日経ビジネス オンライン)&lt;/a&gt;&lt;br /&gt;&lt;a href='http://business.nikkeibp.co.jp/article/tech/20080520/157860/'&gt;「トレードオフの概念は日本に無いのか」 三菱東京UFJ銀のシステム一本化報道に思う：NBonline(日経ビジネス オンライン)&lt;/a&gt;&lt;br /&gt;&lt;a href='http://plusd.itmedia.co.jp/pcuser/articles/0805/22/news055.html'&gt;なぜか変換できない vs. なぜか変換できる：最近の「MS-IME」は目に余る――よろしい、ならば「ATOK」だ (1/4) - ITmedia +D PC USER&lt;/a&gt;&lt;br /&gt;&lt;a href='http://plusd.itmedia.co.jp/lifestyle/articles/0805/22/news019.html'&gt;今日から始めるデジカメ撮影術：第97回　一眼レフとボケの関係 (1/3) - ITmedia  D LifeStyle&lt;/a&gt;&lt;br /&gt;&lt;a href='http://blog.goo.ne.jp/kotoba_mamoru/e/307f39118eb8847c93c6e27b405debd3'&gt;NHK「クローズアップ現代」児ポ法単純所持処罰に絞って特集 - フィギュア萌え族(仮)犯行説問題ブログ版・サブカル叩き報道を追う&lt;/a&gt;&lt;br /&gt;&lt;a href='http://headlines.yahoo.co.jp/hl?a=20080522-00000015-maiall-soci'&gt;＜ネットカフェ難民＞「しんどい」と訴える妊婦まで　１００人の実態調査（毎日新聞） - Yahoo!ニュース&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Group [ other ] --------------------&lt;br /&gt;&lt;a href='http://builder.japan.zdnet.com/news/story/0,3800079086,20373608,00.htm'&gt;Steve Jobs氏のようにプレゼンテーションをする方法 - builder by ZDNet Japan&lt;/a&gt;&lt;br /&gt;&lt;a href='http://wiredvision.jp/news/200805/2008052121.html'&gt;調査結果に基づいて合成「人々が最も不愉快になる曲／最も聴きたい曲」：試聴可能 | WIRED VISION&lt;/a&gt;&lt;br /&gt;&lt;a href='http://japan.cnet.com/marketing/story/0,3800080523,20373730,00.htm'&gt;グーグル、検索アルゴリズムを少しずつ明らかに:マーケティング - CNET Japan&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Group [ 59 ] --------------------&lt;br /&gt;&lt;a href='http://gigazine.net/index.php?/news/comments/20080522_sex_benefit/'&gt;愛し合うってすばらしい、セックスすると得られる10の効能 - GIGAZINE&lt;/a&gt;&lt;br /&gt;&lt;a href='http://www.hatena.ne.jp/info/hatenaclub'&gt;はてなクラブ - はてな&lt;/a&gt;&lt;br /&gt;&lt;a href='http://d.hatena.ne.jp/mojimoji/20080522/p1'&gt;十字軍はバカに勝てるか - モジモジ君の日記。みたいな。&lt;/a&gt;&lt;br /&gt;&lt;a href='http://www.digitaldj.jp/2008/05/22_180000.html'&gt;「宅配寿司 銀のさら」の自虐CM | DIGITAL DJ&lt;/a&gt;&lt;br /&gt;&lt;a href='http://anond.hatelabo.jp/20080522131842'&gt;変な人があまりにも酷すぎる件について&lt;/a&gt;&lt;br /&gt;&lt;a href='http://d.hatena.ne.jp/komachimania/20080521/p2'&gt;高学歴のお嬢様をお持ちの方、教えて下さい - 発狂小町&lt;/a&gt;&lt;br /&gt;&lt;a href='http://med-legend.com/2008/05/%E7%9B%AE%E3%82%92%E9%96%8B%E3%81%84%E3%81%A6%E3%81%84%E3%82%8B%E3%81%AE%E3%81%AB%E9%96%89%E3%81%98%E3%81%A6%E3%81%84%E3%82%8B%E3%81%A8%E6%84%9F%E3%81%98%E3%82%8B%E9%8C%AF%E8%A6%9A%E4%BD%9C%E6%88%90/'&gt;目を開いているのに閉じていると感じる錯覚作成法 | 医学都市伝説&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Group [ 60 ] --------------------&lt;br /&gt;&lt;a href='http://d.hatena.ne.jp/fuku33/20080522/1211444127'&gt;ケーキを売ればいいのに - 福耳コラム&lt;/a&gt;&lt;br /&gt;&lt;a href='http://2chart.fc2web.com/ochiaigundam.html'&gt;落合博満ガンダム宣言&lt;/a&gt;&lt;br /&gt;&lt;a href='http://blitznews.blog97.fc2.com/blog-entry-1021.html'&gt;電撃速報!! Amazonを倉庫代わりにしていた転売厨終了のお知らせ&lt;/a&gt;&lt;br /&gt;&lt;a href='http://d.hatena.ne.jp/GilCrows/20080521/p1'&gt;『らき☆すた』を見た非オタの友人が衝撃の一言 - GilCrowsのペネトレイト・トーク&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Group [ 64 ] --------------------&lt;br /&gt;&lt;a href='http://gura5.blog120.fc2.com/blog-entry-137.html'&gt;世界のPhotoshopチュートリアル トップ50 - ITクオリティ&lt;/a&gt;&lt;br /&gt;&lt;a href='http://coliss.com/articles/build-websites/operation/design/1112.html'&gt;光源、光線、光跡を表現するPhotoshopのブラシ -2XGU.NET | コリス&lt;/a&gt;&lt;br /&gt;&lt;a href='http://d.hatena.ne.jp/mkusunok/20080521/wocs'&gt;歌舞伎町で遇ったギークなタクシー運転手の編み出した、群衆の英知を活かした馬券購入法 - 雑種路線でいこう&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Group [ 68 ] --------------------&lt;br /&gt;&lt;a href='http://gigazine.net/index.php?/news/comments/20080522_miterudake/'&gt;人間関係が苦手で社会に適合できない人向けのDVDソフト「ミテルだけ」が登場 - GIGAZINE&lt;/a&gt;&lt;br /&gt;&lt;a href='http://gigazine.net/index.php?/news/comments/20080522_youtomb/'&gt;YouTubeから削除された動画の墓場「YouTomb」が登場、日本のアニメの削除件数は圧倒的 - GIGAZINE&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Group [ 72 ] --------------------&lt;br /&gt;&lt;a href='http://air-users.jp/'&gt;AIR-users.jp - 日本の AIR ユーザのためのハブサイト&lt;/a&gt;&lt;br /&gt;&lt;a href='http://js-users.jp/'&gt;js-users.jp - 日本の JavaScript ユーザのためのハブサイト&lt;/a&gt;&lt;br /&gt;&lt;a href='http://perl-users.jp/'&gt;perl-users.jp - 日本の Perl ユーザのためのハブサイト&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Group [ 75 ] --------------------&lt;br /&gt;&lt;a href='http://blog.livedoor.jp/dqnplus/archives/1130403.html'&gt;痛いニュース(ﾉ∀`):「美少女ゲーム（エロゲ）・アニメは、人間性を破壊し少女殺害事件につながる。販売規制を」…民主党女性議員が請願&lt;/a&gt;&lt;br /&gt;&lt;a href='http://gigazine.net/index.php?/news/comments/20080522_sangiin_game/'&gt;「美少女ゲーム・アニメをする人は心を破壊され、人間性を失っているので規制すべき」と主張するトンデモ請願が参議院に - GIGAZINE&lt;/a&gt;&lt;br /&gt;&lt;a href='http://blog.livedoor.jp/dqnplus/archives/1130723.html'&gt;痛いニュース(ﾉ∀`):「ジョジョの奇妙な冒険」、中東で「日本が侮辱」「テレビ局爆破しろ」と批判殺到→集英社、原作の第３部など出荷停止&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Group [ 76 ] --------------------&lt;br /&gt;&lt;a href='http://wordpress.rauru-block.org/index.php/1656'&gt;人工知能の叛乱&lt;/a&gt;&lt;br /&gt;&lt;a href='http://www.ideaxidea.com/archives/2008/05/gmail_1.html'&gt;Gmailの検索オプションまとめ | IDEA*IDEA&lt;/a&gt;&lt;br /&gt;&lt;a href='http://d.hatena.ne.jp/tanemori/20080520/MostUsedApps'&gt;マックユーザがインストールしているアプリケーション - soundscape out&lt;/a&gt;&lt;br /&gt;&lt;a href='http://okyuu.com/ja/top'&gt;[okyuu.com] ソーシャルITメディア&lt;/a&gt;&lt;br /&gt;&lt;a href='http://www.designwalker.com/2008/05/transparent-inspiration.html'&gt;透過をきれいに使ったウェブデザインいろいろ - DesignWalker&lt;/a&gt;&lt;br /&gt;&lt;a href='http://gihyo.jp/dev/feature/01/firebug'&gt;特集：Firefox 3とFirebugで始めるJavaScript開発｜gihyo.jp … 技術評論社&lt;/a&gt;&lt;br /&gt;&lt;a href='http://d.hatena.ne.jp/koto2/20080518/1211070116'&gt;PHP コード最適化 Best Practices 63+ - カタコト日記&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Group [ 77 ] --------------------&lt;br /&gt;&lt;a href='http://www.nikkansports.com/general/news/f-gn-tp0-20080522-362998.html'&gt;「ジョジョの奇妙な冒険」が中東で非難 - 社会ニュース : nikkansports.com&lt;/a&gt;&lt;br /&gt;&lt;a href='http://sankei.jp.msn.com/world/mideast/080522/mds0805220813001-n1.htm'&gt;「コーラン読み殺害指示」日本アニメ、中東で非難 - MSN産経ニュース&lt;/a&gt;&lt;br /&gt;&lt;a href='http://www.asahi.com/business/update/0521/NGY200805210017.html'&gt;asahi.com：トヨタ、「カイゼン」に残業代　業務と認定、来月から - ビジネス&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Group [ 78 ] --------------------&lt;br /&gt;&lt;a href='http://alfalfa.livedoor.biz/archives/51299093.html'&gt;ヒトラー名言集:アルファルファモザイク&lt;/a&gt;&lt;br /&gt;&lt;a href='http://alfalfa.livedoor.biz/archives/51299206.html'&gt;傷つきやすい人はどうすれば強くなる？:アルファルファモザイク&lt;/a&gt;&lt;br /&gt;&lt;a href='http://alfalfa.livedoor.biz/archives/51296978.html'&gt;ウマーな牛スジカレーの作り方:アルファルファモザイク&lt;/a&gt;&lt;br /&gt;&lt;a href='http://www.itmedia.co.jp/news/articles/0805/21/news101.html'&gt;ねとらぼ：米WIREDに「やる夫」の特大AA掲載　ひろゆき氏インタビューも - ITmedia News&lt;/a&gt;&lt;br /&gt;&lt;a href='http://www.gamenews.ne.jp/archives/2008/05/1500_1.html'&gt;1日500アクセス以上のブログは全ブログの●％:Garbagenews.com&lt;/a&gt;&lt;br /&gt;&lt;a href='http://portal.nifty.com/2008/05/22/a/'&gt;@nifty：デイリーポータルZ：50年前の新聞広告&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Group [ 79 ] --------------------&lt;br /&gt;&lt;a href='http://www.moongift.jp/2008/05/usvn/'&gt;MOONGIFT: � ブラウザベースのSubversion管理ツール「USVN」:オープンソースを毎日紹介&lt;/a&gt;&lt;br /&gt;&lt;a href='http://phpspot.org/blog/archives/2008/05/css_58.html'&gt;CSSで背景画像をリサイズするテクニック:phpspot開発日誌&lt;/a&gt;&lt;br /&gt;&lt;a href='http://www.makonako.com/mt/archives/2008/05/post_689.html'&gt;ナムコの成果主義、有能なゲーム開発者が報われない開発現場&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-2408040234060352995?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2408040234060352995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2408040234060352995'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/python_23.html' title='はてブのホットエントリをなんとなーく分類するPythonスクリプトサンプル'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-2966950523963649335</id><published>2008-05-22T02:00:00.005+09:00</published><updated>2008-05-22T02:14:59.782+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Ward法のPythonバインディングを作りました。</title><content type='html'>&lt;a href="http://hiroshiykw.blogspot.com/2008/05/cward-g.html"&gt;先日から作っていたクラスタリング(Ward法)&lt;/a&gt;のPython用バインディングを作りました。Pythonから一応つないで使えるようになりました。&lt;br /&gt;&lt;br /&gt;ソースコードの取得とインストール。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ svn export http://svn.coderepos.org/share/lang/cplusplus/misc/clustercpp&lt;br /&gt;$ cd clustercpp/python/wardcluster&lt;br /&gt;$ python setup.py build_ext --swig-cpp&lt;br /&gt;$ sudo python setup.py install&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;サンプル実行。&lt;br /&gt;引き続きディレクトリclustercpp/python/wardcluster内で以下を実行してください。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ python sample.py&lt;br /&gt;1 + 0 =&gt; 4 ( 0.244948974278 )&lt;br /&gt;3 + 2 =&gt; 5 ( 0.412310562562 )&lt;br /&gt;5 + 4 =&gt; 6 ( 4.80645253132 )&lt;br /&gt;$&lt;/pre&gt;&lt;br /&gt;ちなみに、今上で動いたsample.pyは以下のようなスクリプトで、４本のベクトルをクラスタリングしています。&lt;br /&gt;&lt;pre&gt;from wardcluster import Matrix, DoubleVec, Ward&lt;br /&gt;&lt;br /&gt;m = Matrix()&lt;br /&gt;m.append(DoubleVec([1.0, 2.0, 3.0]))&lt;br /&gt;m.append(DoubleVec([1.1, 2.2, 2.9]))&lt;br /&gt;m.append(DoubleVec([0.1, 1.2, 5.0]))&lt;br /&gt;m.append(DoubleVec([0.3, 1.0, 5.3]))&lt;br /&gt;&lt;br /&gt;w = Ward()&lt;br /&gt;&lt;br /&gt;history = w.cluster(m, 4) #この4ってのは、ベクトルの本数&lt;br /&gt;&lt;br /&gt;for h in history:&lt;br /&gt;    print h.index1, "+" , h.index2, "=&gt;", h.newindex , "(", h.distance ,")"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;メモ--------&lt;br /&gt; * setuptoolsを使ったオシャレなモジュールにするのは断念。（swigの結果ファイルとの調整が難しかった）&lt;br /&gt; * swigのtypemap?とか、そういうのはむずかしくて分からないので、めんどくさいインターフェース。&lt;br /&gt; * あくまで実験的なものですよ。&lt;br /&gt; * 相変わらずswigを理解できていない。&lt;br /&gt; * 今回ベクトルの集合を表すために内部でstd::vector&amp;lt;std::vector&amp;lt;double&gt; &gt;を使うようにしたので、パフォーマンスが落ちています。（将来もとのstd::vector&amp;lt;double&gt;*を使って渡す方式に戻したいものです。。。）&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-2966950523963649335?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2966950523963649335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2966950523963649335'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/wardpython.html' title='Ward法のPythonバインディングを作りました。'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-1240607219392476890</id><published>2008-05-20T00:02:00.003+09:00</published><updated>2008-05-20T00:10:54.836+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>C++のWard法-&gt;g++のオプションで驚異的な高速化</title><content type='html'>先日から作っているクラスタリングアルゴリズムの一種&lt;a href="http://hiroshiykw.blogspot.com/2008/05/python-c.html"&gt;Ward法のプログラム&lt;/a&gt;を&lt;a href="http://coderepos.org/share/changeset/12008"&gt;今日もいじっていた。&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;こまごまとしたことをしたのだが、コンパイルオプションをいじると、恐ろしく速くなった。&lt;br /&gt;&lt;br /&gt;まず、比較のために、前回の結果。&lt;br /&gt;&lt;pre&gt;件数   処理時間(s)    そのうち初期行列作成時間&lt;br /&gt;--------------------------------------------&lt;br /&gt;2352   33.432          6.39&lt;/pre&gt;&lt;br /&gt;そこに、今回以下のコンパイルオプションをつけてみた。(ちなみにOSX10.4&amp;Intelな白MacBookの環境です。）&lt;br /&gt;&lt;pre&gt;g++ -O3 -ffast-math -funroll-loops -Wall -fno-common -march=nocona -o ward -I../include ward.cpp&lt;/pre&gt;&lt;br /&gt;その結果、以下のように高速化された。&lt;br /&gt;&lt;pre&gt;件数   処理時間(s)    そのうち初期行列作成時間&lt;br /&gt;--------------------------------------------&lt;br /&gt;2352   12.628          1.06&lt;/pre&gt;&lt;br /&gt;シャアではないが、通常の３倍以上の速さである。&lt;br /&gt;C++恐るべし。&lt;br /&gt;分散処理とか考えるのはやはりC++で肝心の部分を書いて、その後なんだろうなと実感しました。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-1240607219392476890?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1240607219392476890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1240607219392476890'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/cward-g.html' title='C++のWard法-&gt;g++のオプションで驚異的な高速化'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6653250068601074218</id><published>2008-05-16T22:52:00.008+09:00</published><updated>2008-05-17T17:17:11.865+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Python -&gt; C++への移植でどれぐらい速くなったか</title><content type='html'>&lt;a href="http://hiroshiykw.blogspot.com/2008/05/ward_15.html"&gt;先日、Pythonで実装したWard法&lt;/a&gt;をC++で再実装し、比較してみた。&lt;br /&gt;&lt;br /&gt;まずは、前回のPython版の処理時間を再掲。&lt;br /&gt;&lt;pre&gt;件数   処理時間(s)    そのうち初期行列作成時間&lt;br /&gt;--------------------------------------------&lt;br /&gt;196     0.677          0.334&lt;br /&gt;392     2.158          1.356&lt;br /&gt;588     4.636          3.073&lt;br /&gt;1176    18.071         12.088&lt;br /&gt;2352    79.09          49.507&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;これをC++に移植すると、以下の処理時間に短縮される。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;件数   処理時間(s)    そのうち初期行列作成時間&lt;br /&gt;--------------------------------------------&lt;br /&gt;196     0.216          0.04&lt;br /&gt;392     0.842          0.17&lt;br /&gt;588     1.627          0.39&lt;br /&gt;1176    7.086          1.57&lt;br /&gt;2352   33.432          6.39&lt;/pre&gt;&lt;br /&gt;今回は、まずは行列作成部分に、できるだけC++で可能なチューニングを施してある。&lt;br /&gt;樹形図作成部分は、あまり最適化していない。&lt;br /&gt;標準のstd::mapとかstd::vectorを使用しており、特別な数値計算用ライブラリなどは一切使っていない。&lt;br /&gt;また、コンパイル時の様々なコンパイルオプションでの最適化もまだ行っていない。&lt;br /&gt;&lt;br /&gt;C++(C)のいい所は、メモリの使い方などをダイレクトに想像しながらチューニングが行える所だろう。&lt;br /&gt;今回も、３重ループの効率化を行うだけで、ここまで処理時間が短くなった。&lt;br /&gt;&lt;br /&gt;しかし、作っていて気づいたのは、最適化を意識しないでC++を書くと、Pythonとたいして変わらない処理時間だったことだ。&lt;br /&gt;その証拠に、上の表での処理時間の短縮分のほとんどは、今回意識して最適化を図った行列作成部分のものである。&lt;br /&gt;&lt;br /&gt;次は、実際の樹形図作成部分がネックになっているので、この部分をより速くしていきたいと思う。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://coderepos.org/share/browser/lang/cplusplus/misc/clustercpp"&gt;今回のソースはcodereposに置いておきました。&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6653250068601074218?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6653250068601074218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6653250068601074218'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/python-c.html' title='Python -&gt; C++への移植でどれぐらい速くなったか'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-7751770486209995185</id><published>2008-05-15T01:00:00.004+09:00</published><updated>2008-05-15T01:13:42.225+09:00</updated><title type='text'>行列×行列さえ一瞬でできれば、文書のクラスタリングも一瞬でできそう</title><content type='html'>Ward法をここ数日試してみて、十分速くなったのだが、ここまでくるといろいろ思う事がある。&lt;br /&gt;&lt;br /&gt;1. 最終的に今ネックになっているのは、一番最初の行列×行列の計算である。&lt;br /&gt;2. その演算であれば、分散処理での高速化が十分研究されている。&lt;br /&gt;3. 最初は樹形図をつくるところがネックかと思っていたが、そうでないのは驚きである。&lt;br /&gt;4. dict使いまくりの富豪プログラミングはアルゴリズムの試作に便利。&lt;br /&gt;&lt;br /&gt;ということで、例えば分散処理で行列×行列を一瞬で計算できるようになれば、直前のエントリのクラスタリングアルゴリズムで1000文書であろうとものの数秒で分類できるということになる。&lt;br /&gt;&lt;br /&gt;このクラスタリングの計算方法をC++で書き直せば、もっともっと速くなるはずで、たとえばweb経由でアクセスがあった瞬間に分類アルゴリズムを走らせることもできるだろう。&lt;br /&gt;&lt;br /&gt;樹形図をどこでちょんぎるかのさじ加減は別途研究の必要があるが。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-7751770486209995185?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7751770486209995185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7751770486209995185'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/blog-post_15.html' title='行列×行列さえ一瞬でできれば、文書のクラスタリングも一瞬でできそう'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8490152499204605453</id><published>2008-05-15T00:11:00.008+09:00</published><updated>2008-05-15T01:20:22.199+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Ward法さらにキャッシュを効かせて高速に</title><content type='html'>さらに昨日の続き。&lt;br /&gt;&lt;br /&gt;行列の各行の最小距離成分をキャッシュするようにしてみた。&lt;br /&gt;この改造によって、昨日O(N**2)でネックとなっていた、距離表からの最小値の探索がほぼO(N)になったことになる。&lt;br /&gt;さらにパフォーマンスは向上し、以下のようになった。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;件数   処理時間(s)    そのうち初期行列作成時間&lt;br /&gt;--------------------------------------------&lt;br /&gt;196     0.677          0.334&lt;br /&gt;392     2.158          1.356&lt;br /&gt;588     4.636          3.073&lt;br /&gt;1176    18.071         12.088&lt;br /&gt;2352    79.09          49.507&lt;/pre&gt;&lt;br /&gt;昨日、おとといに比べると、だいぶ速くなった。例えば昨日は588件の処理に19秒かかっていたのが、今日は4.6秒！&lt;br /&gt;しかし、計算は速くなったものの、今度は実は最初の行列作成に大半の時間を使われていることがわかる。&lt;br /&gt;&lt;br /&gt;ここが速くなれば、あるいは、行列の作成時間を気にしなくていい状況とかであれば、十分使い物になるパフォーマンスになってきた。&lt;br /&gt;C/C++にはとうていかなわないでしょうけど、Pythonでも工夫次第でいろいろがんばれるものだ。&lt;br /&gt;&lt;br /&gt;以下、今日の改造版のソース。&lt;br /&gt;&lt;pre&gt;#!/usr/local/python25/bin/python&lt;br /&gt;# _*_ coding: utf-8 _*_&lt;br /&gt;# Copyright (C)  2007 Ayukawa Hiroshi&lt;br /&gt;import sys&lt;br /&gt;import time&lt;br /&gt;from operator import itemgetter&lt;br /&gt;from collections import defaultdict&lt;br /&gt;from itertools import repeat, groupby&lt;br /&gt;from math import sqrt&lt;br /&gt;&lt;br /&gt;def distmatrix_by_dict(vectors):&lt;br /&gt;    """&lt;br /&gt;    上三角部分のみの距離表を作ります(ベクトルがdict型のsparseベクトルの場合)&lt;br /&gt;    返り値  (距離, ベクトル番号1, ベクトル番号2) の列&lt;br /&gt;    """&lt;br /&gt;    mat = defaultdict(lambda: defaultdict(float))&lt;br /&gt;    for i in range(len(vectors)):&lt;br /&gt;        dist = []&lt;br /&gt;        for j in range(i):&lt;br /&gt;            d = 0.0&lt;br /&gt;            for k in set(vectors[i].keys()) &amp; set(vectors[j].keys()): #ユークリッド距離&lt;br /&gt;                d += (vectors[i].get(k, 0.0) - vectors[j].get(k, 0.0))**2&lt;br /&gt;            dist.append((j, sqrt(d)))&lt;br /&gt;        mat[i] = dafaultdict(float, dist)&lt;br /&gt;    return mat&lt;br /&gt;&lt;br /&gt;def distmatrix_by_list(vectors):&lt;br /&gt;    """&lt;br /&gt;    上三角部分のみの距離表を作ります(ベクトルが通常のリストの場合)&lt;br /&gt;    返り値  (距離, ベクトル番号1, ベクトル番号2) の列&lt;br /&gt;    """&lt;br /&gt;    mat = defaultdict(lambda: defaultdict(float))&lt;br /&gt;    for i in range(1,len(vectors)):&lt;br /&gt;        v = vectors[i]&lt;br /&gt;        dist = []&lt;br /&gt;        for j in range(i):&lt;br /&gt;            dist.append((j, sqrt(sum([(x[0]-x[1])**2 for x in zip(v, vectors[j])])))) #ユークリッド距離&lt;br /&gt;        mat[i] = defaultdict(float, dist)&lt;br /&gt;    return mat&lt;br /&gt;&lt;br /&gt;def _initcache(mat):&lt;br /&gt;    """&lt;br /&gt;    距離表の各行ごとの最小値をキャッシュする配列を初期化します。&lt;br /&gt;    """&lt;br /&gt;    cache = []&lt;br /&gt;    for i in sorted(mat.keys()):&lt;br /&gt;        cache.append((i, min(((v, i, j) for j,v in mat[i].iteritems()))))&lt;br /&gt;    return dict(cache)&lt;br /&gt;&lt;br /&gt;class _Rap:&lt;br /&gt;    """&lt;br /&gt;    パフォーマンス測定用クラス&lt;br /&gt;    """&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.t = 0&lt;br /&gt;    def b(self):&lt;br /&gt;        self.start = time.time()&lt;br /&gt;    def e(self):&lt;br /&gt;        self.t += time.time() - self.start&lt;br /&gt;&lt;br /&gt;def cluster(vectors, distfunc=distmatrix_by_list):&lt;br /&gt;    """&lt;br /&gt;    クラスタリング（ウォード法）&lt;br /&gt;    返り値 クラスタ結合履歴配列&lt;br /&gt;    """&lt;br /&gt;    rap0 = _Rap()&lt;br /&gt;    rap00 = _Rap()&lt;br /&gt;&lt;br /&gt;    #距離表の用意&lt;br /&gt;    rap0.b()&lt;br /&gt;    mat = distfunc(vectors)&lt;br /&gt;    rap0.e()&lt;br /&gt;    &lt;br /&gt;    #距離表の最小値キャッシュを初期化する&lt;br /&gt;    rap00.b()&lt;br /&gt;    cache = _initcache(mat)&lt;br /&gt;    rap00.e()&lt;br /&gt;&lt;br /&gt;    size = len(vectors)    #全体のサイズ&lt;br /&gt;    sizes = list(repeat(1, size)) # 各クラスタのサイズ&lt;br /&gt;&lt;br /&gt;    #ノードを結合した履歴を保存する配列（この列を最終的に返します）&lt;br /&gt;    hist = [dict(&lt;br /&gt;            joined=None, #joined: この回で結合したインデックス&lt;br /&gt;            dist=0.0,     #dist: この回で結合したインデックス間の距離&lt;br /&gt;            newid=None,  #newid: この回で新設されたインデックス&lt;br /&gt;            )]&lt;br /&gt;    rap1 = _Rap()&lt;br /&gt;    rap2 = _Rap()&lt;br /&gt;    nextnodenum = size   #次に使うクラスタ番号&lt;br /&gt;    kieta = set() #消えた行番号の保存用&lt;br /&gt;&lt;br /&gt;    #size-1回繰り返して結合していきます。&lt;br /&gt;    while len(hist) &amp;lt; size:&lt;br /&gt;        #最小距離のものを選ぶ&lt;br /&gt;        rap1.b()&lt;br /&gt;        dist, q, p = min(cache.values())  # p &amp;lt; q&lt;br /&gt;        rap1.e()&lt;br /&gt;&lt;br /&gt;        #消えるもの集合を更新&lt;br /&gt;        kieta.add(p)&lt;br /&gt;        kieta.add(q)&lt;br /&gt;&lt;br /&gt;        #高速化のための事前計算&lt;br /&gt;        pairsize = sizes[p]+sizes[q]&lt;br /&gt;        r = mat[q][p]&lt;br /&gt;        obj = mat[nextnodenum]&lt;br /&gt;        sp = sizes[p]&lt;br /&gt;        sq = sizes[q]&lt;br /&gt;&lt;br /&gt;        #距離の計算しなおし&lt;br /&gt;        rap2.b()&lt;br /&gt;        #キャッシュから、今回消えるものをあらかじめ排除&lt;br /&gt;        if p in cache: cache.pop(p)&lt;br /&gt;        if q in cache: cache.pop(q)&lt;br /&gt;        tmpdist = [] #新ノードからの最小距離を求めるための一時記憶場所&lt;br /&gt;        for i in xrange(nextnodenum):&lt;br /&gt;            if i in kieta: continue #すでに消えているなら何もしない&lt;br /&gt;&lt;br /&gt;            #距離の計算  Ward法&lt;br /&gt;            if i &amp;lt; p:&lt;br /&gt;                obj[i] = ((sp+sizes[i])*mat[p][i]+(sq+sizes[i])*mat[q][i]-sizes[i]*r)/float(pairsize+sizes[i])&lt;br /&gt;            elif p &amp;lt; i and i &amp;lt; q:&lt;br /&gt;                obj[i] = ((sp+sizes[i])*mat[i][p]+(sq+sizes[i])*mat[q][i]-sizes[i]*r)/float(pairsize+sizes[i])&lt;br /&gt;                mat[i].pop(p)  #今後使わなくなる成分の消去&lt;br /&gt;            else:&lt;br /&gt;                obj[i] = ((sp+sizes[i])*mat[i][p]+(sq+sizes[i])*mat[i][q]-sizes[i]*r)/float(pairsize+sizes[i])&lt;br /&gt;                mat[i].pop(p)  #今後使わなくなる成分の消去&lt;br /&gt;                mat[i].pop(q)  #今後使わなくなる成分の消去&lt;br /&gt;&lt;br /&gt;            #キャッシュ更新&lt;br /&gt;            if i in cache:&lt;br /&gt;                if obj[i] &amp;lt; cache[i][0]: #新ノードとi番目の距離がより近い場合はi行目のキャッシュを置き換えます。&lt;br /&gt;                    cache[i] = (obj[i], nextnodenum, i)&lt;br /&gt;                elif mat[i] and (p in cache[i][1:] or q in cache[i][1:]):&lt;br /&gt;                    cache[i] = min(((v, i, j) for j,v in mat[i].iteritems()))&lt;br /&gt;                if not mat[i]: #i行が空になってたら、iのキャッシュは不要。matからもけずる&lt;br /&gt;                    cache.pop(i)&lt;br /&gt;                    mat.pop(i)&lt;br /&gt;            elif not mat[i]: mat.pop(i)&lt;br /&gt;            tmpdist.append((obj[i], i))&lt;br /&gt;        if p in mat: mat.pop(p)  #今後使わなくなる成分の消去&lt;br /&gt;        if q in mat: mat.pop(q)  #今後使わなくなる成分の消去&lt;br /&gt;&lt;br /&gt;        #新ノードからの最小距離をキャッシュに記録&lt;br /&gt;        if tmpdist:&lt;br /&gt;            mindist = min(tmpdist)&lt;br /&gt;            cache[nextnodenum] = (mindist[0], nextnodenum, mindist[1])&lt;br /&gt;&lt;br /&gt;        sizes.append(pairsize)  #新クラスタのサイズデータを格納&lt;br /&gt;        rap2.e()&lt;br /&gt;        #履歴情報に今回の結合結果を格納&lt;br /&gt;        hist.append(dict(&lt;br /&gt;                joined=(p,q),  &lt;br /&gt;                dist=dist,&lt;br /&gt;                newid=nextnodenum,&lt;br /&gt;                ))&lt;br /&gt;        nextnodenum += 1 #次のクラスタID    &lt;br /&gt;&lt;br /&gt;    print "rap0", rap0.t&lt;br /&gt;    print "rap00", rap00.t&lt;br /&gt;    print "rap1", rap1.t&lt;br /&gt;    print "rap2", rap2.t&lt;br /&gt;    &lt;br /&gt;    return hist&lt;br /&gt;&lt;br /&gt;def main(nottest=False):&lt;br /&gt;    """&lt;br /&gt;    引数  nottest  パフォーマンステスト用フラグ Falseの場合はテストのために、結果出力しません。&lt;br /&gt;    """&lt;br /&gt;    ids = []     # データラベル格納用&lt;br /&gt;    vectors = [] # ベクトル格納用&lt;br /&gt;    for line in sys.stdin:  #標準入力からベクトルを読む&lt;br /&gt;        data = line.strip().split("\t")&lt;br /&gt;        ids.append(data[0])&lt;br /&gt;        vectors.append(map(float, data[1:]))&lt;br /&gt;&lt;br /&gt;    #クラスタリング実行&lt;br /&gt;    hist = cluster(vectors)            &lt;br /&gt;&lt;br /&gt;    if nottest:  #出力処理&lt;br /&gt;        for c, h in enumerate(hist):&lt;br /&gt;            j = h["joined"]&lt;br /&gt;            if not j: continue&lt;br /&gt;            i = "(%s+%s)" % (ids[j[0]], ids[j[1]])&lt;br /&gt;            ids.append(i)&lt;br /&gt;            print c, ":", h["dist"], ":", i&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;   import optparse&lt;br /&gt;   &lt;br /&gt;   parser = optparse.OptionParser(u"""&lt;br /&gt;   Ward法によるクラスタリング。&lt;br /&gt;   """)&lt;br /&gt;   parser.add_option("-t", "--test", dest="test", help=u"パフォーマンステスト実行", default=False, action="store_true")&lt;br /&gt;   (options, args) = parser.parse_args()&lt;br /&gt;&lt;br /&gt;   if options.test:&lt;br /&gt;       #パフォーマンステスト&lt;br /&gt;       import hotshot, hotshot.stats&lt;br /&gt;       prof = hotshot.Profile("cluster.prof")&lt;br /&gt;       prof.runcall(main)&lt;br /&gt;       prof.close()&lt;br /&gt;       stats = hotshot.stats.load("cluster.prof")&lt;br /&gt;       stats.strip_dirs()&lt;br /&gt;       stats.sort_stats('time', 'calls')&lt;br /&gt;       stats.print_stats(20)&lt;br /&gt;   else:&lt;br /&gt;       #通常実行&lt;br /&gt;       main(True)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8490152499204605453?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8490152499204605453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8490152499204605453'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/ward_15.html' title='Ward法さらにキャッシュを効かせて高速に'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-9148641777194481206</id><published>2008-05-14T02:03:00.004+09:00</published><updated>2008-05-14T02:35:00.223+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Ward法再実装で少し速くなった</title><content type='html'>&lt;a href="http://hiroshiykw.blogspot.com/2008/05/pythonward.html"&gt;PythonでWard法によるクラスタリング&lt;/a&gt;&lt;br /&gt;&lt;a href="http://hiroshiykw.blogspot.com/2008/05/ward.html"&gt;Ward法のパフォーマンスと分散処理のための考察&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;このシリーズの続き。&lt;br /&gt;プログラムを書き直し、真っ当な行列的データを用意したところ、ずいぶん速くなり、588件でも19秒程度となった。（1100件でも2分程度なので、ずいぶんと自分が想定している実用化に近づいたと思う。）&lt;br /&gt;&lt;br /&gt;しかし、真っ当な行列データにすると、今度は最小距離の探索に９割の時間を取られるようになったため、ここを改造すべきと強く思う。&lt;br /&gt;&lt;br /&gt;ここまでくれば、常に行列の成分のソート情報をなんらか記憶しておけばいいように思うのだが、そのソート情報の維持にはまたコストがかかるというジレンマ。&lt;br /&gt;&lt;br /&gt;今は可変長の行列として、pythonのdefaultdict(lambda: defaultdict(float))を使っている。これで定義した簡易行列クラスは非常に便利なのでそんなにシビアでない計算の目的にはよく使っている。可変長＆メモリ節約というのがとくにすばらしい。&lt;br /&gt;&lt;br /&gt;これがC++であったらどうするべきであろうか。&lt;br /&gt;こうした細かい計算アルゴリズムの王道としては最初から使用するメモリをまとめて最小限確保しておき、その上でメモリを上書きしながら計算して行くべきか。&lt;br /&gt;それとも今回のPythonでの実装にならってSTLを使って map&amp;lt;size_t, map&amp;lt;size_t, double&gt;*&gt;* などとするべきか。ああ、こういう場合shared_ptrにするべきなんだっけ、、、。ここはいつも覚えてないので参考書を読み直さなくては。&lt;br /&gt;はたまたboostになんかいいのないかと見ていたら、&lt;a href="http://www.kmonos.net/alang/boost/iterator.html"&gt;いつの間にかboostのコンテナ系が増えている！&lt;/a&gt;調査しなければ。&lt;br /&gt;うーん、前途多難。&lt;br /&gt;&lt;br /&gt;以下、今日の改造版。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#!/usr/local/python25/bin/python&lt;br /&gt;# _*_ coding: utf-8 _*_&lt;br /&gt;# Copyright (C)  2007 Ayukawa Hiroshi&lt;br /&gt;import sys&lt;br /&gt;import time&lt;br /&gt;from operator import itemgetter&lt;br /&gt;from collections import defaultdict&lt;br /&gt;from itertools import repeat, groupby&lt;br /&gt;from math import sqrt&lt;br /&gt;&lt;br /&gt;def distmatrix_by_dict(vectors):&lt;br /&gt;    """&lt;br /&gt;    上三角部分のみの距離表を作ります(ベクトルがdict型のsparseベクトルの場合)&lt;br /&gt;    返り値  (距離, ベクトル番号1, ベクトル番号2) の列&lt;br /&gt;    """&lt;br /&gt;    for i in xrange(len(vectors)):&lt;br /&gt;        for j in xrange(i):&lt;br /&gt;            dist = 0.0&lt;br /&gt;            for k in set(vectors[i].keys()) &amp; set(vectors[j].keys()): #ユークリッド距離&lt;br /&gt;                dist += (vectors[i].get(k, 0.0) - vectors[j].get(k, 0.0))**2&lt;br /&gt;            yield (sqrt(dist), i, j)&lt;br /&gt;&lt;br /&gt;def distmatrix_by_list(vectors):&lt;br /&gt;    """&lt;br /&gt;    上三角部分のみの距離表を作ります(ベクトルが通常のリストの場合)&lt;br /&gt;    返り値  (距離, ベクトル番号1, ベクトル番号2) の列&lt;br /&gt;    """&lt;br /&gt;    for i in xrange(len(vectors)):&lt;br /&gt;        for j in xrange(i):&lt;br /&gt;            dist = sum([(x[0]-x[1])**2 for x in zip(vectors[i], vectors[j])]) #ユークリッド距離&lt;br /&gt;            yield (sqrt(dist), i, j)&lt;br /&gt;&lt;br /&gt;def minmatrix(mat, size):    &lt;br /&gt;    d = min((min(((v, j) for j,v in mat[i].iteritems())), i) for i in mat.iterkeys() if mat[i])&lt;br /&gt;    return (d[0][0], d[1], d[0][1])&lt;br /&gt;&lt;br /&gt;def cluster(vectors, distfunc=distmatrix_by_list):&lt;br /&gt;    """&lt;br /&gt;    クラスタリング（ウォード法）&lt;br /&gt;    返り値 クラスタ結合履歴配列&lt;br /&gt;    """&lt;br /&gt;    #距離表の用意&lt;br /&gt;    mat = defaultdict(lambda : defaultdict(float))&lt;br /&gt;    for d in distfunc(vectors):&lt;br /&gt;        mat[d[1]][d[2]] = d[0]        &lt;br /&gt;&lt;br /&gt;    size = len(vectors)    #全体のサイズ&lt;br /&gt;    sizes = list(repeat(1, size)) # 各クラスタのサイズ&lt;br /&gt;&lt;br /&gt;    #ノードを結合した履歴を保存する配列（この列を最終的に返します）&lt;br /&gt;    hist = [dict(&lt;br /&gt;            joined=None, #joined: この回で結合したインデックス&lt;br /&gt;            dist=0.0,     #dist: この回で結合したインデックス間の距離&lt;br /&gt;     newid=None,  #newid: この回で新設されたインデックス&lt;br /&gt;            )]&lt;br /&gt;&lt;br /&gt;    class Rap:&lt;br /&gt;        def __init__(self):&lt;br /&gt;            self.t = 0&lt;br /&gt;        def b(self):&lt;br /&gt;            self.start = time.time()&lt;br /&gt;        def e(self):&lt;br /&gt;            self.t += time.time() - self.start&lt;br /&gt;    rap1 = Rap()&lt;br /&gt;    rap2 = Rap()&lt;br /&gt;    nextnodenum = size   #次に使うクラスタ番号&lt;br /&gt;    #size-1回繰り返して結合していきます。&lt;br /&gt;    kieta = set()&lt;br /&gt;    while len(hist) &amp;lt; size:&lt;br /&gt;        #最小距離のものを選ぶ&lt;br /&gt;        rap1.b()&lt;br /&gt;        dist, q, p = minmatrix(mat, nextnodenum)  # p &amp;lt; q&lt;br /&gt;        rap1.e()&lt;br /&gt;&lt;br /&gt;        #消えるもの集合を更新&lt;br /&gt;        kieta.add(p)&lt;br /&gt;        kieta.add(q)&lt;br /&gt;&lt;br /&gt;        #高速化のための事前計算&lt;br /&gt;        pairsize = sizes[p]+sizes[q]&lt;br /&gt;        r = mat[q][p]&lt;br /&gt;        obj = mat[nextnodenum]&lt;br /&gt;        sp = sizes[p]&lt;br /&gt;        sq = sizes[q]&lt;br /&gt;&lt;br /&gt;        #距離の計算しなおし&lt;br /&gt;        rap2.b()&lt;br /&gt;        for i in xrange(nextnodenum):&lt;br /&gt;            if i in kieta: continue #すでに消えているなら何もしない&lt;br /&gt;&lt;br /&gt;            #距離の計算  Ward法&lt;br /&gt;            if i &amp;lt; p:&lt;br /&gt;                obj[i] = ((sp+sizes[i])*mat[p][i]+(sq+sizes[i])*mat[q][i]-sizes[i]*r)/float(pairsize+sizes[i])&lt;br /&gt;            elif p &amp;lt; i and i &amp;lt; q:&lt;br /&gt;                obj[i] = ((sp+sizes[i])*mat[i][p]+(sq+sizes[i])*mat[q][i]-sizes[i]*r)/float(pairsize+sizes[i])&lt;br /&gt;                mat[i].pop(p)  #今後使わなくなる成分の消去&lt;br /&gt;            else:&lt;br /&gt;                obj[i] = ((sp+sizes[i])*mat[i][p]+(sq+sizes[i])*mat[i][q]-sizes[i]*r)/float(pairsize+sizes[i])&lt;br /&gt;                mat[i].pop(p)  #今後使わなくなる成分の消去&lt;br /&gt;                mat[i].pop(q)  #今後使わなくなる成分の消去&lt;br /&gt;        if p in mat: mat.pop(p)  #今後使わなくなる成分の消去&lt;br /&gt;        if q in mat: mat.pop(q)  #今後使わなくなる成分の消去&lt;br /&gt;        sizes.append(pairsize)  #新クラスタのサイズデータを格納&lt;br /&gt;        rap2.e()&lt;br /&gt;        #履歴情報に今回の結合結果を格納&lt;br /&gt;        hist.append(dict(&lt;br /&gt;                joined=(p,q),  &lt;br /&gt;                dist=dist,&lt;br /&gt;                newid=nextnodenum,&lt;br /&gt;                ))&lt;br /&gt;        nextnodenum += 1 #次のクラスタID    &lt;br /&gt;    print "rap1", rap1.t&lt;br /&gt;    print "rap2", rap2.t&lt;br /&gt;    &lt;br /&gt;    return hist&lt;br /&gt;&lt;br /&gt;def main(nottest=False):&lt;br /&gt;    """&lt;br /&gt;    引数  nottest  パフォーマンステスト用フラグ Falseの場合はテストのために、結果出力しません。&lt;br /&gt;    """&lt;br /&gt;    ids = []     # データラベル格納用&lt;br /&gt;    vectors = [] # ベクトル格納用&lt;br /&gt;    for line in sys.stdin:  #標準入力からベクトルを読む&lt;br /&gt;        data = line.strip().split("\t")&lt;br /&gt;        ids.append(data[0])&lt;br /&gt;        vectors.append(map(float, data[1:]))&lt;br /&gt;&lt;br /&gt;    #クラスタリング実行&lt;br /&gt;    hist = cluster(vectors)            &lt;br /&gt;&lt;br /&gt;    if nottest:  #出力処理&lt;br /&gt;        for c, h in enumerate(hist):&lt;br /&gt;            j = h["joined"]&lt;br /&gt;            if not j: continue&lt;br /&gt;            i = "(%s+%s)" % (ids[j[0]], ids[j[1]])&lt;br /&gt;            ids.append(i)&lt;br /&gt;            print c, ":", h["dist"], ":", i&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;   import optparse&lt;br /&gt;   &lt;br /&gt;   parser = optparse.OptionParser(u"""&lt;br /&gt;   Ward法によるクラスタリング。&lt;br /&gt;   """)&lt;br /&gt;   parser.add_option("-t", "--test", dest="test", help=u"パフォーマンステスト実行", default=False, action="store_true")&lt;br /&gt;   (options, args) = parser.parse_args()&lt;br /&gt;&lt;br /&gt;   if options.test:&lt;br /&gt;       #パフォーマンステスト&lt;br /&gt;       import hotshot, hotshot.stats&lt;br /&gt;       prof = hotshot.Profile("cluster.prof")&lt;br /&gt;       prof.runcall(main)&lt;br /&gt;       prof.close()&lt;br /&gt;       stats = hotshot.stats.load("cluster.prof")&lt;br /&gt;       stats.strip_dirs()&lt;br /&gt;       stats.sort_stats('time', 'calls')&lt;br /&gt;       stats.print_stats(20)&lt;br /&gt;   else:&lt;br /&gt;       #通常実行&lt;br /&gt;       main(True)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-9148641777194481206?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/9148641777194481206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/9148641777194481206'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/ward_14.html' title='Ward法再実装で少し速くなった'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3891204319680044344</id><published>2008-05-13T01:23:00.005+09:00</published><updated>2008-05-13T01:37:17.577+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>2ちゃんねる Pythonのお勉強 Part26よりParallel Python関係の議論抜粋</title><content type='html'>&lt;a href="http://pc11.2ch.net/test/read.cgi/tech/1209480428/201-300"&gt;Pythonのお勉強 Part26&lt;/a&gt;&lt;br /&gt;からの抜粋。なんともタイムリーなことに、Parallel Pythonが話題になっている。&lt;br /&gt;この議論で288が指摘している事は、やはり的を得ているのではないだろうか。&lt;br /&gt;Python-&gt;C/C++という移植で10倍速くなるなんてことは珍しくない。&lt;br /&gt;（例えば、C++からMecabを利用した時の速度は驚異的ですらあるが、Pythonから利用した場合はちょっとのんびりとしたものになってしまう。）&lt;br /&gt;numpyがうまくハマっているPythonスクリプトとかなら別ですけど。&lt;br /&gt;&lt;br /&gt;で、以下その議論抜粋です。。。。&lt;br /&gt;---------------------&lt;br /&gt;&lt;pre&gt;169 ：デフォルトの名無しさん：2008/05/06(火) 21:31:30&lt;br /&gt;    threadって計算速度の向上に効果ある？&lt;br /&gt;    a = b1 + b2の計算を（a,b1,b2はarray）&lt;br /&gt;    b1とb2をthreadで計算して，&lt;br /&gt;    それぞれ計算終了後に足すというプログラムを作ったんだけど，&lt;br /&gt;    普通にb1とb2をメインスレッドで順番に求めて足した方が早かった．．．&lt;br /&gt;&lt;br /&gt;    ちなみにb1とb2の計算はダミーのforループ10000回です． &lt;br /&gt;&lt;br /&gt;244 ：デフォルトの名無しさん：2008/05/10(土) 04:27:34&lt;br /&gt;    &gt;&gt;169&lt;br /&gt;    Parallel Python というパッケージがあるのを知ったので参考までに紹介しとく。&lt;br /&gt;    http://www.parallelpython.com/&lt;br /&gt;    スレッドじゃなく複数プロセスで並列実行する仕組みらしい。&lt;br /&gt;    Python のみで実装されていて非常にシンプルなパッケージ構成になっている。&lt;br /&gt;    マルチコア環境の場合はスレッドモジュール風に使える。&lt;br /&gt;    クラスタ環境では各ノードで計算サーバ（ppserver.py）をしておく仕組みになっている。&lt;br /&gt;    応用プログラムはどちらの環境でも同じにできるっぽい。&lt;br /&gt;&lt;br /&gt;    手元の共有メモリマシンで付属サンプル（sum_primes.py）を実行したら下のようになった。&lt;br /&gt;    素数の和を計算するプログラムなのでプロセス間通信はほとんどないけど、&lt;br /&gt;    並列化のオーバヘッドはあるわけで、なかなか良好な結果だと思う。&lt;br /&gt;&lt;br /&gt;    並列度，実行時間（秒），速度向上率&lt;br /&gt;    1，　　17.54，　　1.000&lt;br /&gt;    2，　　8.781，　　1.998&lt;br /&gt;    4，　　4.424，　　3.965&lt;br /&gt;    8，　　2.261，　　7.759 &lt;br /&gt;&lt;br /&gt;245 ：169：2008/05/10(土) 13:53:14&lt;br /&gt;    &gt;&gt;244&lt;br /&gt;    おおお，サンクス！&lt;br /&gt;    早速いじってみまふ。 &lt;br /&gt;&lt;br /&gt;280 ：244：2008/05/10(土) 23:51:28&lt;br /&gt;    引続き Parallel Python をいじってみたんだけども、このシステムはマスタワーカモデルを前提にしているみたいだ。&lt;br /&gt;    つまり、マスタが仕事の集合を持っていて、有限個のワーカに1つずつ仕事を割り当てる。仕事を終えたワーカは&lt;br /&gt;    マスタから新しい仕事をもらって処理する。これを仕事の集合が空になるまで続ける。&lt;br /&gt;&lt;br /&gt;    ワーカ間で通信をする機能は提供されていないし、特定のワーカ（たとえば特定のリモートホスト上のppserver.py）に&lt;br /&gt;    特定の仕事を割り当てることもできないっぽい。Parallel Python が有効かどうかは実現したい並列アルゴリズムが&lt;br /&gt;    マスタワーカモデルに適合するかどうかに依る希ガス。 &lt;br /&gt;&lt;br /&gt;283 ：デフォルトの名無しさん：2008/05/11(日) 00:40:31&lt;br /&gt;    &gt;&gt;280&lt;br /&gt;    具体的には、どういう用途に使えそうなんですか？ &lt;br /&gt;&lt;br /&gt;285 ：デフォルトの名無しさん：2008/05/11(日) 01:34:00&lt;br /&gt;    &gt;&gt;283&lt;br /&gt;    最も適しているのは並列処理の分野で embarrassingly parallel と呼ばれるカテゴリに属する種々の計算、&lt;br /&gt;    すなわち入力データを複数の独立した部分に分割できて、各部分について他から独立して計算が行なえる&lt;br /&gt;    タイプの用途に適している。&lt;br /&gt;    http://en.wikipedia.org/wiki/Embarrassingly_parallel&lt;br /&gt;    Wikipediaに例があがっている。フラクタル計算とか3DCGのレンダリング（例：レイトレーシング）とか力任せの&lt;br /&gt;    暗号解読とか色々ある。&lt;br /&gt;&lt;br /&gt;    並列処理って概して複雑で長時間計算し続ける必要のある応用が多い。そういう応用には C とか Fortran を&lt;br /&gt;    使うことがほとんどなんだけど、きちんと動くようになるまでの開発時間が長くてデバッグがたいへんだったりする。&lt;br /&gt;    そういう並列プログラムの試作（プロトタイピング）に Python が使えたらいいなーと個人的には思っている。&lt;br /&gt;&lt;br /&gt;288 ：デフォルトの名無しさん：2008/05/11(日) 09:43:58&lt;br /&gt;    &gt;&gt;285&lt;br /&gt;    PythonでCPU8個使って並列計算するよりCで書いたプログラムの方が速そうだったり。。。&lt;br /&gt;&lt;br /&gt;289 ：デフォルトの名無しさん：2008/05/11(日) 09:57:09&lt;br /&gt;    &gt;&gt;288&lt;br /&gt;    何言ってんだ？&lt;br /&gt;&lt;br /&gt;290 ：デフォルトの名無しさん：2008/05/11(日) 10:28:52&lt;br /&gt;    &gt;&gt;289&lt;br /&gt;    あ？ヤンのかコラ &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;295 ：デフォルトの名無しさん：2008/05/11(日) 14:39:25&lt;br /&gt;    &gt;&gt;285&lt;br /&gt;    自分も並列化するときのプロトタイプとしてPythonの並列環境を使ってみたいと&lt;br /&gt;    考えているんだけれど、今のところプロトタイプとしての感触はどう？&lt;br /&gt;&lt;br /&gt;    データ分割の楽な問題ってCとかFORTRANでもOpenMPを注意深く使うだけでも早くなる事が&lt;br /&gt;    多いし、MPIでも慣れれば苦労せずに書けるけれど、そうでない、スレーブ間での通信が必要&lt;br /&gt;    とかうまく分割できないとかそういう問題はMPIでやろうとするとデバッグが(；ﾟдﾟ)&lt;br /&gt;    なことになりがちで、そういう用途にPythonのプロトタイプが役に立つなら素晴らしいと思う&lt;br /&gt;    実はC並列版とそれほど速度とメモリ使用量が変わらないとかなら最高&lt;br /&gt;    C並列版より速ければ神&lt;br /&gt;&lt;br /&gt;296 ：デフォルトの名無しさん：2008/05/11(日) 16:53:12&lt;br /&gt;    Parallel Python だけど pp.Server.__scheduler() を適当に書き直せばワーカと仕事の対応（割り当て）を&lt;br /&gt;    ユーザ側で決められそうな希ガス。問題はワーカ間のプロセス間通信。これが一番面倒なところなんで&lt;br /&gt;    自前で実装となると Parallel Python を使ううまみがほとんどない・・・。&lt;br /&gt;&lt;br /&gt;    やっぱ MPI の Python バインディングあたりが一番現実的な解かなー。でもなんか気が重いんだなー。&lt;br /&gt;    もっと Python らしく lightweight なソリューションがないかなー。&lt;br /&gt;&lt;br /&gt;    &gt;&gt;288&lt;br /&gt;    Python の並列プログラムより C の逐次プログラムの方が速そうってことだよね。&lt;br /&gt;    そういうことは十分（多分頻繁に）あると思われ。&lt;br /&gt;&lt;br /&gt;    &gt;&gt;295&lt;br /&gt;    残念ながらまだ並列プログラムのプロトタイプ用途には使えてなくて感触を得るところまでいってない。&lt;br /&gt;    理由は単純で、Python で手軽に並列プログラミングを実現できる道具を見つけられていないから。&lt;br /&gt;    &gt;&gt;209に書いたようにいろいろ試してるんだけどなかなか・・・。&lt;br /&gt;&lt;br /&gt;    ただ、個人的には Python を並列化のプロトタイピングに使うのは大いに有望だと思っている。&lt;br /&gt;    プロトタイピングの場合、欲しいのは並列度やデータ量を上げたときの実行時間の変化であって、&lt;br /&gt;    実行速度が多少遅くて実験に時間がかかるとしても知りたいことは分かるはずだから。&lt;br /&gt;    プロセス間通信にソケットを使うとすると、データ量が大きくなれば Python でも C 等と同じぐらいの&lt;br /&gt;    速度が出る（ハズ）。演算量が多い部分に numpy 等の C/Fortran で書かれた数値カーネルを使うことに&lt;br /&gt;    すれば、プロトタイピング用途には十分な速度とメモリ使用量が得られるのではと思う。 &lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3891204319680044344?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3891204319680044344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3891204319680044344'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/2-python-part26parallel-python.html' title='2ちゃんねる Pythonのお勉強 Part26よりParallel Python関係の議論抜粋'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-2008698532162402825</id><published>2008-05-13T00:01:00.002+09:00</published><updated>2008-05-13T00:06:34.724+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Ward法のパフォーマンスと分散処理のための考察</title><content type='html'>昨日実装したWard法の処理だが、200件程度なら２秒で終わるが、詳しく調べると、400件で10秒、700件で60秒と、O(n**2)どころか、「もしかしてO(2^n)？！」ぐらいのできであった(T_T)。。。&lt;br /&gt;&lt;br /&gt;その99%は距離計算直し対象の発見と選り分けの部分であり、本来のWard法の距離計算の部分は微々たるもの。&lt;br /&gt;&lt;br /&gt;今後はこの選り分け対象の部分でちゃんとインデックスの効いた選り分けができるように変更すべきか。&lt;br /&gt;&lt;br /&gt;やはり、まずは王道に従って、きちんとした行列データとして距離を持つべきだろう。&lt;br /&gt;&lt;br /&gt;作り直しだ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-2008698532162402825?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2008698532162402825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2008698532162402825'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/ward.html' title='Ward法のパフォーマンスと分散処理のための考察'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3331609716496737669</id><published>2008-05-12T04:29:00.007+09:00</published><updated>2008-05-12T05:05:26.524+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>PythonでWard法によるクラスタリング</title><content type='html'>Pythonで、Ward法によるクラスタリング（デンドログラム作成まで）を実装してみた。&lt;br /&gt;参考にしたのは、岡山大学が公開している&lt;a href="http://case.f7.ems.okayama-u.ac.jp/statedu/hbw2-book/node124.html"&gt;この資料&lt;/a&gt;。&lt;br /&gt;（岡山大学の先生ありがとう！）&lt;br /&gt;&lt;br /&gt;今回こんな車輪の再発明をしたのは、距離表と呼ばれる行列データを行列のイメージで保存せず、&lt;br /&gt;&lt;pre&gt;[(ベクトル1とベクトル2の距離, ベクトル番号1, ベクトル番号2), ...]&lt;/pre&gt;&lt;br /&gt;という形式のリストにして、距離でソートしておき、そのソート結果を維持したままこのリストを分割、更新していくという方針で作ったらどうかと思ったからです。&lt;br /&gt;&lt;br /&gt;196個の19次元の非スパースなデータのデンドログラム作成に2.5秒だからなかなかのパフォーマンスではないだろうか。&lt;br /&gt;CもC++もNumpy系の数値計算ライブラリも使わないでこれだから、いいですねえ。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;使い方&lt;/b&gt;&lt;br /&gt;読み込むデータファイルをタブ区切りで用意する。&lt;br /&gt;1カラム目はデータの識別用ID文字列、2カラム目以降にベクトルの数値データを記入。&lt;br /&gt;あとはそのデータを標準入力から流し込むだけ。&lt;br /&gt;&lt;b&gt;例&lt;/b&gt;&lt;br /&gt;以下のsample.txtを用意する。&lt;br /&gt;&lt;pre&gt;A 1.0 1.1 0.2&lt;br /&gt;B 1.1 0.5 0.3&lt;br /&gt;C 3.1 0.5 0.2&lt;br /&gt;D 4.0 1.1 1.2&lt;/pre&gt;&lt;br /&gt;以下を実行&lt;br /&gt;&lt;pre&gt;ayu@~/work/cluster% ./cluster.py &lt; sample.txt &lt;br /&gt;1 : (B+A)&lt;br /&gt;2 : (D+C)&lt;br /&gt;3 : ((D+C)+(B+A))&lt;/pre&gt;&lt;br /&gt;最初にBとAを結合し、次にDとCを結合し、最後に(D+C)と(B+A)を結合していることが分かる。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ソースcluster.py&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;#!/usr/local/Python25/bin/python&lt;br /&gt;# _*_ coding: utf-8 _*_&lt;br /&gt;# Copyright (C)  2007 Ayukawa Hiroshi&lt;br /&gt;import sys&lt;br /&gt;from collections import defaultdict&lt;br /&gt;from itertools import repeat, groupby&lt;br /&gt;from math import sqrt&lt;br /&gt;&lt;br /&gt;def distmatrix_by_dict(vectors):&lt;br /&gt;    """&lt;br /&gt;    上三角部分のみの距離表を作ります(ベクトルがdict型のsparseベクトルの場合)&lt;br /&gt;    返り値  (距離, ベクトル番号1, ベクトル番号2) の列&lt;br /&gt;    """&lt;br /&gt;    for i in xrange(len(vectors)):&lt;br /&gt;        for j in xrange(i):&lt;br /&gt;            dist = 0.0&lt;br /&gt;            for k in set(vectors[i].keys()) &amp; set(vectors[j].keys()): #ユークリッド距離&lt;br /&gt;                dist += (vectors[i].get(k, 0.0) - vectors[j].get(k, 0.0))**2&lt;br /&gt;            yield (sqrt(dist), i, j)&lt;br /&gt;&lt;br /&gt;def distmatrix_by_list(vectors):&lt;br /&gt;    """&lt;br /&gt;    上三角部分のみの距離表を作ります(ベクトルが通常のリストの場合)&lt;br /&gt;    返り値  (距離, ベクトル番号1, ベクトル番号2) の列&lt;br /&gt;    """&lt;br /&gt;    for i in xrange(len(vectors)):&lt;br /&gt;        for j in xrange(i):&lt;br /&gt;            dist = sum([(x[0]-x[1])**2 for x in zip(vectors[i], vectors[j])]) #ユークリッド距離&lt;br /&gt;            yield (sqrt(dist), i, j)&lt;br /&gt;&lt;br /&gt;def cluster(vectors, distfunc=distmatrix_by_list):&lt;br /&gt;    """&lt;br /&gt;    クラスタリング（ウォード法）&lt;br /&gt;    返り値 クラスタ結合履歴配列&lt;br /&gt;    """&lt;br /&gt;    #距離表の用意&lt;br /&gt;    data = list(distfunc(vectors))&lt;br /&gt;    data.sort()&lt;br /&gt;&lt;br /&gt;    size = len(vectors)    #全体のサイズ&lt;br /&gt;    sizes = list(repeat(1, size)) # 各クラスタのサイズ&lt;br /&gt;&lt;br /&gt;    #ノードを結合した履歴を保存する配列（この列を最終的に返します）&lt;br /&gt;    hist = [dict(&lt;br /&gt;            data=data,   #data: まだ結合されていない成分一覧(常に距離でソート済みの状態で格納)&lt;br /&gt;            joined=None, #joined: この回で結合したインデックス&lt;br /&gt;            dist=0.0     #dist: この回で結合したインデックス間の距離&lt;br /&gt;            )]&lt;br /&gt;&lt;br /&gt;    nextnodenum = size   #次に使うクラスタ番号&lt;br /&gt;&lt;br /&gt;    #size-1回繰り返して結合していきます。&lt;br /&gt;    while len(hist) &amp;lt; size:&lt;br /&gt;        #最小距離のものを選ぶ&lt;br /&gt;        firstpair = min([h["data"][0] for h in hist if h["data"]])&lt;br /&gt;        #最小距離のもののインデックスペア&lt;br /&gt;        pairindex = set(firstpair[1:])&lt;br /&gt;&lt;br /&gt;        movedata = []  #新クラスタ形成のために計算し直し対象とするもの格納用&lt;br /&gt;        for h in hist: #履歴をさかのぼって、計算しなおしとそうでないものに分ける。&lt;br /&gt;            newdata = [] #計算しなおさない居残り組格納用&lt;br /&gt;            for d in h["data"]:&lt;br /&gt;                if d == firstpair:  #今回結合対象のものは除外&lt;br /&gt;                    continue&lt;br /&gt;                intersect = set(d[1:]) &amp; pairindex&lt;br /&gt;                if intersect:  #今回結合対象とインデックスがかぶるなら、計算しなおし対象へ&lt;br /&gt;                    movedata.append(d)&lt;br /&gt;                else:  #そうでないなら居残り組&lt;br /&gt;                    newdata.append(d)&lt;br /&gt;            h["data"] = newdata  #居残り組に更新&lt;br /&gt;&lt;br /&gt;        newdata = []  #計算しなおしデータ格納用&lt;br /&gt;&lt;br /&gt;        dpq, p, q = firstpair  #改めて今回の結合ペアをp,qなどと名付ける&lt;br /&gt;        #計算し直しデータを点ごとにグループ化。この点ごとに新距離を計算しなおします。&lt;br /&gt;        movedata = groupby(sorted((((set(x[1:])-pairindex).pop(), x) for x in movedata)), key=lambda x: x[0])&lt;br /&gt;        for r, d in movedata:&lt;br /&gt;            newdist = 0.0 #新距離計算用&lt;br /&gt;            for w in d:  #ward法計算式にしたがって計算&lt;br /&gt;                w = w[1]&lt;br /&gt;                newdist += (sizes[w[1]]+sizes[w[2]])*w[0]&lt;br /&gt;            newdist = (newdist-sizes[r] * dpq) / float(sizes[r]+sizes[p]+sizes[q])&lt;br /&gt;            newdata.append((newdist, nextnodenum, r)) #新距離を格納&lt;br /&gt;        newdata.sort()  #距離データは常にソートして整理整頓&lt;br /&gt;        sizes.append(sizes[p]+sizes[q])  #新クラスタのサイズデータを格納&lt;br /&gt;        nextnodenum += 1 #次のクラスタID&lt;br /&gt;        #履歴情報に今回の結合結果を格納&lt;br /&gt;        hist.append(dict(&lt;br /&gt;                data=newdata,&lt;br /&gt;                joined=(p,q),  &lt;br /&gt;                dist=firstpair[0]&lt;br /&gt;                ))&lt;br /&gt;    return hist&lt;br /&gt;&lt;br /&gt;def main(nottest=False):&lt;br /&gt;    """&lt;br /&gt;    引数  nottest  パフォーマンステスト用フラグ Falseの場合はテストのために、結果出力しません。&lt;br /&gt;    """&lt;br /&gt;    ids = []     # データラベル格納用&lt;br /&gt;    vectors = [] # ベクトル格納用&lt;br /&gt;    for line in sys.stdin:  #標準入力からベクトルを読む&lt;br /&gt;        data = line.strip().split("\t")&lt;br /&gt;        ids.append(data[0])&lt;br /&gt;        vectors.append(map(float, data[1:]))&lt;br /&gt;&lt;br /&gt;    #クラスタリング実行&lt;br /&gt;    hist = cluster(vectors)            &lt;br /&gt;&lt;br /&gt;    if nottest:  #出力処理&lt;br /&gt;        for c, h in enumerate(hist):&lt;br /&gt;            j = h["joined"]&lt;br /&gt;            if not j: continue&lt;br /&gt;            i = "(%s+%s)" % (ids[j[0]], ids[j[1]])&lt;br /&gt;            ids.append(i)&lt;br /&gt;            print c, ":", i&lt;br /&gt;        &lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;   import optparse&lt;br /&gt;   &lt;br /&gt;   parser = optparse.OptionParser(u"""&lt;br /&gt;   Ward法によるクラスタリング。&lt;br /&gt;   """)&lt;br /&gt;   parser.add_option("-t", "--test", dest="test", help=u"パフォーマンステスト実行", default=False, action="store_true")&lt;br /&gt;   (options, args) = parser.parse_args()&lt;br /&gt;&lt;br /&gt;   if options.test:&lt;br /&gt;       #パフォーマンステスト&lt;br /&gt;       import hotshot, hotshot.stats&lt;br /&gt;       prof = hotshot.Profile("cluster.prof")&lt;br /&gt;       prof.runcall(main)&lt;br /&gt;       prof.close()&lt;br /&gt;       stats = hotshot.stats.load("cluster.prof")&lt;br /&gt;       stats.strip_dirs()&lt;br /&gt;       stats.sort_stats('time', 'calls')&lt;br /&gt;       stats.print_stats(20)&lt;br /&gt;   else:&lt;br /&gt;       #通常実行&lt;br /&gt;       main(True)&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3331609716496737669?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3331609716496737669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3331609716496737669'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/pythonward.html' title='PythonでWard法によるクラスタリング'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6593090616410107991</id><published>2008-05-11T15:02:00.007+09:00</published><updated>2008-05-11T16:09:48.118+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Parallel Pythonで分散処理</title><content type='html'>Erlangでなくて、Pythonで分散処理を書く意義はなんだろうかと考えた。&lt;br /&gt;Erlangはたしかに分散処理が得意なんだろうけど、いろいろ調べた感じでは、複雑な数値計算などの分散処理には向いていないというウワサだ。良く知られているTwitterや通信の例のようなシンプルな処理を膨大な量さばくにはいいようだけど。&lt;br /&gt;&lt;br /&gt;計算を分散で行う場合、本来はGoogleが採用しているように、C++をベースにすべきだろう。&lt;br /&gt;（ただし、GoogleではSawzallという独自言語で記述し、それをC++に変換して実行するそうな。）&lt;br /&gt;&lt;br /&gt;そうなると、「なぜPythonで分散処理？」というのが重要になる訳だが、おそらく以下のようなことだろうか。&lt;br /&gt;&lt;ol&gt;&lt;li&gt;既存の豊富なモジュール（しかも多くはCで書かれている）を使える。&lt;/li&gt;&lt;li&gt;C、C++で書かれたルーチンをswig等でPythonに連結し、それを分散させれば、実質C、C++で実行しているようなものだろう。&lt;/li&gt;&lt;li&gt;簡単で読みやすい。(重要！)&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;そこで、まさに自分が今仕事で考えているものの要件でぴったりの問題があった。&lt;br /&gt;&lt;pre&gt;問題&lt;br /&gt;文の列（数十文程度）の各文どうしの総当たりのdiff（通常の行単位ではなく、&lt;br /&gt;単語単位でのdiff）を取り、diffで異なった割合を数値にした総当たり表を&lt;br /&gt;リアルタイムで返す。&lt;/pre&gt;&lt;br /&gt;都合のいいことに、Pythonには標準でdiffを取るためのライブラリ&lt;a href="http://www.python.jp/doc/2.4/lib/module-difflib.html"&gt;difflib&lt;/a&gt;がついているので、こむずかしいdiff計算はそいつに丸投げできる。&lt;br /&gt;これが、文の数が10、20程度なら分散させずに普通に解いても速度上問題はない。&lt;br /&gt;しかし、これが40、50になってくると、ちょっと「リアルタイム」とは言えなくなってくる。&lt;br /&gt;（文の数をnとすると、対称であることと、自分自身とのdiffは計算しないとしても、n*(n-1)/2回diffを取る必要がある。）&lt;br /&gt;&lt;br /&gt;ということで、これを分散処理させてみよう。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;準備&lt;/b&gt;&lt;br /&gt;&lt;a href="http://www.parallelpython.com/"&gt;Parallel Python&lt;/a&gt;を使う。インストールは通常のpython setup.py install 一発で完了。&lt;br /&gt;実験に使ったソースdiffdist.pyは本記事末尾に添付した。&lt;br /&gt;以下のように実行できる。&lt;br /&gt;分散処理で働いてもらいたいマシン群で、Parallel Pythonのサーバーを起動しておく。&lt;br /&gt;ppserver.pyコマンドはParallel Pythonをインストールした時に、pythonコマンドと同じディレクトリ(Linux, OSX)又は、c:¥Python25¥Scritpsフォルダ(Windows)に格納されているものです。&lt;br /&gt;&lt;pre&gt;$ /PATH/TO/PYTHONBIN/ppserver.py&lt;/pre&gt;&lt;br /&gt;あとは、diffdist.pyのppservers変数(113行あたり)にサーバー群のアドレスを記入しておいて、&lt;br /&gt;&lt;pre&gt;$ ./diffdist.py&lt;/pre&gt;&lt;br /&gt;で実行。&lt;br /&gt;(※Parallel Python本家ドキュメントに従ってauto discovery機能を使えば、IPアドレスの設定記入を省く事もできる。)&lt;br /&gt;今回は、140文(合計サイズ32kb程度)の英文の総当たり表を計算した。（今回このデータは添付しない。）&lt;br /&gt;英文データファイルの各行どうしで、単語ごとのdiffを取るというサンプルになっている。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;結果&lt;/b&gt;&lt;br /&gt;まず普通に分散させないコードだとどれぐらいになるかというと、&lt;br /&gt;&lt;pre&gt;ayu@~/work/difftest% time ./diffdist.py &lt;br /&gt;Starting pp with 2 workers&lt;br /&gt;./diffdist.py  26.64s user 0.36s system 97% cpu 27.705 total&lt;/pre&gt;&lt;br /&gt;ていう感じ。余裕で20秒以上かかります。&lt;br /&gt;&lt;br /&gt;これを、自分の手元マシン(MacBook白2GHz Intel Core2 Duo &amp; メモリ2G)でppserverを起動して分散処理させると、&lt;br /&gt;&lt;pre&gt;ayu@~/work/difftest% time ./diffdist.py &lt;br /&gt;Starting pp with 2 workers&lt;br /&gt;./diffdist.py  14.22s user 0.62s system 90% cpu 16.412 total&lt;/pre&gt;&lt;br /&gt;ここに、さらに別マシン(DELL SC1420、Intel Xeon 2.8GHz &amp; メモリ1G)を追加すると、、、&lt;br /&gt;&lt;pre&gt;ayu@~/work/difftest% time ./diffdist.py &lt;br /&gt;Starting pp with 2 workers&lt;br /&gt;./diffdist.py  9.62s user 0.59s system 89% cpu 11.394 total&lt;/pre&gt;&lt;br /&gt;順調に速くなっている。。&lt;br /&gt;おまけだが、我が家の物置で眠っていたSharpのメビウス君(AMD Duron 897MHz &amp; メモリ256M)を追加すると、、、&lt;br /&gt;&lt;pre&gt;ayu@~/work/difftest% time ./diffdist.py &lt;br /&gt;Starting pp with 2 workers&lt;br /&gt;./diffdist.py  8.03s user 0.58s system 85% cpu 10.100 total&lt;/pre&gt;&lt;br /&gt;ほんのちょっとだけど速くなるね！&lt;br /&gt;&lt;br /&gt;この調子で、どんどんマシンを追加していけば、この処理はすごく速くなっていくだろう。&lt;br /&gt;明日会社で本格的に試してみよう。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ソース diffdist.py&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;#!/usr/local/Python25/bin/python&lt;br /&gt;# _*_ coding: utf-8 _*_&lt;br /&gt;# Copyright (C)  2007 Ayukawa Hiroshi&lt;br /&gt;import sys&lt;br /&gt;import difflib&lt;br /&gt;from itertools import islice&lt;br /&gt;from collections import defaultdict&lt;br /&gt;&lt;br /&gt;import pp&lt;br /&gt;&lt;br /&gt;def getdiffrate(src1, src2):&lt;br /&gt;    """&lt;br /&gt;    diffを取って、異なった割合(diff割合)を返す。&lt;br /&gt;    """&lt;br /&gt;    SPC = " "&lt;br /&gt;    same = 0&lt;br /&gt;    diff = 0&lt;br /&gt;    for x in difflib.ndiff(src1, src2):&lt;br /&gt;        if x[0] == SPC:&lt;br /&gt;            same += 2 #一致部分カウントはsrc1とsrc2の分で+2&lt;br /&gt;        else:&lt;br /&gt;            diff += 1&lt;br /&gt;    return 100 * same / float(same+diff)&lt;br /&gt;&lt;br /&gt;def diffrow(src):&lt;br /&gt;    """&lt;br /&gt;    一つの文と、対比する複数の文のdiff割合をバッチ的に計算する。&lt;br /&gt;    &lt;br /&gt;    引数 src&lt;br /&gt;    [(文番号, 原文, [(対比する文1の番号,対比する文1), (対比する文2の番号,対比する文), ..]), ...]&lt;br /&gt;    &lt;br /&gt;    返り値&lt;br /&gt;    [(文番号, 対比する文の番号, 原文と対比文のdiff割合), ...]&lt;br /&gt;    """&lt;br /&gt;    ans = []&lt;br /&gt;    for i1, s1, osrc in src:&lt;br /&gt;        for i2, s2 in osrc:&lt;br /&gt;            rate = getdiffrate(s1, s2)&lt;br /&gt;            ans.append((i1, i2, rate))&lt;br /&gt;    return ans&lt;br /&gt;    &lt;br /&gt;def d_diffmatrix(job_server, srcs, unit=140):&lt;br /&gt;    """&lt;br /&gt;    文一覧を与えて、各文同士の間のdiff割合行列を返す。(分散処理バージョン)&lt;br /&gt;&lt;br /&gt;    引数&lt;br /&gt;    job_server 分散処理サーバー&lt;br /&gt;    srcs 文一覧（文字列の配列）&lt;br /&gt;    unit バッチ処理する単位（文の数）&lt;br /&gt;&lt;br /&gt;    返り値&lt;br /&gt;    行列データ(dict型データで、res[1][2]のようにdiff割合を格納しています。）&lt;br /&gt;    ただし、対角線成分上には、同じ文同士のdiff割合を格納すべきですが、計算を省略するため、&lt;br /&gt;    0.0を格納しています。&lt;br /&gt;    """&lt;br /&gt;    #各タスク実行に必要なデータを作成する。&lt;br /&gt;    task = [] #タスクに与えるデータ格納用&lt;br /&gt;    subtask = [] #サブタスクとりわけ用&lt;br /&gt;    sublen = 0   #サブタスクの分量計算用&lt;br /&gt;    #全タスクを、文の数に従って、サブタスクに分割します。&lt;br /&gt;    #サブタスクごとに分散処理させます。&lt;br /&gt;    for i1, s1 in enumerate(srcs):&lt;br /&gt;        osrc = list(islice(enumerate(srcs), i1))&lt;br /&gt;        subtask.append((i1, s1, osrc))&lt;br /&gt;        sublen += len(osrc)&lt;br /&gt;        if sublen &gt; unit: #文の数がunitを超えたら、一回分としてtaskに格納。&lt;br /&gt;            task.append(subtask)&lt;br /&gt;            subtask = []&lt;br /&gt;            sublen = 0&lt;br /&gt;    if subtask:&lt;br /&gt;        task.append(subtask)&lt;br /&gt;&lt;br /&gt;    #分散処理します。&lt;br /&gt;    jobs = []  #実行ジョブ格納用&lt;br /&gt;    for t in task:&lt;br /&gt;        jobs.append(job_server.submit(diffrow,(t, ), (getdiffrate,), ("difflib",))) &lt;br /&gt;        &lt;br /&gt;    #結果を取得して格納&lt;br /&gt;    diffrates = defaultdict(lambda: defaultdict(float))&lt;br /&gt;    for job in jobs:&lt;br /&gt;        for i1, i2, rate in job():&lt;br /&gt;            #行列状に格納&lt;br /&gt;            diffrates[i1][i2] = rate&lt;br /&gt;            diffrates[i2][i1] = rate&lt;br /&gt;    return diffrates&lt;br /&gt;&lt;br /&gt;def diffmatrix(srcs):&lt;br /&gt;    """&lt;br /&gt;    文一覧を与えて、各文同士の間のdiff割合行列を返す。(比較のための通常処理バージョン)&lt;br /&gt;&lt;br /&gt;    引数&lt;br /&gt;    srcs 文一覧（文字列の配列）&lt;br /&gt;&lt;br /&gt;    返り値&lt;br /&gt;    行列データ(dict型データで、res[1][2]のようにdiff割合を格納しています。）&lt;br /&gt;    ただし、対角線成分上には、同じ文同士のdiff割合を格納すべきですが、計算を省略するため、&lt;br /&gt;    0.0を格納しています。&lt;br /&gt;    """&lt;br /&gt;&lt;br /&gt;    #全タスクのジェネレーター&lt;br /&gt;    def gen():&lt;br /&gt;        for i1, s1 in enumerate(srcs):&lt;br /&gt;            osrc = list(islice(enumerate(srcs), i1))&lt;br /&gt;            yield (i1, s1, osrc)&lt;br /&gt;    #処理しながら、結果を行列に格納&lt;br /&gt;    diffrates = defaultdict(lambda: defaultdict(float))&lt;br /&gt;    for i1, i2, rate in diffrow(gen()):&lt;br /&gt;        diffrates[i1][i2] = rate&lt;br /&gt;        diffrates[i2][i1] = rate&lt;br /&gt;    return diffrates&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    ppservers = ("192.168.1.21","192.168.1.22","192.168.1.23")&lt;br /&gt;&lt;br /&gt;    if len(sys.argv) &gt; 1:&lt;br /&gt;        ncpus = int(sys.argv[1])&lt;br /&gt;        job_server = pp.Server(ncpus, ppservers=ppservers)&lt;br /&gt;    else:&lt;br /&gt;        job_server = pp.Server(ppservers=ppservers)&lt;br /&gt;&lt;br /&gt;    print "Starting pp with", job_server.get_ncpus(), "workers"&lt;br /&gt;&lt;br /&gt;    src = file("samplepatent.txt").readlines()&lt;br /&gt;    res = d_diffmatrix(job_server, [x.split(" ") for x in src])&lt;br /&gt;&lt;br /&gt;    #比較用&lt;br /&gt;    #res = diffmatrix([x.split(" ") for x in src])&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6593090616410107991?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6593090616410107991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6593090616410107991'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/parallel-python.html' title='Parallel Pythonで分散処理'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8714353415272555142</id><published>2008-05-10T22:11:00.004+09:00</published><updated>2008-05-10T22:27:59.868+09:00</updated><title type='text'>Erlangでベクトルの集合をクラスタリング（k-means）</title><content type='html'>&lt;a href="http://www.tektek.in/d/tk/detail/4756150705/"&gt;Erlang本&lt;/a&gt;を買ったので、k-means法によるクラスタリングをサンプル的に作ってみた。&lt;br /&gt;Erlang簡潔でいいですね。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;使い方&lt;/b&gt;&lt;br /&gt;データファイルをタブ区切りで用意する。&lt;br /&gt;1カラム目はデータの識別用ID文字列、2カラム目以降にベクトルの数値データを記入。改行コードは¥nで。&lt;br /&gt;&lt;pre&gt;ayu@~/work% /usr/local/erlang_R12B_2/bin/erl&lt;br /&gt;Erlang (BEAM) emulator version 5.6.2 [source] [smp:2] [async-threads:0] [kernel-poll:false]&lt;br /&gt;Eshell V5.6.2  (abort with ^G)&lt;br /&gt;1&gt; c(kmeans).&lt;br /&gt;{ok,kmeans}&lt;br /&gt;2&gt; Src = kmeans:read_line("sampledata2.txt").&lt;br /&gt;[{"1",[1,9,2,4,4,163.5,54,3,1,4,4,2.5,1,1,1,4,3,3,3,2,5]},&lt;br /&gt; {"2",[2,7,1,5,5,154.2,42,2,2,4,3,24.5,1,1,4,3,4,3,5,2,4]},&lt;br /&gt; {"3",[2,8,2,5,3,153.8,44.8,3.5,1,2,5,24,1,1,5,3,2,5,4,3,2]},&lt;br /&gt;  .....&lt;br /&gt;3&gt; {L, R} = kmeans:splitvectorset(Src).&lt;br /&gt;{[{"210",[2,4,2,3,3,156,42,3,2,3,4,2,2,2,3,2,3,5,4,1,3]},&lt;br /&gt;  {"205",[1,6,1,3,5,170,54,2.5,2,3,3,1.5,1,1,4,3,4,1,2,3,5]},&lt;br /&gt;  {"203",[1,2,1,2,3,163,53,2,2,4,4,24,2,1,3,2,2,1,3,1,3]},&lt;br /&gt;  ....&lt;br /&gt;4&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;以上で、LとRに二分割された集合が格納される。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ソース&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;-module(kmeans).&lt;br /&gt;-import(lists, [map/2, zip/2, sum/1]).&lt;br /&gt;-import(math, [sqrt/1]).&lt;br /&gt;-export([splitvectorset/1, read_line/1]).&lt;br /&gt;&lt;br /&gt;%ベクトルのノルム&lt;br /&gt;norm(X)-&gt;&lt;br /&gt;    sqrt(sum(map(fun(Y)-&gt;Y*Y end, X))).&lt;br /&gt;&lt;br /&gt;%ベクトル集合の重心&lt;br /&gt;median([],_)-&gt;&lt;br /&gt;    [];&lt;br /&gt;median(X, L)-&gt;&lt;br /&gt;    First = lists:nth(1,X),&lt;br /&gt;    if&lt;br /&gt;    First == [] -&gt; [];&lt;br /&gt;    true -&gt; [sum(map(fun erlang:hd/1, X))/L | median(map(fun erlang:tl/1, X), L)]&lt;br /&gt;    end.&lt;br /&gt;median(X)-&gt;&lt;br /&gt;    median(X, length(X)).&lt;br /&gt;&lt;br /&gt;%ベクトルの差&lt;br /&gt;sub([], _)-&gt;&lt;br /&gt;    [];&lt;br /&gt;sub(X, Y) -&gt;&lt;br /&gt;    [hd(X)-hd(Y)|sub(tl(X), tl(Y))].&lt;br /&gt;&lt;br /&gt;%二つのベクトル間の距離&lt;br /&gt;distance(X, Y) -&gt;&lt;br /&gt;    norm(sub(X,Y)).&lt;br /&gt;&lt;br /&gt;%与えられた二点X,YのどちらにベクトルZは近いか？&lt;br /&gt;% Xに近ければ'Right', Yに近ければ'Left'を返す。&lt;br /&gt;which(_,_,[])-&gt;   &lt;br /&gt;    ok;&lt;br /&gt;which(X, Y, Z) -&gt;&lt;br /&gt;    DX = distance(X,Z),&lt;br /&gt;    DY = distance(Y,Z),&lt;br /&gt;    if&lt;br /&gt;    DX &gt; DY -&gt; 'Left';&lt;br /&gt;    true  -&gt; 'Right'&lt;br /&gt;    end.&lt;br /&gt;&lt;br /&gt;%[{'Right/Left', ベクトル}, ...]というリストを'Right'/'Left'に従って二つの&lt;br /&gt;%リストに分けて返す。&lt;br /&gt;splitvector([], R, L)-&gt;&lt;br /&gt;    {R, L};&lt;br /&gt;splitvector([{D,Z}|T],R,L) -&gt;&lt;br /&gt;    case D of&lt;br /&gt;    'Right' -&gt; splitvector(T, [Z|R], L);&lt;br /&gt;    'Left'  -&gt; splitvector(T, R, [Z|L])&lt;br /&gt;    end.&lt;br /&gt;&lt;br /&gt;%集合ZSの２元からなる部分集合列を返す&lt;br /&gt;pairs([])-&gt;&lt;br /&gt;    [];&lt;br /&gt;pairs([Z|T]) -&gt;&lt;br /&gt;    lists:append(map(fun(X)-&gt;{Z,X} end, T), pairs(T)).&lt;br /&gt;%ベクトル集合の距離＆ベクトルペアの列を作る&lt;br /&gt;pairdistance([])-&gt;&lt;br /&gt;    [];&lt;br /&gt;pairdistance(ZS) -&gt;&lt;br /&gt;    map(fun({X,Y})-&gt;{distance(X,Y), X, Y} end, pairs(ZS)).&lt;br /&gt;&lt;br /&gt;%ベクトル集合の最大距離を持つ２点を選ぶ&lt;br /&gt;maxdistance(ZS)-&gt;&lt;br /&gt;    Pairs = pairdistance(ZS),&lt;br /&gt;    {_, MX, MY} = maxdistance(Pairs, hd(Pairs)),&lt;br /&gt;    {MX, MY}.   &lt;br /&gt;maxdistance([], M)-&gt; M;&lt;br /&gt;maxdistance([Z|T], M)-&gt;&lt;br /&gt;    {D1,_,_} = M,&lt;br /&gt;    {D2,_,_} = Z,&lt;br /&gt;    if&lt;br /&gt;    D2 &gt; D1 -&gt; maxdistance(T, Z);&lt;br /&gt;    true -&gt; maxdistance(T, M)&lt;br /&gt;    end.&lt;br /&gt;       &lt;br /&gt;   &lt;br /&gt;%二点X,Yのどっちに近いかで、ベクトル集合ZSを二分割する。&lt;br /&gt;splitvectorset(X,Y,ZS, Thre)-&gt;&lt;br /&gt;    {R,L} = splitvector(zip(map(fun({_,W})-&gt;which(X,Y,W) end, ZS), ZS), [], []),&lt;br /&gt;    IdRmv = fun ({_, V})-&gt;V end,&lt;br /&gt;    CR = median(map(IdRmv, R)),&lt;br /&gt;    CL = median(map(IdRmv, L)),&lt;br /&gt;    MinDist  = lists:min([distance(X,CR)+distance(Y, CL), distance(Y, CR)+distance(X, CL)]),&lt;br /&gt;    if&lt;br /&gt;    MinDist &gt; Thre -&gt; &lt;br /&gt;        splitvectorset(CR, CL, ZS, Thre);&lt;br /&gt;    true -&gt; {R, L}&lt;br /&gt;    end.&lt;br /&gt;&lt;br /&gt;%公開関数その１  &lt;br /&gt;%ベクトル集合ZSを二分割する。&lt;br /&gt;%集合ZSは、もう一つの公開関数read_lineで読み込んだデータです。&lt;br /&gt;splitvectorset(ZS)-&gt;&lt;br /&gt;    Threshold = 0.1,&lt;br /&gt;    case length(ZS) of&lt;br /&gt;    0 -&gt; [[],[]];&lt;br /&gt;    1 -&gt; [ZS|[[]]];&lt;br /&gt;    2 -&gt; [[lists:nth(1, ZS)], [lists:nth(2, ZS)]];&lt;br /&gt;    _ -&gt;&lt;br /&gt;         {X, Y} = maxdistance(map(fun ({_, X})-&gt;X end, ZS)),&lt;br /&gt;         splitvectorset(X, Y, ZS, Threshold)&lt;br /&gt;    end.&lt;br /&gt;&lt;br /&gt;%分析するデータファイルを読んで{ID, ベクトル}のリストとして返します。&lt;br /&gt;% データファイル仕様&lt;br /&gt;%   データファイルはタブ区切り、先頭カラムはレコードID文字列、次カラム以降が数値データ&lt;br /&gt;%   改行コードは\n&lt;br /&gt;read_line(File) -&gt;&lt;br /&gt;    {ok, IoDevice} = file:open(File, read),&lt;br /&gt;    ANS = read_line(IoDevice, 1, []),&lt;br /&gt;    file:close(IoDevice),&lt;br /&gt;    ANS.&lt;br /&gt;&lt;br /&gt;read_line(IoDevice, LineNumber, Buf) -&gt;&lt;br /&gt;    case io:get_line(IoDevice, "") of&lt;br /&gt;    eof -&gt;&lt;br /&gt;        Buf;&lt;br /&gt;    Line -&gt;&lt;br /&gt;        Data = string:tokens(lists:delete(10, Line), "\t"),  % 10 = "\n"&lt;br /&gt;        if&lt;br /&gt;        length(Data) == 0 -&gt; ok;&lt;br /&gt;        true -&gt; Vec = {hd(Data), map(fun(X)-&gt; parse_num(X) end, tl(Data))},&lt;br /&gt;            read_line(IoDevice, LineNumber + 1, lists:append(Buf, [Vec]))&lt;br /&gt;        end&lt;br /&gt;    end.&lt;br /&gt;&lt;br /&gt;%数値を表す文字列をinteger又はfloatに変換します。   &lt;br /&gt;parse_num(X)-&gt;&lt;br /&gt;    case string:str(X, ".") of&lt;br /&gt;    0 -&gt; list_to_integer(X);&lt;br /&gt;    _ -&gt; list_to_float(X)&lt;br /&gt;    end.&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8714353415272555142?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8714353415272555142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8714353415272555142'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/erlangk-means.html' title='Erlangでベクトルの集合をクラスタリング（k-means）'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-4175228922529399253</id><published>2008-05-08T02:05:00.006+09:00</published><updated>2008-05-08T02:14:43.065+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>pythonで英語の同義語などを取得する</title><content type='html'>&lt;a href="http://nltk.org"&gt;nltk&lt;/a&gt;には&lt;a href="http://ja.wikipedia.org/wiki/WordNet"&gt;wordnet&lt;/a&gt;が組み込まれているので、nltkひとつをインストールするだけで、同義語、上位語、下位語などを自由に取得できる。&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; from nltk import wordnet&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; dog = wordnet.N["dog"]&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; dog.synsets()&lt;br /&gt;[{noun: dog, domestic_dog, Canis_familiaris}, {noun: frump, dog}, &lt;br /&gt;{noun: dog}, {noun: cad, bounder, blackguard, dog, hound, heel}, &lt;br /&gt;{noun: frank, frankfurter, hotdog, hot_dog, dog, wiener, &lt;br /&gt;wienerwurst, weenie}, {noun: pawl, detent, click, dog}, &lt;br /&gt;{noun: andiron, firedog, dog, dog-iron}]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;英語の検索エンジンの検索クエリ入力画面を作ったときなんかに、このデータでクエリーを膨らませて検索することとかも考えてみると使い手がありそうですね。&lt;br /&gt;&lt;br /&gt;より詳しい使い方は&lt;a href="http://nltk.org/doc/api/nltk.wordnet.synset-pysrc.html#demo"&gt;nltkのデモ&lt;/a&gt;でざっと眺める事ができます。&lt;br /&gt;&lt;br /&gt;nltkのインストール方法は、&lt;a href="http://hiroshiykw.blogspot.com/2008/04/nltk.html"&gt;自分の過去記事にあります。&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-4175228922529399253?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/4175228922529399253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/4175228922529399253'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/python.html' title='pythonで英語の同義語などを取得する'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8992949350788621562</id><published>2008-05-04T03:03:00.010+09:00</published><updated>2008-05-04T03:45:32.425+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>日本語テキストのトピック分割</title><content type='html'>先日から&lt;a href="http://coderepos.org/share"&gt;coderepos&lt;/a&gt;に置いている自動要約モジュールに、日本語テキストのトピック分割のソースをコミットしました。&lt;br /&gt;(-&amp;gt;&lt;a href="http://coderepos.org/share/browser/lang/python/yoyaku/yoyaku/engine/TopicSegmentationJP.py"&gt;そのソース&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;このスクリプトでは、与えられた日本語のテキストを、トピックごとに分割する機能を提供しています。&lt;br /&gt;&lt;br /&gt;基本的には論文"&lt;a href="http://acl.ldc.upenn.edu/A/A00/A00-2004.pdf"&gt;Advances in domain independent linear text segmentation&lt;/a&gt;"を参考にしています。&lt;br /&gt;この論文では&lt;br /&gt; 1. 文ごとにTFベクトルを計算し、&lt;br /&gt; 2. そのベクトル間でcos正規化された内積を計算して文間の類似度を算出、&lt;br /&gt; 3. 近接する文同士の類似度の変化具合を見て、トピックの変わり目を決定。&lt;br /&gt;という方式をとっています。&lt;br /&gt;ですが、今回の実装では、上記を日本語にも適用するためにさらに以下の改良を加えています。&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;動詞も使うことにした。&lt;/h1&gt;&lt;br /&gt;日本語のテキスト、特にブログの記事などは、名詞だけでなく、「節約する」とか「怒る」とかの動詞も考慮にいれたほうがよかろうと思い、動詞も使っています。ただし、動詞は活用しますので、mecabでの処理結果の品詞情報の行から動詞の原型を取得して使うことにしました。&lt;br /&gt;（-&amp;gt;&lt;a href="http://coderepos.org/share/browser/lang/python/yoyaku/yoyaku/engine/TopicSegmentationJP.py?rev=11041#L25"&gt;対応するソースの部分&lt;/a&gt;）&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;表記揺れ対策&lt;/h1&gt;&lt;br /&gt;原論文では英語のporter stemmingをしていましたが、日本語では独自の表記揺れ対策をしなければいけません。&lt;br /&gt;表記揺れ対策には以下の方針をとりました。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. カタカナ語は地道に辞書を作る。&lt;/b&gt;&lt;br /&gt;カタカナ語の表記揺れ辞書データは本職で半自動生成したことがありますので、近いうちに作ろうと思います。大量の生テキストデータが必要ですので、どこかからテキストを取得せねばなりません。wikipediaデータでもいいかもしれませんが、できればあんなきれいな文章ではないほうがいいので考えます。&lt;br /&gt;(-&amp;gt;対応するソース&lt;a href="http://coderepos.org/share/browser/lang/python/yoyaku/yoyaku/engine/HyokiyureData.py"&gt;HyokiyureData.py&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. 漢字の単語はunigramも生成する&lt;/b&gt;&lt;br /&gt;名詞＆未知語の場合のみ、漢字の単語の表記揺れは、その語のunigramもTFカウントすることで対応します。&lt;br /&gt;例えば、通常「人」と「人々」は異なる語と認識されてしまいますが、「人々」の方を文字単位で分割し、「人」と「々」それぞれについてもカウントすることにより、「人」と「人々」が互いに多少は類似していると判定できるようになります。&lt;br /&gt;(-&amp;gt;&lt;a href="http://coderepos.org/share/browser/lang/python/yoyaku/yoyaku/engine/TopicSegmentationJP.py?rev=11041#L58"&gt;対応するソース&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;語の重みのバリエーション&lt;/h1&gt;&lt;br /&gt;語の重みを以下のように変えて計算しています。&lt;br /&gt; * 名詞、未知語: 1語 = 重み1&lt;br /&gt; * 名詞、未知語unigram: 1語(1文字) = 重み0.3&lt;br /&gt; * 動詞: 1語 = 重み0.5&lt;br /&gt;これは、一文でTFベクトルを作っても、たいていはTF=1の語ばかりで、あまりその文の特徴を表しているとも思えませんでしたので、unigramや動詞も考慮に入れた上で、それらの重みの間に差を付けることで、文の間により特色の違いをだせないかという試みです。検証してませんが、まあ、見たかんじ結果がよくなったように思うので、ひとまずこれで行きます。&lt;br /&gt;(-&amp;gt;&lt;a href="http://coderepos.org/share/browser/lang/python/yoyaku/yoyaku/engine/TopicSegmentationJP.py?rev=11041#L54"&gt;対応するソース&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;TFベクトルではなく、TFIDF的ベクトルを使用&lt;/h1&gt;&lt;br /&gt;ブログ記事のような中程度の長さの文を扱うことを想定していますので、より文の間の特徴を鋭く認識したほうがいいかと思いました。&lt;br /&gt;そこで、文全体でまんべんなく頻出している単語の効果を間引くために語が現れた文の数の逆数をかけることで、ベクトルの重みを調整しています。&lt;br /&gt;(-&amp;gt;&lt;a href="http://coderepos.org/share/browser/lang/python/yoyaku/yoyaku/engine/TopicSegmentationJP.py?rev=11041#L86"&gt;対応するソース&lt;/a&gt;）&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;まだまだ先は長いですが、こつこつ作って行きます。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8992949350788621562?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8992949350788621562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8992949350788621562'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/blog-post.html' title='日本語テキストのトピック分割'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-1275106852113931370</id><published>2008-05-04T02:33:00.002+09:00</published><updated>2008-05-04T02:35:28.447+09:00</updated><title type='text'>coderepos</title><content type='html'>&lt;a href="http://coderepos.org"&gt;coderepos&lt;/a&gt;に自分のページを作った。今後ここに開発中のライブラリのマニュアルなどを書いていこうと思います。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://coderepos.org/share/wiki/Committers/ayu"&gt;http://coderepos.org/share/wiki/Committers/ayu&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-1275106852113931370?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1275106852113931370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1275106852113931370'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/coderepos.html' title='coderepos'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6055042350109154134</id><published>2008-05-01T00:35:00.002+09:00</published><updated>2008-05-01T00:38:59.836+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Jython本を注文した</title><content type='html'>Jython本を注文しました。&lt;br /&gt;&lt;br /&gt;まだAmazonのレビューはない見たいだけど、&lt;a href="http://www.tektek.in/d/tk/detail/4839922829/"&gt;ブログでは話題になっているようだ。&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;随所で最高の評価を受けているようなので、とても楽しみです！&lt;br /&gt;&lt;br /&gt;今度「Python禁止！JAVAだけで書け！」みたいなプロジェクトに無理矢理入れられそうなので、ちょっとJythonの準備しとくかな。。。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6055042350109154134?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6055042350109154134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6055042350109154134'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/05/jython.html' title='Jython本を注文した'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-9141008622813485868</id><published>2008-04-30T23:57:00.002+09:00</published><updated>2008-05-01T00:05:48.495+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Python用の自動要約モジュールをcodereposにimportしたよ</title><content type='html'>けっこう前からのんびり作っていた自動要約モジュールを&lt;a href="http://coderepos.org"&gt;Coderepos&lt;/a&gt;にimportしました。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://coderepos.org/share/browser/lang/python/yoyaku"&gt;http://coderepos.org/share/browser/lang/python/yoyaku&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;この自動要約モジュールはまだあまり精度はよくないです。&lt;br /&gt;が、どのぐらい良くないかを知るには、以下のサイトでいちおうサービスとして設置していますので、お試しいただけます。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.civory.com/"&gt;自動要約サービス Civory&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;今の所は単純なMMRアルゴリズムで文を抜粋するだけのものですので、まあ、あまり、、、。&lt;br /&gt;&lt;br /&gt;今取り組んでいるのは、英文の自動要約の際に、文をまずトピックごとに分割して、その上で要約をかけようとしています。&lt;br /&gt;トピックに分けるアルゴリズムは以下の論文を参考にしています。&lt;br /&gt;&lt;a href="http://acl.ldc.upenn.edu/A/A00/A00-2004.pdf"&gt;Advances in domain independent linear text segmentation&lt;/a&gt;&lt;br /&gt;いちおうこれの実装はひとまず終わっていて、それに対応するソースは以下になります。&lt;br /&gt;&lt;a href="http://coderepos.org/share/browser/lang/python/yoyaku/yoyaku/engine/TopicSegmentationEN.py"&gt;TopicSegmentationEN.py&lt;/a&gt;&lt;br /&gt;今後これにバグがないか注意しながらいろんな例で実験を重ねていく予定です。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-9141008622813485868?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/9141008622813485868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/9141008622813485868'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/pythoncodereposimport.html' title='Python用の自動要約モジュールをcodereposにimportしたよ'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-5932908825054016468</id><published>2008-04-30T23:15:00.001+09:00</published><updated>2008-04-30T23:17:02.090+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>NLTKでstemming</title><content type='html'>&lt;a href="http://nltk.org"&gt;nltk&lt;/a&gt;にはステミングの有名なアルゴリズムであるporterアルゴリズムが用意されている。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; import nltk&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; nltk.PorterStemmer().stem("application")&lt;br /&gt;'applic'&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-5932908825054016468?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/5932908825054016468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/5932908825054016468'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/nltkstemming.html' title='NLTKでstemming'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-504493603713406151</id><published>2008-04-23T19:45:00.005+09:00</published><updated>2008-04-23T19:52:47.696+09:00</updated><title type='text'>自分のサイトでのユーザーの視線の流れを調べてみる</title><content type='html'>&lt;a href="http://coliss.com/articles/build-websites/operation/design/1025.html"&gt;プレゼンにも最適、ページ内のユーザーの視線をシミュレートする -Feng GUI heatmap&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Feng GUI heatmapは、独自のアルゴリズムに基づいて、ユーザーの視線がどのようにページ内で移動するかとその頻度を表示するヒートマップを作成するサービスです。&lt;/blockquote&gt;&lt;br /&gt;ということなので、自分のサイト&lt;a href="http://www.tektek.in"&gt;TekTek&lt;/a&gt;でもユーザーの視線をシミュレートしてみました。&lt;br /&gt;対象ページ: &lt;a href="http://www.tektek.in/d/tk/detail/487311361X/"&gt;書籍「ハイパフォーマンスWebサイト」の詳細ページ&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.tektek.in/d/tk/detail/487311361X/"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_TlQ68V-OBvk/SA8T7p45UjI/AAAAAAAAAAY/SZpzUXr3gOc/s400/tektekheat.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5192390810959172146" /&gt;&lt;/a&gt;&lt;br /&gt;ぱっと見、書籍の画像とAmazonへのリンクに視線が集中するようだ。&lt;br /&gt;しかし、このページのメインはレビューを眺めてもらうことなので、そちらがもっと読みやすくなるようにすべきかもしれない。&lt;br /&gt;なんかよいアイデアはないだろうか。&lt;br /&gt;&lt;br /&gt;ついでだが、上記書籍がまだ手元に届かない。早くしてよ〜。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-504493603713406151?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/504493603713406151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/504493603713406151'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/blog-post_23.html' title='自分のサイトでのユーザーの視線の流れを調べてみる'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_TlQ68V-OBvk/SA8T7p45UjI/AAAAAAAAAAY/SZpzUXr3gOc/s72-c/tektekheat.jpg' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-7274300212954489635</id><published>2008-04-20T09:20:00.004+09:00</published><updated>2008-04-20T09:26:43.562+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>NLTKで英文の文末判定</title><content type='html'>英文の文末を判定する簡易なルールベースのアルゴリズム。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://nedbatchelder.com/blog/200804/separating_sentences.html"&gt;Separating sentences&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;１年前にこの手のアルゴリズムを実装しようとしたが、この問題は非常にやっかいです。&lt;br /&gt;たとえばこんな例:&lt;blockquote&gt;CELLULAR COMMUNICATIONS INC. sold 1,550,000 common shares at $21.75 each&lt;br /&gt;yesterday, according to lead underwriter L.F. Rothschild &amp;amp; Co.&lt;/blockquote&gt;&lt;br /&gt;"INC."の直後や"$21.75"、"L.F."などのピリオドを文末と認識しては大間違いになるのです。&lt;br /&gt;&lt;br /&gt;この問題を解決するのに自分が１年前に着目していた論文は以下のもの。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.linguistics.ruhr-uni-bochum.de/%7Estrunk/ks2005FINAL.pdf"&gt;Unsupervised Multilingual Sentence Boundary Detection&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;この論文では、特に言語を英語だけに限定しない方法を提案しています。&lt;br /&gt;大規模な生のテキストデータから得られる統計情報のみで、文末判定を行えます。&lt;br /&gt;難点はルールベースなどとは違って、事前の綿密な統計の作成、統計処理後の各種特別処理の実装が面倒くさいこと。&lt;br /&gt;昨年途中まで実装したが、Python用の自然言語処理ライブラリ&lt;a href="http://nltk.org/"&gt;NLTK&lt;/a&gt;でどうも実装予定との情報を見つけて半端でやめていました。&lt;br /&gt;&lt;br /&gt;それで久しぶりに調べてみたら、このアルゴリズムがすでに&lt;a href="http://nltk.org/"&gt;NLTK&lt;/a&gt;で実装されて公開されているではないですか！&lt;br /&gt;&lt;br /&gt;早速インストールして使ってみました。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;インストール&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;% wget http://prdownloads.sourceforge.net/nltk/nltk-0.9.2.tar.gz&lt;br /&gt;% tar zxvf nltk-0.9.2.tar.gz&lt;br /&gt;% cd nltk-0.9.2&lt;br /&gt;% sudo python setup.py install&lt;br /&gt;% cd ..&lt;br /&gt;% sudo mkdir /usr/share/nltk&lt;br /&gt;% cd /usr/share/nltk&lt;br /&gt;% sudo wget http://prdownloads.sourceforge.net/nltk/nltk-data-0.9.2.zip&lt;br /&gt;% sudo unzip nltk-data-0.9.2.zip&lt;br /&gt;% sudo chmod -R g+r data&lt;br /&gt;% export NLTK_DATA=/usr/share/nltk/data&lt;br /&gt;% python&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import nltk&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; nltk.corpus.brown.words()&lt;br /&gt;['The', 'Fulton', 'County', 'Grand', 'Jury', 'said', ...]&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ここまでできればインストール完了。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;生テキストデータを用意&lt;/b&gt;&lt;br /&gt;例えば、Google News（英語版）などからリンクをたどって、ひたすらニュース本文をファイルnews.txtにコピペする。&lt;br /&gt;実験でやるんであれば１０００行程度で十分でした。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;実験！！&lt;/b&gt;&lt;br /&gt;まず生テキストを食わせて学習&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; from nltk.tokenize import PunktSentenceTokenizer&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; p = PunktSentenceTokenizer()&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; fp = file("news.txt")&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; p.train(fp.read())&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;次に実際に判定してみる。&lt;br /&gt;判定に使うテキストは次のような少々意地の悪い例&lt;br /&gt;&lt;blockquote&gt;The Finland-based company expects a weaker dollar and slower economic growth in the U.S. and parts of Europe to dampen the overall handset market this year. About half of Nokia's (NOK) sales are in dollars or currencies tied to it; a weaker dollar makes imports more expensive.&lt;br /&gt;&lt;br /&gt;"What spooked us was its outlook for the industry in general," said Rick Franklin, equities analyst at Edward Jones.&lt;br /&gt;&lt;br /&gt;Nokia reiterated projections that the industry shipments of handsets will grow 10% this year over last. In the first quarter, though, global shipments rose 17%, suggesting a slowdown in the remainder of the year.&lt;br /&gt;&lt;br /&gt;For the quarter that ended March 31, Nokia earned $1.9 billion (1.2 euros), up 25% from the same quarter last year but short of an expected $2.3 billion. Overall sales rose 28% to $20.1 billion (12.6 billion euros), roughly in line with views.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; a=p.tokenize("""The Finland-based company expects&lt;br /&gt;a weaker dollar and slower economic growth in the U.S. and parts of Europe to&lt;br /&gt;dampen the overall handset market this year. About half of Nokia's (NOK) sales&lt;br /&gt;are in dollars or currencies tied to it; a weaker dollar makes imports more&lt;br /&gt;expensive.&lt;br /&gt;&lt;br /&gt;"What spooked us was its outlook for the industry in general," said Rick Franklin,&lt;br /&gt;equities analyst at Edward Jones.&lt;br /&gt;&lt;br /&gt;Nokia reiterated projections that the industry shipments of handsets will grow 10%&lt;br /&gt;this year over last. In the first quarter, though, global shipments rose 17%,&lt;br /&gt;suggesting a slowdown in the remainder of the year.&lt;br /&gt;&lt;br /&gt;For the quarter that ended March 31, Nokia earned $1.9 billion (1.2 euros), up 25%&lt;br /&gt;from the same quarter last year but short of an expected $2.3 billion. Overall&lt;br /&gt;sales rose 28% to $20.1 billion (12.6 billion euros), roughly in line with views.""")&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; for x in a:&lt;br /&gt;...    print x&lt;br /&gt;...    print "-"*20&lt;br /&gt;The Finland-based company expects a weaker dollar and slower economic growth&lt;br /&gt;in the U.S. and parts of Europe to dampen the overall handset market this year.&lt;br /&gt;--------------------&lt;br /&gt;About half of Nokia's (NOK) sales are in dollars or currencies tied to it;&lt;br /&gt;a weaker dollar makes imports more expensive.&lt;br /&gt;--------------------&lt;br /&gt;"What spooked us was its outlook for the industry in general," said Rick Franklin,&lt;br /&gt;equities analyst at Edward Jones.&lt;br /&gt;--------------------&lt;br /&gt;Nokia reiterated projections that the industry shipments of handsets will&lt;br /&gt;grow 10% this year over last.&lt;br /&gt;--------------------&lt;br /&gt;In the first quarter, though, global shipments rose 17%, suggesting a slowdown&lt;br /&gt;in the remainder of the year.&lt;br /&gt;--------------------&lt;br /&gt;For the quarter that ended March 31, Nokia earned $1.9 billion (1.2 euros), up&lt;br /&gt;25% from the same quarter last year but short of an expected $2.3 billion.&lt;br /&gt;--------------------&lt;br /&gt;Overall sales rose 28% to $20.1 billion (12.6 billion euros), roughly in line&lt;br /&gt;with views.&lt;br /&gt;--------------------&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;きちんと、ピリオドで文をわけつつも、"U.S."や、"1.2 euros"などで区切るのは避けていることが分かります。&lt;br /&gt;&lt;br /&gt;精度を上げるには、もっともっと大量の生テキストを食わせる必要があります。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-7274300212954489635?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7274300212954489635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7274300212954489635'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/nltk.html' title='NLTKで英文の文末判定'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8032646515040462483</id><published>2008-04-20T07:20:00.002+09:00</published><updated>2008-04-20T07:27:15.089+09:00</updated><title type='text'>モンティ・ホール問題</title><content type='html'>以下のリンク先の問題が興味深い。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://handasse.blogspot.com/2008/04/python_20.html"&gt;Python: モンティ・ホール問題&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;「プレイヤーは、三つのドアを見せられる。ドアの一つの後ろにはプレイヤーが獲得できる車(アタリ)があり、一方、他の二つのドアには山羊(ハズレ)が 入っている。ホストであるモンティは、それぞれのドアの後ろに何があるか知っているのに対し、もちろんプレイヤーは知らない。&lt;br /&gt;&lt;br /&gt;プレイヤーはまず三つのドアの一つを選ぶ。次にモンティは他の二つのドアのうち一つを開け、山羊をみせる。そしてモンティはプレイヤーに、初めの選択のま までよいか、もう一つの閉じているドアに変更するか、どちらかの選択権を提供する。プレイヤーは、選択を変更すべきだろうか?」&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;変更しない場合: 普通に３つのうちの一つが当たりなので、当たる確率は1/3&lt;br /&gt;&lt;br /&gt;変更する場合: &lt;br /&gt;　最初の選択でもしも当たっていたら、(これは1/3の確率でおこる)-&amp;gt;変更するためかならずはずれになる。&lt;br /&gt;　最初の選択でもしもはずれていたら、(これは2/3の確率でおこる)-&amp;gt;モンティがもう一つのはずれを引いていてくれるので、変更することで必ず当たりになる。&lt;br /&gt;　そのため、変更する場合に当たる確率は2/3&lt;br /&gt;&lt;br /&gt;なので、変更したほうが当たる確率が二倍になる！！！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8032646515040462483?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8032646515040462483'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8032646515040462483'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/blog-post_20.html' title='モンティ・ホール問題'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-7603537174223424201</id><published>2008-04-14T00:17:00.004+09:00</published><updated>2008-04-14T00:23:34.762+09:00</updated><title type='text'>partty</title><content type='html'>&lt;a href="http://www.partty.org/"&gt;partty&lt;/a&gt;が面白い。&lt;br /&gt;&lt;br /&gt;自分のterminalを晒すことができるwebサービスだそうです。&lt;br /&gt;&lt;br /&gt;面識がないにも関わらずtwitterでこっそりfollow している&lt;a href=""&gt;西尾さん&lt;/a&gt;が使っているのを見てシビレました。&lt;br /&gt;&lt;br /&gt;自分はMacOS 10.4.11だが、上記サイトで配布されているparttyソフトがbus errorとやらで起動しなかったので、ソースをconfigure &amp;amp; makeしました。&lt;br /&gt;&lt;br /&gt;gnu screen で複数画面を立ち上げていても、それらがきちんと公開されます。&lt;br /&gt;mysql -uaaa -pxxx somedb&lt;br /&gt;などとうっかり打つと、パスワードが晒されますのでご注意を。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-7603537174223424201?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7603537174223424201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7603537174223424201'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/partty.html' title='partty'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6601421680485536775</id><published>2008-04-10T02:12:00.002+09:00</published><updated>2008-04-10T02:16:34.749+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Google App Engineが待ち遠しすぎる。。。</title><content type='html'>&lt;a href="http://www.tektek.in/d/tk/"&gt;TekTek&lt;/a&gt;の&lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt;対応は完了したのだが、まだ登録の順番が回ってこない！！&lt;br /&gt;&lt;br /&gt;なので、ちょっとメモなど&lt;br /&gt;&lt;br /&gt; * Google App Engineではdjangoのauth、sessionは使えないようだ。sessionが使えないのは、djangoのsessionがdjangoのmodelに依存しているからだそうな。この制限は厳しいが誰かが簡単な解決を探してくれるんじゃないかな。&lt;br /&gt; * TekTekでは、sessionをやめて、できる限りCookieに保存するようにした。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6601421680485536775?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6601421680485536775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6601421680485536775'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/google-app-engine_10.html' title='Google App Engineが待ち遠しすぎる。。。'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-5687911901326024928</id><published>2008-04-09T08:25:00.002+09:00</published><updated>2008-04-09T08:33:37.078+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Google App Engine と格闘中</title><content type='html'>昨晩、数時間ほど&lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt;で自作のdjangoアプリを移植していた際に気づいたこと。&lt;br /&gt;&lt;br /&gt; * printデバッグをしていると、HTTPヘッダの前にprintの結果が出力され、HTTPヘッダもろともブラウザに表示されてしまう。&lt;br /&gt; * urlopenは使えず、Googleが用意した&lt;a href="http://code.google.com/appengine/docs/urlfetch/"&gt;URL Fetch API&lt;/a&gt;を用いる。&lt;br /&gt; * 手元のマシンのpythonのsite-packagesはそのままではどうも見てくれないようだ。&lt;br /&gt; * django の ContextProcessorは通常内部的にrequest.userを使っているようで、以下のようにしてTEMPLATE_CONTEXT_PROCESORSからauthを外す必要がある。&lt;br /&gt;&lt;pre&gt;TEMPLATE_CONTEXT_PROCESSORS = (&lt;br /&gt;"django.core.context_processors.debug",&lt;br /&gt;"django.core.context_processors.i18n",&lt;br /&gt;"django.core.context_processors.media"&lt;br /&gt;    )&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;早く本登録来い！！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-5687911901326024928?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/5687911901326024928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/5687911901326024928'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/google-app-engine.html' title='Google App Engine と格闘中'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-86516285357777569</id><published>2008-04-09T01:15:00.006+09:00</published><updated>2008-04-09T01:40:59.156+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Google App Engine SDKインストール編</title><content type='html'>&lt;a href="http://www.tektek.in/d/tk/"&gt;TekTek&lt;/a&gt;で使えたらいいなと思って、&lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt;のSDKをインストールしてみた。&lt;br /&gt;(まだ登録は順番待ちなのです。(T_T)&lt;br /&gt;ひとまずHello worldまで実験完了したので書いておきます。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. SDKのダウンロード&lt;/b&gt;&lt;br /&gt;&lt;a href="http://code.google.com/appengine/downloads.html"&gt;http://code.google.com/appengine/downloads.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. インストール&lt;/b&gt;&lt;br /&gt;ダウンロードしたパッケージをひたすらクリックしてインストールして行きます。&lt;br /&gt;その間表示されるメッセージには、以下のようなことが書いてあります。&lt;br /&gt;&lt;pre&gt;開発用サーバーは、/usr/local/bin/dev_appserver.py にインストールされます。&lt;br /&gt;その他の部品は /usr/local/google_appengine へインストールされます。&lt;br /&gt;&lt;br /&gt;開発サーバーの起動&lt;br /&gt;/usr/local/bin/dev_appserver.py [options] &amp;lt;application root&amp;gt;&lt;br /&gt;&lt;br /&gt;"application root"は、文字通りアプリケーションのルートディレクトリで、&lt;br /&gt;正式なフォーマットのapp.yamlかapp.ymlファイルを置いていなければならない。&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;追加で、以下のコマンドを実行し、各アプリをPythonにインストール。&lt;br /&gt;&lt;pre&gt;% sudo ln -s /usr/local/google_appengine/google /usr/local/Python25/lib/python2.5/site-packages/google&lt;br /&gt;※上記"/usr/local/Python25/lib/python2.5/site-packages/"の部分は、&lt;br /&gt;あなたがお使いのPythonのインストールパスに合わせてください。&lt;br /&gt;&lt;br /&gt;% cd /usr/local/google_appengine/lib/webob&lt;br /&gt;% sudo python setup.py install&lt;br /&gt;% cd /usr/local/google_appengine/lib/yaml&lt;br /&gt;% sudo python setup.py&lt;br /&gt;※djangoをインストールしていない方は、さらに&lt;br /&gt;% cd /usr/local/google_appengine/lib/django&lt;br /&gt;% sudo python setup.py&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;3. 確認&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;% python&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;  from google.appengine.ext import webapp&lt;br /&gt;※このimportで何もエラーがでなければ、OKのようだ。&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; ^D&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4. Hello worldを書く。&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;% mkdir helloworld&lt;br /&gt;% cd helloworld&lt;br /&gt;※ここでこのディレクトリに以下の２ファイルを作成。&lt;br /&gt;% cat helloworld.py&lt;br /&gt;print 'Content-Type: text/plain'&lt;br /&gt;print ''&lt;br /&gt;print 'Hello, world!'&lt;br /&gt;&lt;br /&gt;% cat app.yaml&lt;br /&gt;application: helloworld&lt;br /&gt;version: 1&lt;br /&gt;runtime: python&lt;br /&gt;api_version: 1&lt;br /&gt;&lt;br /&gt;handlers:&lt;br /&gt;- url: /.*&lt;br /&gt;  script: helloworld.py&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;5. hello worldアプリを起動&lt;/b&gt;&lt;br /&gt;先ほどのhelloworldディレクトリ内にいる場合は、その上の階層へ&lt;br /&gt;&lt;pre&gt;% cd ..&lt;/pre&gt;&lt;br /&gt;そして、以下を実行&lt;br /&gt;&lt;pre&gt;ayu@~/work% /usr/local/google_appengine/dev_appserver.py helloworld&lt;br /&gt;Allow dev_appserver to check for updates on startup? (Y/n): n  &lt;br /&gt;※上でdev_appserver.pyのアップデートをするかを聞かれるが、あせってnを選びました。。。&lt;br /&gt;&lt;br /&gt;WARNING  2008-04-09 01:31:55,128 datastore_file_stub.py] Could not read datastore data from /tmp/dev_appserver.datastore&lt;br /&gt;WARNING  2008-04-09 01:31:55,128 datastore_file_stub.py] Could not read datastore data from /tmp/dev_appserver.datastore.history&lt;br /&gt;INFO     2008-04-09 01:31:55,131 dev_appserver_main.py] Running application helloworld on port 8080: http://localhost:8080&lt;/pre&gt;&lt;br /&gt;ここまでできたら、以下のURLをブラウザで開く。&lt;br /&gt;&lt;pre&gt;http://127.0.0.1:8080/&lt;/pre&gt;&lt;br /&gt;これでhello world!が画面に表示されるはず！！！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-86516285357777569?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/86516285357777569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/86516285357777569'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/google-app-engine-sdk.html' title='Google App Engine SDKインストール編'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8833928582659808993</id><published>2008-04-08T13:40:00.002+09:00</published><updated>2008-04-08T13:46:44.233+09:00</updated><title type='text'>MySQL5のFederatedはまだまだ使えないという話</title><content type='html'>&lt;a href="http://bugs.mysql.com/bug.php?id=26697"&gt;Every query to a federated table results in a full scan of MyISAM table.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Federatedエンジンでselect count(*) from ...をすると、いちいちテーブルの全レコードをリモートに送り込むというバグがあるそうで、期待のFederatedであったがまだまだ使い物にはならない。&lt;br /&gt;5.1以上で直すことになると見えるが、現時点ではChange logにその修正の旨は発見できず。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8833928582659808993?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8833928582659808993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8833928582659808993'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/mysql5federated.html' title='MySQL5のFederatedはまだまだ使えないという話'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-7177048915694694056</id><published>2008-04-08T00:52:00.003+09:00</published><updated>2008-04-08T00:59:26.954+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>PythonでLatent semantic analysis</title><content type='html'>&lt;a href="http://www.joesniff.co.uk/projects/latent-semantic-analysis-in-python.html"&gt;Latent Semantic Analysis in Python&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;興味深い。&lt;br /&gt;&lt;br /&gt;【要点】&lt;br /&gt; * TFIDFをベクトルの成分とする。&lt;br /&gt; * scipy のsvdルーチンを使う。（次元が１００万とかになっても大丈夫なんだろうか？Lanczos法のような手法を内部で使っているか？）&lt;br /&gt;&lt;br /&gt;Blogの記事のような、極端に短い内容の記事も大量にあるような文書集合だと、こういった手法でぼかした検索ができるといいのかもしれません。&lt;br /&gt;&lt;br /&gt;でもこういうのは実運用の場合はC++で書くべきと思うよ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-7177048915694694056?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7177048915694694056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7177048915694694056'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/pythonlatent-semantic-analysis.html' title='PythonでLatent semantic analysis'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3432027373201642024</id><published>2008-04-07T11:23:00.001+09:00</published><updated>2008-04-07T11:27:39.079+09:00</updated><title type='text'>optparseのhelp文で改行を生かす方法</title><content type='html'>pythonのoptparseモジュールは便利だが、help文に改行を使ってもうまく表示されない。&lt;br /&gt;解決の参考になるのは&lt;a href="http://groups.google.com/group/comp.lang.python/browse_frm/thread/6df6e6b541a15bc2/09f28e26af0699b1"&gt;ここ&lt;/a&gt;の議論だろう。&lt;br /&gt;以下にそのソースを抜粋。&lt;br /&gt;&lt;pre&gt;import optparse&lt;br /&gt;import textwrap&lt;br /&gt;&lt;br /&gt;class IndentedHelpFormatterWithNL(optparse.IndentedHelpFormatter):&lt;br /&gt;  def format_description(self, description):&lt;br /&gt;    if not description: return ""&lt;br /&gt;    desc_width = self.width - self.current_indent&lt;br /&gt;    indent = " "*self.current_indent&lt;br /&gt;    bits = description.split('\n')&lt;br /&gt;    formatted_bits = [&lt;br /&gt;      textwrap.fill(bit,&lt;br /&gt;        desc_width,&lt;br /&gt;        initial_indent=indent,&lt;br /&gt;        subsequent_indent=indent)&lt;br /&gt;      for bit in bits]&lt;br /&gt;    result = "\n".join(formatted_bits) + "\n"&lt;br /&gt;    return result&lt;br /&gt;&lt;br /&gt;  def format_option(self, option):&lt;br /&gt;    """&lt;br /&gt;     The help for each option consists of two parts:&lt;br /&gt;       * the opt strings and metavars&lt;br /&gt;       eg. ("-x", or "-fFILENAME, --file=FILENAME")&lt;br /&gt;       * the user-supplied help string&lt;br /&gt;       eg. ("turn on expert mode", "read data from FILENAME")&lt;br /&gt;    &lt;br /&gt;     If possible, we write both of these on the same line:&lt;br /&gt;       -x    turn on expert mode&lt;br /&gt;    &lt;br /&gt;     But if the opt string list is too long, we put the help&lt;br /&gt;     string on a second line, indented to the same column it would&lt;br /&gt;     start in if it fit on the first line.&lt;br /&gt;       -fFILENAME, --file=FILENAME&lt;br /&gt;           read data from FILENAME&lt;br /&gt;    """&lt;br /&gt;    result = []&lt;br /&gt;    opts = self.option_strings[option]&lt;br /&gt;    opt_width = self.help_position - self.current_indent - 2&lt;br /&gt;    if len(opts) &amp;gt; opt_width:&lt;br /&gt;      opts = "%*s%s\n" % (self.current_indent, "", opts)&lt;br /&gt;      indent_first = self.help_position&lt;br /&gt;    else: # start help on same line as opts&lt;br /&gt;      opts = "%*s%-*s  " % (self.current_indent, "", opt_width, opts)&lt;br /&gt;      indent_first = 0&lt;br /&gt;    result.append(opts)&lt;br /&gt;    if option.help:&lt;br /&gt;      help_text = self.expand_default(option)&lt;br /&gt;      help_lines = []&lt;br /&gt;      for para in help_text.split("\n"):&lt;br /&gt;        help_lines.extend(textwrap.wrap(para, self.help_width))&lt;br /&gt;      result.append("%*s%s\n" % (&lt;br /&gt;        indent_first, "", help_lines[0]))&lt;br /&gt;      result.extend(["%*s%s\n" % (self.help_position, "", line)&lt;br /&gt;        for line in help_lines[1:]])&lt;br /&gt;    elif opts[-1] != "\n":&lt;br /&gt;      result.append("\n")&lt;br /&gt;    return "".join(result)&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    parser = optparse.OptionParser(&lt;br /&gt;      formatter=IndentedHelpFormatterWithNL(),&lt;br /&gt;      usage=u"""....""")&lt;br /&gt;    ....&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3432027373201642024?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3432027373201642024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3432027373201642024'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/optparsehelp.html' title='optparseのhelp文で改行を生かす方法'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8088045507999595733</id><published>2008-04-05T18:14:00.002+09:00</published><updated>2008-04-05T18:16:41.154+09:00</updated><title type='text'>「ケータイマルチキャリア高機能テスター」を使ってみるよ。</title><content type='html'>&lt;a href="http://p1.netfarm.ne.jp/"&gt;ケータイマルチキャリア高機能テスター P1エミュレーター&lt;/a&gt;&lt;br /&gt;を使ってみる事にした。&lt;br /&gt;&lt;br /&gt;ほとんどの最近のケータイのエミュレーターになるそうで、携帯用サイトの作成に役立ちそうです。&lt;br /&gt;&lt;br /&gt;これで&lt;a href="http://www.tektek.in/d/tk/"&gt;TekTek&lt;/a&gt;のi-mode版、SB版も作ってみることにしよう。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8088045507999595733?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8088045507999595733'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8088045507999595733'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/blog-post.html' title='「ケータイマルチキャリア高機能テスター」を使ってみるよ。'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-2869792942634463695</id><published>2008-04-04T00:43:00.004+09:00</published><updated>2008-04-04T00:50:19.344+09:00</updated><title type='text'>Amazon.comから尻を叩かれた話</title><content type='html'>&lt;a href="http://www.tektek.in/d/tk/"&gt;TekTek&lt;/a&gt;を作った時に、米国のAmazon.comのアフィリエイトにも加入したのだが、今日、そのAmazon.comから「売り上げが上がってないぞ！」ということをやんわりと伝えるメールが来た。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Hello Associate,&lt;br /&gt;We noticed that you were accepted to the Amazon.com Associate Program &lt;br /&gt;several weeks ago but have yet to refer a sale. Here are a few quick &lt;br /&gt;and easy steps to help you get started: &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;訳:&lt;br /&gt;&lt;pre&gt;こんにちは、&lt;br /&gt;数週間前にAmazon.comのアソシエイトプログラムに加入させてあげましたが、&lt;br /&gt;まだ売り上げが上がってないようですねえ。助け舟として、すぐに＆簡単に&lt;br /&gt;できることを教えておきます、、、&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;あ、、、ありがとう、、、。がんばるよ。米国かーーー、、、どうやって宣伝すればいいものか。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-2869792942634463695?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2869792942634463695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2869792942634463695'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/amazoncom.html' title='Amazon.comから尻を叩かれた話'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-7952409765383670901</id><published>2008-04-02T02:17:00.003+09:00</published><updated>2008-04-02T03:10:47.567+09:00</updated><title type='text'>TekTekモバイル for EZwebをオープンしました！</title><content type='html'>&lt;a href="http://www.tektek.in"&gt;TekTek&lt;/a&gt;のモバイル版&lt;a href="http://www.tektek.in/d/tk/m/"&gt;TekTek mobile for EZweb&lt;/a&gt;をオープンしました。&lt;br /&gt;今の所はEZwebのまあここ２〜３年ぐらいの機種のみ対応です。（古い機種での動作は確認していませんので保証できません。）&lt;br /&gt;&lt;br /&gt;URLは以下になります。&lt;br /&gt;http://www.tektek.in/d/tk/m/　　　→  &lt;a href="http://www.tektek.in/d/tk/m/"&gt;TekTek mobile for EZweb&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.tektek.in"&gt;TekTek&lt;/a&gt;を最初に作ろうと思った動機が、本屋で本を選ぶ時にAmazonの書評と評価点数をすばやく見たいからでした。&lt;br /&gt;また、場合によってはその場で本を買わずに、Amazonに注文して届けてほしいと思う事もあります。&lt;br /&gt;そんな用途を考えて、このモバイル版を作っています。&lt;br /&gt;&lt;br /&gt;今後さらなる機能追加も行って行きますが、これでひとまず自分が使いたい最低ラインに到達です。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-7952409765383670901?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7952409765383670901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7952409765383670901'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/04/tektek-for-ezweb.html' title='TekTekモバイル for EZwebをオープンしました！'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-4899293443348931563</id><published>2008-03-29T14:07:00.003+09:00</published><updated>2008-03-29T14:20:13.982+09:00</updated><title type='text'>TekTekを作った時にお世話になったものリスト＋手のうち公開</title><content type='html'>&lt;a href="http://www.tektek.in"&gt;TekTek&lt;/a&gt;にはまだ今後も追加機能をたくさん考えていますが、ここまででお世話になったものを感謝の気持ちを込めてここに書いておきます。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;デザイン系&lt;/b&gt;&lt;br /&gt;自分は絵心がないので、いろいろな素材にお世話になりました。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.oswd.org/"&gt;Open Source Web Design&lt;/a&gt;&lt;br /&gt;サイトのデザインはここで配布されているオープンソースのデザインを拝借し、それに修正を加えて使用しています。非常に洗練されたものばかりで、すごく助かります。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.pinvoke.com/"&gt;PI Diagona Pack &lt;/a&gt;&lt;br /&gt;アイコンはここから頂きました。すっきりしたかわいいアイコンで、気に入っています。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://sozai.livedoor.biz/archives/50555304.html"&gt;フリー素材　シンプルな吹き出しのイラスト・アイコン &lt;/a&gt;&lt;br /&gt;吹き出し画像をここから頂きました。こういうのを作るのって、絵心がない自分にはなかなかむずかしいんですよ。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://seashore.sourceforge.net/index.php"&gt;Seashore&lt;/a&gt;&lt;br /&gt;画像の編集にはSeashoreというGIMPのMac版を使いました。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;英語&lt;/b&gt;&lt;br /&gt;&lt;a href="http://www.alc.co.jp/"&gt;英辞郎 on the WEB&lt;/a&gt;&lt;br /&gt;英語サイトの制作のためにここで何度も何度も辞書を引いています。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;プログラミング&lt;/b&gt;&lt;br /&gt;開発は全て&lt;a href="http://www.python.org"&gt;Python&lt;/a&gt;とJavascriptで行いましたが、以下のライブラリのお世話になりました。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.djangoproject.jp/"&gt;Django&lt;/a&gt;&lt;br /&gt;WEBアプリのフレームワークとしてDjangoを使いました。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://sourceforge.net/projects/json-py/"&gt;json.py&lt;/a&gt;&lt;br /&gt;JSONの処理にはjson.pyを使っています。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.feedparser.org/"&gt;Universal Feed Parser&lt;/a&gt;&lt;br /&gt;RSSの処理に使いました。このライブラリはすばらしい。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://pyaws.sourceforge.net/"&gt;pyaws&lt;/a&gt;&lt;br /&gt;Amazon Webサービスのラッパーライブラリとして、pyawsを使いました。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.mikage.to/jquery/"&gt;jQuery 開発者向けメモ&lt;/a&gt;&lt;br /&gt;Javascriptのライブラリとして、&lt;a href="http://jquery.com/"&gt;JQuery&lt;/a&gt;を使っていますが、ここのリファレンスなどには大変お世話になりました。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.c6software.com/Products/PopBox/"&gt;PopBox&lt;/a&gt;&lt;br /&gt;書籍画像が飛び出す部分にはPopBoxというライブラリを使用しました。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;API&lt;/b&gt;&lt;br /&gt;各種大手サービスのAPIをふんだんに利用させていただきました。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.amazon.com/E-Commerce-Service-AWS-home-page/b/ref=sc_fe_l_6?ie=UTF8&amp;node=12738641&amp;no=3440661&amp;me=A36L942TSJ2AJA"&gt;Amazon WEBサービス&lt;/a&gt;&lt;br /&gt;これはメインで使用しています。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogsearch.google.co.jp/?hl=en&amp;tab=wb"&gt;Google ブログ検索&lt;/a&gt;&lt;br /&gt;Googleのブログ検索のRSSを使って、&lt;a href="http://www.tektek.in"&gt;TekTek&lt;/a&gt;の書籍紹介画面右のブログ一覧を生成しています。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/apis/ajaxsearch/web.html"&gt;Google Ajax Search API&lt;/a&gt;(+&lt;a href="http://b.hatena.ne.jp"&gt;はてなブックマーク&lt;/a&gt;)&lt;br /&gt;Googleの検索APIを使って、はてなブックマークの検索を行うことで、書籍紹介右の&lt;a href="http://www.tektek.in/d/tk/detail/4101181519/"&gt;注目のレビュー&lt;/a&gt;を表示しています。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-4899293443348931563?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/4899293443348931563'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/4899293443348931563'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/03/tektek_29.html' title='TekTekを作った時にお世話になったものリスト＋手のうち公開'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-187874830443789749</id><published>2008-03-29T12:38:00.003+09:00</published><updated>2008-03-29T12:41:41.748+09:00</updated><title type='text'>TekTekをオープンしました</title><content type='html'>&lt;a href="http://www.tektek.in"&gt;TekTek&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;書評が気になってしょうがない人のための書籍情報閲覧サービス&lt;a href="http://www.tektek.in"&gt;TekTek&lt;/a&gt;をオープンしました。&lt;br /&gt;&lt;br /&gt;こういう全日本＆全世界公開型のサービスを作るのは経験不足ですが、まだいろいろ改善していきたいと思います。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ちなみにPythonとdjangoで作っています。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-187874830443789749?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/187874830443789749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/187874830443789749'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/03/tektek.html' title='TekTekをオープンしました'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-2711800258886290839</id><published>2008-03-12T23:41:00.003+09:00</published><updated>2008-03-12T23:44:25.909+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>djangoのi18nのset_languageリダイレクトビュー</title><content type='html'>またしても国際化ではまった。&lt;br /&gt;&lt;br /&gt;djangoの国際化機能で用意されている、言語選択のビューset_languageは、公式ドキュメントではPOSTで渡すことになっているようだが、これはおそらく開発版での話で、今自分が使っている0.97preの段階ではGETで渡さないといけないようだ。&lt;br /&gt;djangoの開発とその文書への反映速度の速さはすばらしいと思う。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-2711800258886290839?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2711800258886290839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2711800258886290839'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/03/djangoi18nsetlanguage.html' title='djangoのi18nのset_languageリダイレクトビュー'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8457664654682925967</id><published>2008-03-02T13:20:00.003+09:00</published><updated>2008-03-02T13:25:08.367+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>djangoの国際化アプリをOSXで作る時にはまる事。</title><content type='html'>OSXでdjangoの国際化アプリを作る場合、メッセージファイルの作成make-messages.pyでこける。&lt;br /&gt;これはgettextのバージョンが古いから。最新のgettextを入れるとなおる。&lt;br /&gt;gettextのインストールは、&lt;a href="http://homepage.mac.com/matsuan_tamachan/software/"&gt;これ&lt;/a&gt;に従った。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8457664654682925967?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8457664654682925967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8457664654682925967'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/03/djangoosx.html' title='djangoの国際化アプリをOSXで作る時にはまる事。'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3815540085784903517</id><published>2008-03-01T08:22:00.003+09:00</published><updated>2008-03-01T08:29:32.793+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>djangoのgeneric viewsのobject_listでPythonの普通のlistを表示する</title><content type='html'>（以下、あまり詳しく既存の情報を調べず、手元のdjangoのコードを読んで適当に作ったもの。。）&lt;br /&gt;&lt;br /&gt;djangoのgenericviewsのobject_listは便利だが、デフォルトではmodelのレコードしか表示できない。&lt;br /&gt;一般のリストの中身などを表示する場合は、リストオブジェクトを適切にラップしてあげる必要がある。&lt;br /&gt;そういう状況はマッシュアップサイトなどを作っていると、model以外からアイテムリストを取得したりするので、よくありますね。&lt;br /&gt;&lt;br /&gt;以下、そのサンプル。&lt;br /&gt;※get()メソッドでの例外の投げ方はあまり詳しく調べてないので、いい加減です。エラーが出るかも。&lt;br /&gt;※まだpagenationさせて動かしていないので、その辺はこれからテストします。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;from django.views.generic.list_detail import object_list&lt;br /&gt;from django.core.exceptions import ObjectDoesNotExist&lt;br /&gt;    &lt;br /&gt;def list2genericviews(lst):            &lt;br /&gt;    class GenList(list):&lt;br /&gt;        model = "GenList"&lt;br /&gt;        DoesNotExist = ObjectDoesNotExist&lt;br /&gt;        def __init__(self, lst):&lt;br /&gt;            self.extend([{"id": i, "value": x} for i, x in enumerate(lst)])&lt;br /&gt;        def _clone(self):&lt;br /&gt;            return self&lt;br /&gt;        def filter(self, pk=None):&lt;br /&gt;            return self[pk]&lt;br /&gt;        def count(self):&lt;br /&gt;            return len(self)&lt;br /&gt;        def get(self):&lt;br /&gt;            if len(self) == 0:&lt;br /&gt;                raise self.DoesNotExist("No item found in GenList")&lt;br /&gt;            if len(self) &amp;gt; 1:&lt;br /&gt;                raise AssertionError("There are multiple items in GenList")&lt;br /&gt;            return self[0]&lt;br /&gt;    return GenList(lst)&lt;br /&gt;&lt;br /&gt;def show_list(request):&lt;br /&gt;    items = ["apple", "banana", "orange"]&lt;br /&gt;&lt;br /&gt;    #引数template_nameは必須です。&lt;br /&gt;    return object_list(request, queryset=list2genericviews(items), template_name="itemlist.html")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;テンプレートitemlist.htmlはこんな感じ。&lt;br /&gt;&lt;pre&gt;{% if object_list %}&lt;br /&gt;  &amp;lt;ul&amp;gt;&lt;br /&gt;  {% for item in object_list %}&lt;br /&gt;    &amp;lt;li&amp;gt;{{ item.value }}&amp;lt;/li&amp;gt;&lt;br /&gt;  {% endfor %}&lt;br /&gt;  &amp;lt;/ul&amp;gt;&lt;br /&gt;{% endif %}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3815540085784903517?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3815540085784903517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3815540085784903517'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/03/djangogeneric-viewsobjectlistpythonlist.html' title='djangoのgeneric viewsのobject_listでPythonの普通のlistを表示する'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-2260685981451281919</id><published>2008-02-04T01:15:00.000+09:00</published><updated>2008-02-04T01:36:03.924+09:00</updated><title type='text'>Macのある生活 （現実）</title><content type='html'>&lt;a href="http://d.hatena.ne.jp/nbsp/"&gt;Macのある生活&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;こんなにオシャレなMacもしがない三十路独身男性の手にかかると、、、、&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_TlQ68V-OBvk/R6XrjxOSZVI/AAAAAAAAAAM/3SzbE3W2WfA/s1600-h/table.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_TlQ68V-OBvk/R6XrjxOSZVI/AAAAAAAAAAM/3SzbE3W2WfA/s320/table.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5162791547591353682" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;最初はもっと引いて撮ってましたが、あまりにもMacがかわいそうな部屋なので容赦してこの範囲だけ撮影。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-2260685981451281919?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2260685981451281919'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2260685981451281919'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/02/mac.html' title='Macのある生活 （現実）'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_TlQ68V-OBvk/R6XrjxOSZVI/AAAAAAAAAAM/3SzbE3W2WfA/s72-c/table.jpg' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6415572055841372946</id><published>2008-01-29T18:27:00.000+09:00</published><updated>2008-01-29T18:28:50.162+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>mod_pythonでLD_LIBRARY_PATHの設定</title><content type='html'>&lt;a href="http://www.troches.jp/content/view/131/66/"&gt;http://www.troches.jp/content/view/131/66/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;mod_pythonの設定をapacheのhttpd.confに書くときに、SetEnvでLD_LIBRARY_PATHなどを設定しても効き目がないそうだ。&lt;br /&gt;&lt;br /&gt;/etc/init.d/httpd にexport LD_LIBRARY_PATH = ... と書くとよいとのこと。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6415572055841372946?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6415572055841372946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6415572055841372946'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/01/modpythonldlibrarypath.html' title='mod_pythonでLD_LIBRARY_PATHの設定'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-2879339476617501867</id><published>2008-01-29T17:01:00.000+09:00</published><updated>2008-01-29T18:35:57.974+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>ハイフンっぽい文字を一括で半角マイナスに変換</title><content type='html'>元ネタはこちら。 &lt;a href="http://d.hatena.ne.jp/koseki2/20070927/unicodehyphen"&gt;http://d.hatena.ne.jp/koseki2/20070927/unicodehyphen&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;hihuns = (u"\u002d", u"\u2212", u"\uff0d", u"\u30fc", &lt;br /&gt;    u"\u2012", u"\u2013", u"\u2014", u"\u2015", u"\u2500")&lt;br /&gt;def to_han_hihun(s):&lt;br /&gt;        for x in hihuns:&lt;br /&gt;                s = s.replace(x, u"-")&lt;br /&gt;        return s&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-2879339476617501867?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2879339476617501867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2879339476617501867'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/01/blog-post_29.html' title='ハイフンっぽい文字を一括で半角マイナスに変換'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-7870044915612324243</id><published>2008-01-28T11:07:00.000+09:00</published><updated>2008-01-28T11:09:33.906+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]djangoのnewformsで半角英数のみのフィールド</title><content type='html'>以下のような感じでCharFieldを定義すると一応できるが、作法的にOKなのだろうか。&lt;br /&gt;なんかいちいちこういう書式の制限を書かなければならないわけはないと思うのでもっと簡単な方法があるはずじゃないかなあ。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;class AsciiCharField(forms.CharField):&lt;br /&gt;    def clean(self, value):&lt;br /&gt;        if not re.match(ur"^[A-Za-z0-9_\-\.]+$", value):&lt;br /&gt;            raise forms.ValidationError(u'半角英数字のみを使用してください。')&lt;br /&gt;        return forms.CharField.clean(self, value)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-7870044915612324243?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7870044915612324243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7870044915612324243'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/01/djangonewforms.html' title='[メモ]djangoのnewformsで半角英数のみのフィールド'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8308963131747939587</id><published>2008-01-24T11:26:00.000+09:00</published><updated>2008-01-24T11:35:33.368+09:00</updated><title type='text'>[メモ]シェルでファイル名を数字でソート（２桁まで）</title><content type='html'>２桁までの数字のついたファイルfile**.txtをgrepしたい。ただし、ファイルについている番号順にgrepをかけていきたい。&lt;br /&gt;そういう場合は、ワイルドカード{?,??}を使うと、数字順にソートした上で処理できる。(1の次が10にならないようにソートできる。）&lt;br /&gt;&lt;pre&gt;grep searchword file{?,??}.txt&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ただし、lsコマンドでファイル一覧を表示する場合は、lsコマンドがデフォルトで名前でのソートを行うので、-vをつけないといけない。&lt;br /&gt;&lt;pre&gt;[ayu@home]~/tmp% ls -l -v file{?,??}.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file1.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file2.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file3.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file4.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file5.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file6.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file7.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file8.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file9.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file10.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file11.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file12.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file13.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file14.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file15.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file16.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file17.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file18.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file19.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file20.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file21.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file22.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file23.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file24.txt&lt;br /&gt;-rw-r--r--  1 ayu ayu 0 Jan 24 11:28 file25.txt&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8308963131747939587?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8308963131747939587'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8308963131747939587'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/01/blog-post_24.html' title='[メモ]シェルでファイル名を数字でソート（２桁まで）'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-9013630754784469179</id><published>2008-01-22T13:06:00.000+09:00</published><updated>2008-01-22T13:08:46.062+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]djangoからloggingを使う場合のタイムゾーンはsettings.TIME_ZONEで決まる</title><content type='html'>djangoのsettings.pyのTIME_ZONEはいつも適当にデフォルトで放置していましたが、loggingモジュールでログを出力する場合のタイムゾーン設定として、きちんと効いているので、ちゃんと以下のように書こう。&lt;br /&gt;&lt;pre&gt;TIME_ZONE = 'Asia/Tokyo'&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-9013630754784469179?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/9013630754784469179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/9013630754784469179'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/01/djangologgingsettingstimezone.html' title='[メモ]djangoからloggingを使う場合のタイムゾーンはsettings.TIME_ZONEで決まる'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6220026823816018207</id><published>2008-01-20T02:18:00.000+09:00</published><updated>2008-01-20T02:34:27.824+09:00</updated><title type='text'>[日記]過去の認識</title><content type='html'>&lt;a href="http://workingnews.blog117.fc2.com/blog-entry-616.html"&gt;リアル84歳だけど質問ある？&lt;/a&gt;&lt;br /&gt;興味深い。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;506 名前：以下、名無しにかわりましてVIPがお送りします。：2008/01/16(水) 18:20:49.46 ID:gixHjhq+0&lt;br /&gt;    ヒトラーとムッソリーニはどう思った？&lt;br /&gt;&lt;br /&gt;    &gt;&gt;506&lt;br /&gt;    ヒトラーはドイツの首相だな&lt;br /&gt;    若い人にはわかりにくい感覚だと思うが聞いてくれ&lt;br /&gt;    当時は今みたいに情報がなかった&lt;br /&gt;    だから、ただ日本の友好国の首相だとしか思ってなかった&lt;br /&gt;    ユダヤ人の虐殺とかもあまり知らなかった&lt;br /&gt;    ただ、ヒトラーはあの人なりに正しいことをしようとしただけだと思うよ&lt;br /&gt;    今のアメリカとイラクだってそうだ&lt;br /&gt;    お互いに正しいと思ったことをやってるだけだ&lt;br /&gt;    後から、あの人は悪い人って決めつけるのは簡単だけど、特別ヒトラーが悪人だとは思わんよ&lt;br /&gt;    真面目過ぎるとは思うけど  &lt;br /&gt;&lt;br /&gt;517 名前：84 ◆5HOOEYijHo ：2008/01/16(水) 18:34:05.69 ID:W45St2r1O&lt;br /&gt;    続き&lt;br /&gt;    若い人の中には戦争に否定的な人も多いし、戦争に関わった人を憎む人も多いね&lt;br /&gt;    気持もわかる&lt;br /&gt;    でも、今の生活や政治や平和も戦争の過去があるからある&lt;br /&gt;    軍人に感謝しろなんて言う馬鹿な老人にはなりたくないが、当時の人もみんな真面目に家族や国の平和を&lt;br /&gt;　　願っていたんだよ&lt;br /&gt;    ただ勝ち負けがあるだけで&lt;br /&gt;    だから、過去を知ることは大切だけど、60年も昔のことを憎むのは馬鹿らしいことだ &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6220026823816018207?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6220026823816018207'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6220026823816018207'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/01/blog-post.html' title='[日記]過去の認識'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-402787797020045269</id><published>2008-01-11T12:29:00.000+09:00</published><updated>2008-01-11T12:30:38.830+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]PILの良サンプル</title><content type='html'>&lt;a href="http://return0.dyndns.org/t/smg/"&gt;サンボマスタージェネレーター&lt;/a&gt;の&lt;a href="http://return0.dyndns.org/t/smg/generator.py"&gt;ソース&lt;/a&gt;はPILのサンプルとしてとてもバランスがよい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-402787797020045269?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/402787797020045269'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/402787797020045269'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/01/pil.html' title='[メモ]PILの良サンプル'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-7444347083288603433</id><published>2008-01-04T10:27:00.000+09:00</published><updated>2008-01-04T10:28:45.613+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scheme'/><title type='text'>[メモ]TODO: プログラミングGaucheを入手すること</title><content type='html'>&lt;a href="http://ssl.ohmsha.co.jp/cgi-bin/menu.cgi?&amp;ISBN=978-4-87311-348-7"&gt;書籍 -- プログラミングGauche&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2008年2月発売予定との事。非常に待ち遠しい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-7444347083288603433?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7444347083288603433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7444347083288603433'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/01/todo-gauche.html' title='[メモ]TODO: プログラミングGaucheを入手すること'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-5000043816898272437</id><published>2008-01-04T00:28:00.000+09:00</published><updated>2008-01-04T00:39:26.812+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scheme'/><title type='text'>Gaucheが相当に"電池内蔵"という話</title><content type='html'>自分がPythonを使えるようになって思い上がっているのをいさめるために始めたSchemeの練習を今年も続けて行こうと思います。&lt;br /&gt;帰省から帰ってきたら自分が年末に書いたコードすら読めなくなっててびびりましたが。&lt;br /&gt;&lt;br /&gt;先日ここに書いた（汚い）ソースに、Gaucheの作者様から直々に添削を頂きました！ありがとうございます！本当にありがとうございます。感激しております！&lt;br /&gt;&lt;br /&gt;そこでまずは、以下の二点を勉強しつつ修正してみた。&lt;br /&gt; * デフォルト値つきのassoc -&amp;gt; util.listのassoc-ref&lt;br /&gt; * Pythonで言うgroupby -&amp;gt; gauche.collectionのgroup-collection&lt;br /&gt;&lt;br /&gt;さらにそのコメントにはパフォーマンスを考慮した工夫や、末尾再帰を簡易に書くヒントまでも頂いておりますが、そこは一晩寝てから続きをします。&lt;br /&gt;&lt;br /&gt;ありがとうございます！&lt;br /&gt;&lt;br /&gt;（上記二点による修正で、コードの行数が100行 -&amp;gt; 78行に激減！）&lt;br /&gt;&lt;pre&gt;;; coding: utf-8&lt;br /&gt;(use mecab)&lt;br /&gt;(use srfi-1)&lt;br /&gt;(use srfi-13)&lt;br /&gt;(use gauche.collection)&lt;br /&gt;(use util.list)&lt;br /&gt;&lt;br /&gt;;;名詞の列を抽出する関数&lt;br /&gt;(define (takenowns node)&lt;br /&gt;  (let impl ((node node) (buf '()) (ans '()))&lt;br /&gt;  (if (mecab-node-null? node) &lt;br /&gt;      (if (null? buf) ans (append ans (list buf)))&lt;br /&gt;      (if (string-prefix? "名詞" (mecab-node-feature node))&lt;br /&gt;   (impl (mecab-node-next node) (append buf (list (mecab-node-surface node))) ans)&lt;br /&gt;   (impl (mecab-node-next node) '() (if (null? buf) ans (append ans (list buf))))))))&lt;br /&gt;   &lt;br /&gt;(define (countgroup data)&lt;br /&gt;  (define (iter data buf)&lt;br /&gt;    (if (null? data)&lt;br /&gt; buf&lt;br /&gt; (if (null? (car data))&lt;br /&gt;     (iter (cdr data) buf)&lt;br /&gt;     (iter (cdr data) (cons (cons (car (car data)) (length (car data))) buf)))))&lt;br /&gt;  (reverse (iter data '())))&lt;br /&gt;&lt;br /&gt;(define (has l n)&lt;br /&gt;  (cond ((zero? n) #t)&lt;br /&gt; ((pair? l) (has (cdr l) (- n 1)))&lt;br /&gt; (#t #f)))&lt;br /&gt;&lt;br /&gt;;; bigram生成関数&lt;br /&gt;(define (bigram data)&lt;br /&gt;  (define (iter data buf)&lt;br /&gt;    (if (has data 2)&lt;br /&gt; (iter (cdr data) (cons (list (car data) (cadr data)) buf))&lt;br /&gt; buf))&lt;br /&gt;  (iter data '()))&lt;br /&gt;&lt;br /&gt;(define (count-bigram data keyf)&lt;br /&gt;  (map (lambda (x) (cons (car x) (length x)))  &lt;br /&gt;       (group-collection (map keyf data) :test equal?)))&lt;br /&gt;&lt;br /&gt;;;スコア計算式&lt;br /&gt;(define (calc-score word all left right)&lt;br /&gt;  (* (assoc-ref all (string-join word) 1.0)&lt;br /&gt;     (expt &lt;br /&gt;      (let loop ((restword word) (weight 1.0))&lt;br /&gt;   (if (null? restword)&lt;br /&gt;       weight&lt;br /&gt;       (loop (cdr restword) &lt;br /&gt;      (* weight (+ 1 (assoc-ref left (car restword) 0))&lt;br /&gt;         (+ 1 (assoc-ref right (car restword) 0))))))&lt;br /&gt;      (/ 1 (* 2 (length word))))))&lt;br /&gt;&lt;br /&gt;;;複合語抽出メイン関数&lt;br /&gt;(define (calc-mword mecabobj body)&lt;br /&gt;  (let* ((words (takenowns &lt;br /&gt;  (mecab-sparse-tonode mecabobj body)))&lt;br /&gt;  (tandoku-hindo (countgroup (group-collection words :test equal?)))&lt;br /&gt;  (uniq-bigram &lt;br /&gt;   (map car &lt;br /&gt;        (group-collection (concatenate (map bigram words)) :test equal?)))&lt;br /&gt;  (left-hindo (count-bigram uniq-bigram cadr))&lt;br /&gt;  (right-hindo (count-bigram uniq-bigram car))&lt;br /&gt;  (tandoku-hindo-map (map (lambda (x) (cons (string-join (car x)) (cdr x))) tandoku-hindo)))&lt;br /&gt;    (sort &lt;br /&gt;     (map &lt;br /&gt;      (lambda (x) (cons (string-join (car x)) (calc-score (car x) tandoku-hindo-map left-hindo right-hindo))) &lt;br /&gt;      tandoku-hindo)&lt;br /&gt;     (lambda (a b) (&amp;gt; (cdr a) (cdr b))))))&lt;br /&gt;&lt;br /&gt;(define m (mecab-new2 ""))&lt;br /&gt;&lt;br /&gt;(time  (map print (calc-mword m&lt;br /&gt;      "日本ハムが来秋のドラフト上位候補に、ホンダの長野（ちょうの）久義外野手（２３）＝日大出＝&lt;br /&gt;をリストアップしていることが２７日、分かった。昨年１１月の大学生・社会人ドラフトで４巡目指名しな&lt;br /&gt;がら入団拒否された“恋人”に、再度アタックする。　１度フラれても、あきらめきれない。日本ハムが再&lt;br /&gt;び、長野の獲得に向けて動いている。「去年は（入団を）断られたけど、今年１年見て順調にきている。改&lt;br /&gt;めて推薦したい選手の１人」と球団関係者。“恋人”の高評価は変わらない。　２年越しのラブコールだ。&lt;br /&gt;日本ハムは、昨年のドラフトで巨人入りを志望していた長野（当時日大）を大学生・社会人ドラフト４巡目&lt;br /&gt;で強行指名。だが、希望球団でないことを理由に入団を断られた。　その後、長野は社会人のホンダへ進&lt;br /&gt;み、１年目から外野の定位置を獲得。３月の社会人東京大会で新人賞を受賞し、日本代表として出場した&lt;br /&gt;１１月のワールド杯（台湾）ではチーム最高打率（．４５７）をマーク。０７年の社会人野球ベストナイン&lt;br /&gt;にも選出された。来秋のドラフトでは上位指名確実の逸材だ。　入団拒否後も、日本ハムの担当スカウトが&lt;br /&gt;再度の獲得へ向けて誠意をみせている。関係者を通じて、巨人オンリーだった長野の心変わりをキャッチし&lt;br /&gt;た。指名を拒否されながら、再び指名するのは過去数例（別項）あるが、極めて異例だ。「来年も（長野&lt;br /&gt;を）注目していきたい」と球団関係者。熱い思いが届く日まで、密着マークする。")))&lt;br /&gt;&lt;br /&gt;(mecab-destroy m)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-5000043816898272437?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/5000043816898272437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/5000043816898272437'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2008/01/gauche.html' title='Gaucheが相当に&quot;電池内蔵&quot;という話'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-9107190114633833800</id><published>2007-12-29T16:37:00.000+09:00</published><updated>2007-12-29T22:07:56.043+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='scheme'/><title type='text'>末尾再帰重要</title><content type='html'>非常に貴重な突っ込みをいただきました。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://d.hatena.ne.jp/odz/20071229/1198902456#c"&gt;odz buffer -- [Python][Scheme]tail call&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;教訓&lt;br /&gt; * 時々は末尾再帰を意識して書こう。（特にこういう頻繁に呼び出す関数では。）&lt;br /&gt; * lengthは遅い。（リストをつらつらたどって毎回計算するのかな？）&lt;br /&gt; * Gaucheは関数の再帰呼び出しでスタックを使い尽くすとヒープに移す。ただしそうなるとちょっと遅くはなるかも。&lt;br /&gt; * Pythonはやはり配列の添字番号をうまく使い、ジェネレーターを活かすと吉。&lt;br /&gt; * Pythonのrange関数は、schemeではsrfi-1のiota&lt;br /&gt;&lt;br /&gt;ほんとうにたすかります。ありがとうございます。&lt;br /&gt;でも、このツッコミで示された最速の関数bigram3を読み解けないという悲しい状況。がんばって読もうと思います。&lt;br /&gt;&lt;br /&gt;追記-------&lt;br /&gt;bigram3理解できました。&lt;br /&gt;同様の方針でこれまで自分が書いていた他の関数も末尾再帰になるようにしてみたりした。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-9107190114633833800?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/9107190114633833800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/9107190114633833800'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/12/blog-post.html' title='末尾再帰重要'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-9190072235621169341</id><published>2007-12-29T15:22:00.000+09:00</published><updated>2007-12-29T16:32:44.303+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scheme'/><title type='text'>Schemeで重要語抽出を書いた感想</title><content type='html'>重要語抽出をSchemeで書いてみて、一応できたのだけど、ソースが汚い。だれか添削してくれないものだろうか。&lt;br /&gt;つい数時間前にsrfiのマニュアルを初めて見ていろいろとがっくり来た。（というぐらい低レベルな自分）&lt;br /&gt;&lt;br /&gt;今リファクタリングを重ねながら、思い知らされるのはやはり自分の今のSchemeの低レベルぶりだ。&lt;br /&gt;&lt;br /&gt;他の要因として、Pythonだと細かい気の利いた標準関数、メソッドなどがあらかじめ用意されているが、Schemeの標準は自由度を尊重(というか「各自自力で」推奨？)しているためPythonほどガチガチではないから、そういうのを自分で書かないといけないというのもあるんじゃなかろうか。&lt;br /&gt;&lt;br /&gt;Pythonのdictのgetメソッドがデフォルト値を指定できたり、itertoolsのgroupbyとかは地味に便利だが、Schemeの場合はそういうのは自分で用意しないといけない。&lt;br /&gt;&lt;br /&gt;以下、その汚いソース。アルゴリズムは毎度のことながら&lt;a href="http://gensen.dl.itc.u-tokyo.ac.jp/"&gt;http://gensen.dl.itc.u-tokyo.ac.jp/&lt;/a&gt;から拝借。&lt;br /&gt;mecabへの接続には、&lt;a href="http://hiroshiykw.blogspot.com/2007/12/schememecab.html"&gt;先日書いたやつ&lt;/a&gt;を使用した。&lt;br /&gt;let*を使っている部分から&lt;a href="http://practical-scheme.net/wiliki/wiliki.cgi?Scheme%3AScheme%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%81%AE%E3%83%AC%E3%83%99%E3%83%AB10"&gt;レベル２&lt;/a&gt;の匂いが。&lt;br /&gt;&lt;pre&gt;;; coding: utf-8&lt;br /&gt;(use mecab)&lt;br /&gt;(use srfi-1)&lt;br /&gt;(use srfi-13)&lt;br /&gt;&lt;br /&gt;;;名詞の列を抽出する関数&lt;br /&gt;(define (takenowns node)&lt;br /&gt;  (let impl ((node node) (buf '()) (ans '()))&lt;br /&gt;  (if (mecab-node-null? node) &lt;br /&gt;      (if (null? buf) ans (append ans (list buf)))&lt;br /&gt;      (if (string-prefix? "名詞" (mecab-node-feature node))&lt;br /&gt;   (impl (mecab-node-next node) (append buf (list (mecab-node-surface node))) ans)&lt;br /&gt;   (impl (mecab-node-next node) '() (if (null? buf) ans (append ans (list buf))))))))&lt;br /&gt;&lt;br /&gt;;;文字列のリストの比較関数&lt;br /&gt;(define (compare-string x y) (if (and (null? x) (null? y)) #t &lt;br /&gt;    (if (null? x) #t&lt;br /&gt;        (if (null? y) #f&lt;br /&gt;     (if (eq? (car x) (car y))&lt;br /&gt;         (comp (cdr x) (cdr y))&lt;br /&gt;         (string&amp;lt;? (car x) (car y)))))))&lt;br /&gt;   &lt;br /&gt;(define (groupby data eqfunc)&lt;br /&gt;  (let impl ((data data) (buf '()) (ans '()))&lt;br /&gt;    (if (null? data) &lt;br /&gt; (if (null? buf) ans (append ans (list buf)))&lt;br /&gt; (let ((head (car data)) (tail (cdr data)))&lt;br /&gt;   (if (null? buf) &lt;br /&gt;       (impl tail (list head) ans)&lt;br /&gt;       (if (eqfunc (car buf) head)&lt;br /&gt;    (impl tail (append buf (list head)) ans)&lt;br /&gt;    (impl tail (list head) (append ans (list buf)))))))))&lt;br /&gt;&lt;br /&gt;(define (countgroup data)&lt;br /&gt;  (if (null? data) &lt;br /&gt;      '()&lt;br /&gt;      (if (null? (car data))&lt;br /&gt;   (countgroup (cdr data))&lt;br /&gt;   (cons (cons (car (car data)) (length (car data)))&lt;br /&gt;  (countgroup (cdr data))))))&lt;br /&gt;&lt;br /&gt;;; bigram生成関数&lt;br /&gt;(define (bigram data)&lt;br /&gt;  (if (&amp;lt; (length data) 2) &lt;br /&gt;      '()&lt;br /&gt;      (cons (list (car data) (cadr data)) (bigram (cdr data)))))   &lt;br /&gt;&lt;br /&gt;(define (count-bigram data keyf)&lt;br /&gt;  (map (lambda (x) (cons (car x) (length x)))  &lt;br /&gt;       (groupby (sort (map keyf data) string&amp;lt;?) equal?)))&lt;br /&gt;&lt;br /&gt;;;デフォルト値付きのassoc&lt;br /&gt;(define (defassoc k ary d)&lt;br /&gt;  (let ((a (assoc k ary)))&lt;br /&gt;    (if (eq? #f a) d (cdr a))))&lt;br /&gt;&lt;br /&gt;;;スコア計算式&lt;br /&gt;(define (calc-score word all left right)&lt;br /&gt;  (* (defassoc (string-join word) all 1.0)&lt;br /&gt;     (expt &lt;br /&gt;      (let loop ((restword word) (weight 1.0))&lt;br /&gt;   (if (null? restword)&lt;br /&gt;       weight&lt;br /&gt;       (loop (cdr restword) &lt;br /&gt;      (* weight (+ 1 (defassoc (car restword) left 0))&lt;br /&gt;         (+ 1 (defassoc (car restword) right 0))))))&lt;br /&gt;      (/ 1 (* 2 (length word))))))&lt;br /&gt;&lt;br /&gt;;;複合語抽出メイン関数&lt;br /&gt;(define (calc-mword mecabobj body)&lt;br /&gt;  (let* ((words (takenowns &lt;br /&gt;  (mecab-sparse-tonode mecabobj body)))&lt;br /&gt;  (tandoku-hindo (countgroup (groupby (sort words compare-string) equal?)))&lt;br /&gt;  (uniq-bigram &lt;br /&gt;   (map car &lt;br /&gt;        (groupby (sort (concatenate (map bigram words)) compare-string) equal?)))&lt;br /&gt;  (left-hindo (count-bigram uniq-bigram cadr))&lt;br /&gt;  (right-hindo (count-bigram uniq-bigram car))&lt;br /&gt;  (tandoku-hindo-map (map (lambda (x) (cons (string-join (car x)) (cdr x))) tandoku-hindo)))&lt;br /&gt;    (sort &lt;br /&gt;     (map &lt;br /&gt;      (lambda (x) (cons (string-join (car x)) (calc-score (car x) tandoku-hindo-map left-hindo right-hindo))) &lt;br /&gt;      tandoku-hindo)&lt;br /&gt;     (lambda (a b) (&amp;gt; (cdr a) (cdr b))))))&lt;br /&gt;&lt;br /&gt;(define m (mecab-new2 ""))&lt;br /&gt;&lt;br /&gt;(map print  (calc-mword m&lt;br /&gt;      "日本ハムが来秋のドラフト上位候補に、ホンダの長野（ちょうの）久義外野手（２３）＝日大出＝を&lt;br /&gt;リストアップしていることが２７日、分かった。昨年１１月の大学生・社会人ドラフトで４巡目指名しなが&lt;br /&gt;ら入団拒否された“恋人”に、再度アタックする。　１度フラれても、あきらめきれない。日本ハムが再&lt;br /&gt;び、長野の獲得に向けて動いている。「去年は（入団を）断られたけど、今年１年見て順調にきている。改&lt;br /&gt;めて推薦したい選手の１人」と球団関係者。“恋人”の高評価は変わらない。　２年越しのラブコールだ。&lt;br /&gt;日本ハムは、昨年のドラフトで巨人入りを志望していた長野（当時日大）を大学生・社会人ドラフト４巡目&lt;br /&gt;で強行指名。だが、希望球団でないことを理由に入団を断られた。　その後、長野は社会人のホンダへ進&lt;br /&gt;み、１年目から外野の定位置を獲得。３月の社会人東京大会で新人賞を受賞し、日本代表として出場した&lt;br /&gt;１１月のワールド杯（台湾）ではチーム最高打率（．４５７）をマーク。０７年の社会人野球ベストナイン&lt;br /&gt;にも選出された。来秋のドラフトでは上位指名確実の逸材だ。　入団拒否後も、日本ハムの担当スカウトが&lt;br /&gt;再度の獲得へ向けて誠意をみせている。関係者を通じて、巨人オンリーだった長野の心変わりをキャッチし&lt;br /&gt;た。指名を拒否されながら、再び指名するのは過去数例（別項）あるが、極めて異例だ。「来年も（長野&lt;br /&gt;を）注目していきたい」と球団関係者。熱い思いが届く日まで、密着マークする。"))&lt;br /&gt;&lt;br /&gt;(mecab-destroy m)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;実行結果&lt;br /&gt;&lt;pre&gt;ayu@~/work/Gauche-mecab% gosh sample.scm | nkf -e | head -n 20&lt;br /&gt;(長野 . 6.0)&lt;br /&gt;(指名 . 5.656854249492381)&lt;br /&gt;(ドラフト . 4.898979485566356)&lt;br /&gt;(日本ハム . 4.0)&lt;br /&gt;(球団 関係 者 . 3.563594872561357)&lt;br /&gt;(１ 人 . 3.309750919646873)&lt;br /&gt;(１ 年 目 . 3.1072325059538586)&lt;br /&gt;(獲得 . 3.0)&lt;br /&gt;(入団 . 2.8284271247461903)&lt;br /&gt;(０ ７ 年 . 2.6671682753399955)&lt;br /&gt;(今年 １ 年 . 2.5873402367724454)&lt;br /&gt;(４ ５ ７ . 2.5697965868506505)&lt;br /&gt;(４ 巡 目 指名 . 2.413690382068065)&lt;br /&gt;(社会 人 ドラフト . 2.2894284851066637)&lt;br /&gt;(社会 人 ドラフト ４ 巡 目 . 2.2894284851066637)&lt;br /&gt;(２ 年 越し . 2.220906154852325)&lt;br /&gt;(社会 人 . 2.2133638394006434)&lt;br /&gt;(上位 指名 確実 . 2.1398263878673256)&lt;br /&gt;(２ ７ 日 . 2.1398263878673256)&lt;br /&gt;(１ 度 フラ . 2.075781631112427)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-9190072235621169341?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/9190072235621169341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/9190072235621169341'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/12/scheme_29.html' title='Schemeで重要語抽出を書いた感想'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8375136432510030519</id><published>2007-12-29T09:11:00.000+09:00</published><updated>2007-12-29T09:16:51.153+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scheme'/><title type='text'>[日記]Schemeのレベル</title><content type='html'>&lt;a href="http://practical-scheme.net/wiliki/wiliki.cgi?Scheme%3AScheme%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%81%AE%E3%83%AC%E3%83%99%E3%83%AB10"&gt;私家版、Schemeプログラマのレベル10&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;SICPの&lt;a href="http://www.shido.info/lisp/scheme_amb.html"&gt;amb&lt;/a&gt;で挫折している自分はレベル4に踏み込んだばかりのレベルだ。&lt;br /&gt;レベル４の「クロージャーうんぬん」はPythonを使っていて自然に身に付いたおかげで、今とても助かっているんだなあと再認識。&lt;br /&gt;&lt;br /&gt;きっとambを使いこなせるようになれば、今会社で書いている複雑なPythonのプログラムもずいぶんすっきり書けるんだろうなあ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8375136432510030519?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8375136432510030519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8375136432510030519'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/12/scheme.html' title='[日記]Schemeのレベル'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-2628935805088475767</id><published>2007-12-29T08:36:00.000+09:00</published><updated>2007-12-29T09:00:56.076+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='scheme'/><title type='text'>[メモ]再帰を使うとn-gramはすっきり書ける</title><content type='html'>例として、bigramを生成する関数。&lt;br /&gt;&lt;br /&gt;再帰を使わないバージョン(Python)&lt;br /&gt;&lt;pre&gt;def bigram(data):&lt;br /&gt;    if len(data) &lt; 2:&lt;br /&gt;        return&lt;br /&gt;    prev = data[0]&lt;br /&gt;    for x in data[1:]:&lt;br /&gt;        yield [prev, x]&lt;br /&gt;        prev = x&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;再帰を使ったバージョン(Scheme)&lt;br /&gt;&lt;pre&gt;(define (bigram data)&lt;br /&gt;  (if (&lt; (length data) 2) &lt;br /&gt;      '()&lt;br /&gt;      (cons (list (car data) (cadr data)) (bigram (cdr data)))))   &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pythonだと再帰の深さの制限があるので、このような書き方はできませんが。&lt;br /&gt;補: 念のためやってみた。&lt;br /&gt;&lt;pre&gt;def bigram2(data):&lt;br /&gt;    if len(data) &lt; 2:&lt;br /&gt;        return []&lt;br /&gt;    return [[data[0], data[1]],] + bigram2(data[1:])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;↑Pythonでこう書ければいいんだけど、すぐに"maximum recursion depth exceeded"になるよ。&lt;br /&gt;&lt;br /&gt;補: 実際にschemeでエラーにならないことも確認。&lt;br /&gt;&lt;pre&gt;(define (bigram data)&lt;br /&gt;  (if (&lt; (length data) 2) &lt;br /&gt;      '()&lt;br /&gt;      (cons (list (car data) (cadr data)) (bigram (cdr data)))))   &lt;br /&gt;&lt;br /&gt;(define (range x)&lt;br /&gt;  (let loop ((ini 0))&lt;br /&gt;    (if (= ini x)&lt;br /&gt; '()&lt;br /&gt; (cons ini (loop (+ ini 1))))))&lt;br /&gt;&lt;br /&gt;(print (bigram (range 10000)))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pythonのrange関数相当のものがschemeにも標準であるはずだと思うんだけどなあ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-2628935805088475767?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2628935805088475767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2628935805088475767'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/12/n-gram.html' title='[メモ]再帰を使うとn-gramはすっきり書ける'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6061024851461497491</id><published>2007-12-28T14:52:00.000+09:00</published><updated>2007-12-28T14:53:40.205+09:00</updated><title type='text'>[メモ]MySQLでテーブル一覧でビューかどうか調べる方法。</title><content type='html'>&lt;pre&gt;&lt;br /&gt;select TABLE_NAME, TABLE_TYPE from INFORMATION_SCHEMA.TABLES &lt;br /&gt;where TABLE_SCHEMA="データベース名";&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6061024851461497491?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6061024851461497491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6061024851461497491'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/12/mysql.html' title='[メモ]MySQLでテーブル一覧でビューかどうか調べる方法。'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3929603152066984461</id><published>2007-12-14T00:43:00.000+09:00</published><updated>2007-12-14T01:00:43.887+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scheme'/><title type='text'>Gaucheの練習: 連続する名詞の抽出</title><content type='html'>連続する名詞の抽出を書いてみた。Gauche(というかScheme)素人なのでとても時間がかかる。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;;; coding: utf-8&lt;br /&gt;&lt;br /&gt;(use mecab)&lt;br /&gt;&lt;br /&gt;(define (takenowns node buf ans)&lt;br /&gt;  (if (mecab-node-null? node) &lt;br /&gt;      (if (null? buf) ans (append ans (list buf)))&lt;br /&gt;      (if (equal? "名詞" (substring (mecab-node-feature node) 0 2)) &lt;br /&gt;   (takenowns (mecab-node-next node) (append buf (list (mecab-node-surface node))) ans)&lt;br /&gt;   (takenowns (mecab-node-next node) '() (if (null? buf) ans (append ans (list buf))))))&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;(define m (mecab-new2 ""))&lt;br /&gt;&lt;br /&gt;(map print &lt;br /&gt;     (takenowns &lt;br /&gt;      (mecab-sparse-tonode m "並み居る共和党候補たちのはるか後方で何カ月も低迷していた&lt;br /&gt;ハッカビー氏は、アイオワ州の支持率でついに、ミット・ロムニー氏についで２位となった")&lt;br /&gt;       '() '()))&lt;br /&gt;&lt;br /&gt;(mecab-destroy m)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;実行結果 &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ayu@~/work/Gauche-mecab% gosh sample.scm | nkf -e&lt;br /&gt;(共和党 候補 たち)&lt;br /&gt;(はるか 後方)&lt;br /&gt;(何 カ月)&lt;br /&gt;(低迷)&lt;br /&gt;(ハッカビー 氏)&lt;br /&gt;(アイオワ 州)&lt;br /&gt;(支持 率)&lt;br /&gt;(ミット・ロムニー 氏)&lt;br /&gt;(ついで ２ 位)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;自分で書いておいてなんだが、非常に読みづらいコードだと思う。&lt;br /&gt;もっときれいに書けるようになるにはあと何年かかるだろうか。&lt;br /&gt;Pythonできれいにかけるようになるのにも数年かかったからなあ。&lt;br /&gt;&lt;br /&gt;以下を調べておく事------&lt;br /&gt;[done] Pythonのリストのように後ろに追加していけるリストはないのだろうか。&lt;br /&gt;Python文字列のstartswithメソッド相当を作る。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3929603152066984461?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3929603152066984461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3929603152066984461'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/12/gauche.html' title='Gaucheの練習: 連続する名詞の抽出'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-596345867041054314</id><published>2007-12-13T03:30:00.000+09:00</published><updated>2007-12-13T03:49:36.004+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scheme'/><title type='text'>Schemeのmecabバインディング</title><content type='html'>関数型言語を勉強して来たが、実用を考えるとマルチバイト文字を扱えることが必須になる。&lt;br /&gt;その時点で早くもHaskellは立場が弱くなるのだが、その点Gaucheはすばらしいということに改めて気づいた。（Schemeでは破壊的代入ができますが、そういう細かいことは自分のような初心者にはまあ、いいでしょう。）&lt;br /&gt;&lt;br /&gt;そこで、自分の分野でガリガリ使ってGaucheの勉強をするために、Gaucheからmecabを使ってみようと思った。&lt;br /&gt;&lt;br /&gt;この点での先人のすばらしい記事を発見。&lt;br /&gt;その記事「&lt;a href="http://practical-scheme.net/wiliki/wiliki.cgi?Gauche%3AMeCab"&gt;Gauche:MeCab&lt;/a&gt;」に、自分としてはparseToNode相当の機能がほしかったので、Gaucheのバインディングの細かい事を勉強せずに推測で機能追加してみた。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://tanashi.s240.xrea.com/misc/Gauche-mecab.tar.gz"&gt;Gauche-mecab.tar.gz&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;いちおう下のようなプログラムで動くようになる。&lt;br /&gt;&lt;br /&gt;（ただし、mecabの文字コードとGaucheの内部encodingをそろえておく必要あり。）&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;;; coding: utf-8&lt;br /&gt;&lt;br /&gt;(use mecab)&lt;br /&gt;&lt;br /&gt;(define (allnodes node)&lt;br /&gt;  (if (mecab-node-null? node) &lt;br /&gt;      '() &lt;br /&gt;      (cons node (allnodes (mecab-node-next node))))&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;(define m (mecab-new2 ""))&lt;br /&gt;&lt;br /&gt;(let ((node (mecab-sparse-tonode m "太郎は極悪です。")))&lt;br /&gt;  (map &lt;br /&gt;   (lambda (x) &lt;br /&gt;     (print (mecab-node-surface x)) &lt;br /&gt;     (print (mecab-node-feature x))) &lt;br /&gt;   (allnodes node))&lt;br /&gt;)&lt;br /&gt;  &lt;br /&gt;(mecab-destroy m)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;実行結果&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ayu@~/work/Gauche-mecab% gosh sample.scm | nkf -e&lt;br /&gt;&lt;br /&gt;BOS/EOS,*,*,*,*,*,*,*,*&lt;br /&gt;太郎&lt;br /&gt;名詞,固有名詞,人名,名,*,*,太郎,タロウ,タロー&lt;br /&gt;は&lt;br /&gt;助詞,係助詞,*,*,*,*,は,ハ,ワ&lt;br /&gt;極悪&lt;br /&gt;名詞,形容動詞語幹,*,*,*,*,極悪,ゴクアク,ゴクアク&lt;br /&gt;です&lt;br /&gt;助動詞,*,*,*,特殊・デス,基本形,です,デス,デス&lt;br /&gt;。&lt;br /&gt;記号,句点,*,*,*,*,。,。,。&lt;br /&gt;&lt;br /&gt;BOS/EOS,*,*,*,*,*,*,*,*&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-596345867041054314?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/596345867041054314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/596345867041054314'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/12/schememecab.html' title='Schemeのmecabバインディング'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6013713550147577597</id><published>2007-11-28T01:19:00.000+09:00</published><updated>2007-11-28T01:31:54.674+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>PythonでHarwell-Boeing matrix</title><content type='html'>C++のような本気言語ではなく、"バッテリー内蔵言語"であるPythonでHarwell-Boeing matrixのようなシビアな世界のデータ構造を書いたらどのぐらいになるかと試した。&lt;br /&gt;&lt;br /&gt;このぐらいになる。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/python&lt;br /&gt;# _*_ coding: euc_jp _*_&lt;br /&gt;# Copyright (C)  2007 Ayukawa Hiroshi&lt;br /&gt;from array import array&lt;br /&gt;from itertools import izip, islice&lt;br /&gt;from collections import defaultdict&lt;br /&gt;&lt;br /&gt;class Hwmatrix(object):&lt;br /&gt;    def __init__(self, rownum_type="I", colnum_type="I", val_type="I"):&lt;br /&gt;        self.rowindex = array(rownum_type)&lt;br /&gt;        self.colindex = array(colnum_type)&lt;br /&gt;        self.val = array(val_type)&lt;br /&gt;        self.rowindex.append(0)&lt;br /&gt;&lt;br /&gt;        if val_type in ("f", "d"):&lt;br /&gt;            self.val_type = float&lt;br /&gt;        else:&lt;br /&gt;            self.val_type = int&lt;br /&gt;        &lt;br /&gt;    def addrow(self, row):&lt;br /&gt;        row = dict(row)&lt;br /&gt;        cols = row.keys()&lt;br /&gt;        cols.sort()&lt;br /&gt;        vals = [row[k] for k in cols]&lt;br /&gt;        self.colindex.extend(cols)&lt;br /&gt;        self.val.extend(vals)&lt;br /&gt;        self.rowindex.append(self.rowindex[-1] + len(cols))&lt;br /&gt;&lt;br /&gt;    def getrow_as_pair(self, n):&lt;br /&gt;        rownum = self.rowindex[n]&lt;br /&gt;        rowlen = self.rowindex[n+1] - rownum&lt;br /&gt;        return islice(izip(self.colindex[rownum:], self.val[rownum:]), rowlen)&lt;br /&gt;&lt;br /&gt;    def __rmul__(self, vector):&lt;br /&gt;        if isinstance(vector, dict):&lt;br /&gt;            answer = defaultdict(self.val_type)&lt;br /&gt;            for k in vector.keys():&lt;br /&gt;                weight = vector[k]&lt;br /&gt;                for i, v in self.getrow_as_pair(k):&lt;br /&gt;                    answer[i] += weight * v&lt;br /&gt;            return answer&lt;br /&gt;&lt;br /&gt;def test():&lt;br /&gt;    """&lt;br /&gt;                  1 1 0 0 0&lt;br /&gt;                  0 1 1 0 0&lt;br /&gt;    (0 2 3 0 1) * 0 0 1 1 0  =  (0 2 5 3 1)&lt;br /&gt;                  0 0 0 1 1&lt;br /&gt;                  0 0 0 0 1&lt;br /&gt;    """&lt;br /&gt;    mat = Hwmatrix()&lt;br /&gt;    mat.addrow({0:1, 1:1})&lt;br /&gt;    mat.addrow({1:1, 2:1})&lt;br /&gt;    mat.addrow({2:1, 3:1})&lt;br /&gt;    mat.addrow({3:1, 4:1})&lt;br /&gt;    mat.addrow({4:1})&lt;br /&gt;&lt;br /&gt;    print {1:2, 2:3, 4:1} * mat&lt;br /&gt;&lt;br /&gt;test()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;これはひょっとして実用的に使えたりしないだろうか。&lt;br /&gt;会社ではC++で書いたものを使っていますが、自宅の趣味にはこういうのでもいいかも。&lt;br /&gt;&lt;br /&gt;追記---&lt;br /&gt;でも、よく考えると、ベクトルとの積__rmul__での処理なんかで、いちいち内部でPyObjectを作って参照カウンタをごにょごにょやっているんだと想像すると、一気に使う気が失せました。&lt;br /&gt;やはりこういうのはC++じゃないといやだな。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6013713550147577597?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6013713550147577597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6013713550147577597'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/11/pythonharwell-boeing-matrix.html' title='PythonでHarwell-Boeing matrix'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6312235423825353568</id><published>2007-11-27T22:48:00.000+09:00</published><updated>2007-11-27T22:52:53.319+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>djangoのせいで</title><content type='html'>S2StrutsのクイックスタートのGreetingのサンプルを見たが、なんかめまいが。&lt;br /&gt;&lt;br /&gt;djangoをここ3ヶ月ほど使っていたおかげで、もうJAVAでのWEB開発には戻れない体になってしまいました。&lt;br /&gt;&lt;br /&gt;S2Strutsでの開発が自分に回ってきそうになっているが、どうしようか悩み中。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6312235423825353568?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6312235423825353568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6312235423825353568'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/11/django.html' title='djangoのせいで'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3915561400860490574</id><published>2007-11-17T01:01:00.000+09:00</published><updated>2007-11-17T01:02:46.127+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>ユークリッドの互除法</title><content type='html'>ユークリッドの互除法のような簡単なものだと、さすがにHaskellもPythonもそんなに差はなく、どちらもきれいに書ける。&lt;br /&gt;&lt;br /&gt;Haskell&lt;br /&gt;&lt;pre&gt;euc m 0 = m&lt;br /&gt;euc m n | m &lt; n = euc n m&lt;br /&gt;        | m `mod` n == 0 = n&lt;br /&gt;        | otherwise = euc n $ m `mod` n&lt;br /&gt;&lt;br /&gt;main = do print $ euc 1071 1029&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Python&lt;br /&gt;&lt;pre&gt;def euc(m, n):&lt;br /&gt;    if m &lt; n: return euc(n, m)&lt;br /&gt;    if n == 0: return m&lt;br /&gt;    if m % n == 0 : return n&lt;br /&gt;    return euc(n, m % n)&lt;br /&gt;&lt;br /&gt;print euc(1071, 1029)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3915561400860490574?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3915561400860490574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3915561400860490574'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/11/blog-post_17.html' title='ユークリッドの互除法'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-739322989150429497</id><published>2007-11-16T00:31:00.000+09:00</published><updated>2007-11-17T01:00:00.830+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]数学の記述ではやはりHaskellがPythonよりも上手ですが、変態的Pythonなら肉薄できそう</title><content type='html'>&lt;a href="http://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%A9%E3%83%88%E3%82%B9%E3%83%86%E3%83%8D%E3%82%B9%E3%81%AE%E7%AF%A9"&gt;エラストテネスのふるい&lt;/a&gt;という素数生成アルゴリズムがあるが、これを（平方と素数の間に成り立つ不等式を考慮せずシンプルに）Haskellで書くと３行で書ける。&lt;br /&gt;&lt;pre&gt;removenum x xs = filter (\a -&gt; a `mod` x /= 0) xs&lt;br /&gt;hurui (x: xs) = x : (hurui $ removenum x xs)&lt;br /&gt;&lt;br /&gt;main = do  print $ take 100 $ hurui [2..]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;これを標準的な作法に従ったPythonで書くと少し行数が増える。（けっこうがんばったのですが。。。）&lt;br /&gt;&lt;pre&gt;from itertools import ifilter, count, islice&lt;br /&gt;&lt;br /&gt;def hurui(xs):&lt;br /&gt;    first = xs.next()&lt;br /&gt;    yield first&lt;br /&gt;    for x in hurui(ifilter(lambda x: x % first != 0, xs)):&lt;br /&gt;        yield x&lt;br /&gt;&lt;br /&gt;for i in islice(hurui(count(2)), 100):&lt;br /&gt;    print i, &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;しかも、10000個ぐらい素数を出力させようとすると再帰呼び出しのスタックがあふれてしまう。&lt;br /&gt;Haskellの場合は10000個でも大丈夫だし、きっといくつでも大丈夫なんだろう。（だからこそ関数型なんだろうし）&lt;br /&gt;&lt;br /&gt;Pythonで無理矢理遅延評価を実現すれば、以下のようにも書けて、再帰であるのにスタックあふれもなくなる。&lt;br /&gt;&lt;pre&gt;from itertools import ifilter, count, islice, takewhile, tee, dropwhile&lt;br /&gt;&lt;br /&gt;def hurui(xs):&lt;br /&gt;    first = xs.next()&lt;br /&gt;    return (first, lambda : hurui(ifilter(lambda x: x % first != 0, xs)))&lt;br /&gt;&lt;br /&gt;first, func = hurui(count(2))&lt;br /&gt;for i in range(10000):&lt;br /&gt;    print first,&lt;br /&gt;    first, func = func()&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;こういうテクニックって、一般にはなんて言うんだろう。末尾再帰？&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;追記&lt;br /&gt;コメントで頂いたのだが、以下のサイトによりエレガントな方法が。&lt;br /&gt;&lt;a href="http://4topcoder.blogspot.com/2007/07/python-generator.html"&gt;http://4topcoder.blogspot.com/2007/07/python-generator.html&lt;/a&gt;&lt;br /&gt;なるほどすごい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-739322989150429497?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/739322989150429497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/739322989150429497'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/11/haskellpythonpython.html' title='[メモ]数学の記述ではやはりHaskellがPythonよりも上手ですが、変態的Pythonなら肉薄できそう'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-1706843183032954228</id><published>2007-11-15T14:58:00.000+09:00</published><updated>2007-11-15T14:59:25.381+09:00</updated><title type='text'>[メモ]MySQLのプロセス監視</title><content type='html'>これは便利。&lt;br /&gt;&lt;pre&gt;watch -n 15 'mysql -u*** -p*** -e "show processlist"'&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-1706843183032954228?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1706843183032954228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1706843183032954228'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/11/mysql_15.html' title='[メモ]MySQLのプロセス監視'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-1895713923536088355</id><published>2007-11-15T12:54:00.000+09:00</published><updated>2007-11-15T12:57:00.513+09:00</updated><title type='text'>[メモ]MySQLの最適なテーブル定義を知る方法</title><content type='html'>既存のテーブルの無駄に長いフィールドなどを調整したい場合は以下のクエリーで最適なフィールドの長さなどの情報を表示できる。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;SELECT * FROM table_name PROCEDURE ANALYSE()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;参考: &lt;a href="http://dev.mysql.com/tech-resources/presentations/presentation-oscon2000-20000719/"&gt;MySQL Presentations: Optimizing MySQL&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-1895713923536088355?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1895713923536088355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1895713923536088355'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/11/mysql.html' title='[メモ]MySQLの最適なテーブル定義を知る方法'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8981141725380154879</id><published>2007-11-13T23:54:00.000+09:00</published><updated>2007-11-14T00:00:06.735+09:00</updated><title type='text'>[日記]まだまだアッカーマン関数</title><content type='html'>いまだにアッカーマン関数が原始的でないことの証明をやっている。&lt;br /&gt;あと１パターンの不等式を証明できればできあがりなんだけど。&lt;br /&gt;ここの日記に最初にアッカーマン関数の事を書いてからもう８日がすぎています。&lt;br /&gt;もしこれが大学の授業の宿題とかだったりしたら、自分は&lt;br /&gt;「１週間やってたけどできませんでした。」&lt;br /&gt;という、まじめはまじめなんだけど、できない子みたいだなあ。&lt;br /&gt;&lt;br /&gt;すべて完成したら、次にもう一度この証明を見直すときのために証明の要点をここの日記に整理して書こうと思います。&lt;br /&gt;しかし、まずは残りをやらなければ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8981141725380154879?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8981141725380154879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8981141725380154879'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/11/blog-post_13.html' title='[日記]まだまだアッカーマン関数'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-2250391734905037382</id><published>2007-11-09T08:31:00.000+09:00</published><updated>2007-11-09T08:52:51.204+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[雑談]「これから一からプログラミングを覚えようと考えています。」</title><content type='html'>&lt;a href="http://q.hatena.ne.jp/1194256707"&gt;これから一からプログラミングを覚えようと考えています。&lt;br /&gt;様々な言語がありますが、どれを覚えるべきでしょうか？&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;PHPすごい人気ですね。&lt;br /&gt;初心者に最適という評価はあるようだ。&lt;br /&gt;&lt;br /&gt;でも初心者でなくなったときにPHPに感じる落胆もでかいんだよなあ。&lt;br /&gt;&lt;br /&gt;数年PHPを使い込んだ過去のある自分としてはおすすめできない。&lt;br /&gt;LL等のイベントでPHPの重鎮の発表の自虐的な雰囲気を見てから判断してもいいと思った。&lt;br /&gt;&lt;br /&gt;（このブログにトラックバック機能があれば、トラックバックしたかったが、残念ながらないみたい。。）&lt;br /&gt;&lt;br /&gt;Pythonはこういう時に自信を持って勧めていいものかどうか迷います。&lt;br /&gt;他の言語にあらかた疲れた時に、ふと使ってみるとはまるという性質もあるからねえ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-2250391734905037382?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2250391734905037382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2250391734905037382'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/11/blog-post_09.html' title='[雑談]「これから一からプログラミングを覚えようと考えています。」'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6845529150137179083</id><published>2007-11-08T22:45:00.001+09:00</published><updated>2007-11-08T22:59:09.752+09:00</updated><title type='text'>[日記]まだアッカーマン関数</title><content type='html'>毎日少ししか勉強時間が取れないので、アッカーマン関数の演習問題から抜け出せていない。&lt;br /&gt;&lt;br /&gt;２日悩んだ問題「アッカーマン関数をNプログラムで計算する方法を考えよ」は、スタックをNプログラムで書ければうまくいきそうだとわかったが、それには次の章以降の知識がいるようだ。。。スタックを書く方法を一日考えていたがやはり自力では思いつかないので素直に次章へ進むしかないか。&lt;br /&gt;しかし、「考えよ」ということだから、（「書け」というわけではないから、）ここまでできれば完了なんだろうか。なんともすっきりしない。&lt;br /&gt;&lt;br /&gt;次の問題はアッカーマン関数が原始的関数でないことの証明問題なので、着々と進んでいるが、長いので時間がかかりそうだ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6845529150137179083?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6845529150137179083'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6845529150137179083'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/11/blog-post_08.html' title='[日記]まだアッカーマン関数'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-2209792267951196081</id><published>2007-11-06T23:29:00.000+09:00</published><updated>2007-11-06T23:41:03.766+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>アッカーマン関数やばい</title><content type='html'>&lt;a href="http://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%83%E3%82%AB%E3%83%BC%E3%83%9E%E3%83%B3%E9%96%A2%E6%95%B0"&gt;アッカーマン関数&lt;/a&gt;を計算論の教科書の演習問題で見て、問題がうまく解けないのでためしにアッカーマン関数の計算結果の一部を一覧にして眺めようと思った。&lt;br /&gt;でも、計算量が多すぎてすぐにとんでもないことになるんだね。お願いだから教科書に書いておいてくださいと思いました。&lt;br /&gt;&lt;pre&gt;f 0 y = y + 1&lt;br /&gt;f x 0 = f (x - 1) 1&lt;br /&gt;f x y = f (x - 1) (f x (y - 1))&lt;br /&gt;&lt;br /&gt;main = do print $ f 4 2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;これをHaskellで実行すると死ぬ。&lt;br /&gt;f 3 2 ぐらいはまだ大丈夫だが。&lt;br /&gt;&lt;br /&gt;どのぐらい計算量がやばいことになるかを、f 2 2 の場合で置換モデルでノートに書き下していったら、なんと２７行もノートを使うということが判明。&lt;br /&gt;f 4 2なんか、そりゃとんでもないことになってるんだろうなあ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-2209792267951196081?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2209792267951196081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/2209792267951196081'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/11/blog-post_06.html' title='アッカーマン関数やばい'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6680341056915343284</id><published>2007-11-06T10:26:00.000+09:00</published><updated>2007-11-06T10:35:31.532+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]正規表現モジュール re のscanner機能</title><content type='html'>Pythonのドキュメントには書かれていないが、正規表現モジュール(re)にはscannerという機能がある。&lt;br /&gt;一旦作成した正規表現オブジェクトで、長い文章中をスキャンしていくような感じで、全てのマッチする部分を検出していく機能だ。&lt;br /&gt;便利なんだが、使いたい時に毎回使い方を忘れているのでこの際ここにメモしておこう。&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; a="aaabbbcccdddaaa111fffsss"&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import re&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; pat = re.compile(r"aaa(...)")&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; dir(pat)&lt;br /&gt;['__copy__', '__deepcopy__', 'findall', 'finditer', 'match', &lt;b&gt;'scanner'&lt;/b&gt;, &lt;br /&gt;'search', 'split', 'sub', 'subn']&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; scanner = pat.scanner(a)&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; dir(scanner)&lt;br /&gt;['match', 'search']&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; m = scanner.search()&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; m&lt;br /&gt;&amp;lt;_sre.SRE_Match object at 0x2a98006210&amp;gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; m.groups()&lt;br /&gt;('bbb',)&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; m = scanner.search()&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; m.groups()&lt;br /&gt;('111',)&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; m = scanner.search()&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; m&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;   #もう候補がないので m = None となっている。&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6680341056915343284?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6680341056915343284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6680341056915343284'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/11/re-scanner.html' title='[メモ]正規表現モジュール re のscanner機能'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8282940866748486396</id><published>2007-11-01T16:25:00.000+09:00</published><updated>2007-11-01T16:28:15.717+09:00</updated><title type='text'>[メモ]有機ＥＬ</title><content type='html'>EUCで「有機ＥＬ」という語の「機」の後半バイトと「Ｅ」の前半バイトはくっつけると「。」と同じコードになる。&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; s = lambda x: map( lambda y: hex(ord(y)) , unicode(x, "utf-8").encode("euc_jp"))&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; s("有機ＥＬ")&lt;br /&gt;['0xcd', '0xad', '0xb5', '0xa1', '0xa3', '0xc5', '0xa3', '0xcc']&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; s("。")&lt;br /&gt;['0xa1', '0xa3']&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8282940866748486396?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8282940866748486396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8282940866748486396'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/11/blog-post.html' title='[メモ]有機ＥＬ'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6852597878086906223</id><published>2007-10-29T17:18:00.000+09:00</published><updated>2007-10-29T17:24:29.528+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]djangoのmodelのカスタムSQLでujisのトラブル回避</title><content type='html'>MySQLでujisを使っている場合、djangoのカスタムSQLで日本語を使おうとすると、以下のエラーがでる。&lt;br /&gt;&lt;pre&gt;UnicodeEncodeError at /***/***/&lt;br /&gt;'latin-1' codec can't encode characters in position 170-172: ordinal not in range(256)&lt;br /&gt;Request Method:  GET&lt;br /&gt;Request URL:  http://**.**.**.**/***/***/&lt;br /&gt;Exception Type:  UnicodeEncodeError&lt;br /&gt;Exception Value:  'latin-1' codec can't encode characters in position 170-172: ordinal not in range(256)&lt;br /&gt;Exception Location:  /usr/local/python25/lib/python2.5/site-packages/MySQL_python-1.2.2-py2.5-linux-x86_64.egg/MySQLdb/cursors.py in execute, line 149&lt;br /&gt;Python Executable:  /usr/local/python25/bin/python&lt;br /&gt;Python Version:  2.5.0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ぐぐると自分が過去にTurboGearsMLに投稿した記事が出てきた。&lt;br /&gt;&lt;a href="http://groups.google.com/group/turbogears-ja/browse_thread/thread/69bc1ff4d86eca33/d18807e59a924bb3&lt;br /&gt;"&gt;http://groups.google.com/group/turbogears-ja/browse_thread/thread/69bc1ff4d86eca33/d18807e59a924bb3&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;ここではみなさんうまくきれいに解決されたようだが、相変わらず自分はうまくいかないので、以下をsettings.pyに書いて解決。&lt;br /&gt;&lt;pre&gt;DATABASE_OPTIONS = dict(charset="ujis", read_default_file="/etc/my.cnf")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(ただし、/etc/my.cnfにデフォルトcharsetをujis指定で設定しておく。）&lt;br /&gt;&lt;br /&gt;本当は↓みたいなのでうまくいけばいいんだけど、なんかそうならない。&lt;br /&gt;&lt;pre&gt;DATABASE_OPTIONS = dict(charset="ujis", use_unicode=1)&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6852597878086906223?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6852597878086906223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6852597878086906223'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/10/djangomodelsqlujis.html' title='[メモ]djangoのmodelのカスタムSQLでujisのトラブル回避'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-393963226242803335</id><published>2007-10-11T23:38:00.000+09:00</published><updated>2007-10-11T23:57:25.286+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>言語の比較記事</title><content type='html'>&lt;a href="http://jijixi.azito.com/cgi-bin/diary/index.rb?date=20071010#p01"&gt;Ruby に比べて Python の面倒なところ&lt;/a&gt;&lt;br /&gt;こういう他の言語を深く知っている方の感想は読んでためになる。&lt;br /&gt;自分が無意識に適応してるけど、実はめんどうなことをやっているんではないかというふうに相対化した視点を得るきっかけになるのはいいことだ。&lt;br /&gt;&lt;br /&gt;で、挙げてある「Pythonの面倒なところ」もたしかに的を得たものばかり。&lt;br /&gt;printが文であることなどは自分も含めたPythonを日頃使う人も違和感を感じることもあるんじゃないだろうか。&lt;br /&gt;&lt;br /&gt;ただ、そういう疑念が湧いたとしても、Pythonのようにそれなりに多くの先人の知恵が集まってできている言語では、たとえばprintが文になっているのもそれなりの利点があったからなのかもしれないと想像している。（うろ覚えだがPython3系ではprintが関数になるんじゃなかったけ？たぶんまた考え直したんだろうか。）&lt;br /&gt;&lt;br /&gt;たとえば、代入が値を返さないというのは、&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;if a = 10:&lt;br /&gt;    ....&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;のようなケアレスミスを直ちに検出できたりするから個人的にはすごく好きな点だったりする。&lt;br /&gt;&lt;br /&gt;selfをいちいち書くのも、そのクラスの名前であることが強烈に分かるのでとても愛すべきポイントだったりする。逆にC++を書くときはthis-&amp;gt;を書きたくて書きたくてしょうがなく感じるときもある。（がまんしてできるだけ書きませんが。）&lt;br /&gt;&lt;br /&gt;importも、これを日々いちいち書く事で、予約語が少なく済んでいるということを骨身に沁みて感じることができたり、関数やクラスをモジュール単位で整理して思い出せるので好きなポイントだ。&lt;br /&gt;&lt;br /&gt;returnも、どこで値が返っているかをエディタの検索で色付き反転させて一気に見る事ができてすごくいい。&lt;br /&gt;&lt;br /&gt;ああ、なんかこうして書いていくとほんとにきりがなくて、自分はPythonに魂をうばわれているんじゃないかと思うよ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-393963226242803335?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/393963226242803335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/393963226242803335'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/10/blog-post.html' title='言語の比較記事'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3364146157570590818</id><published>2007-10-05T23:24:00.000+09:00</published><updated>2007-10-06T00:19:33.287+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>あるPython信者がたどったHaskellの入り口までの道のり</title><content type='html'>Haskellの勉強がついにその入り口の敷居を超えた気がするので、ここまでの経緯を記録しておく。&lt;br /&gt;&lt;br /&gt; * １年ほど前、、、「&lt;a href="http://www.amazon.co.jp/%E5%85%A5%E9%96%80Haskell%E2%80%95%E3%81%AF%E3%81%98%E3%82%81%E3%81%A6%E5%AD%A6%E3%81%B6%E9%96%A2%E6%95%B0%E5%9E%8B%E8%A8%80%E8%AA%9E-%E5%90%91%E4%BA%95-%E6%B7%B3/dp/4839919623/ref=pd_sim_b_2_img/503-4197886-3455920"&gt;入門Haskell&lt;/a&gt;」を購入して一読するも理解できず。&lt;br /&gt;&lt;br /&gt; * その１ヶ月後、、、「&lt;a href="http://www.amazon.co.jp/%E3%81%B5%E3%81%A4%E3%81%86%E3%81%AEHaskell%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E3%81%B5%E3%81%A4%E3%81%86%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E9%96%A2%E6%95%B0%E5%9E%8B%E8%A8%80%E8%AA%9E%E5%85%A5%E9%96%80-%E9%9D%92%E6%9C%A8-%E5%B3%B0%E9%83%8E/dp/4797336021"&gt;ふつうのHaskell&lt;/a&gt;」を購入して一読。途中まで写経。全体像がぼんやり見えてくるも未だ「代数的データ型」とか「型クラス」とかが一体何のためにあるか理解できず。モナドに至っては全くわからない状態。&lt;br /&gt;&lt;br /&gt; * それからしばらくして、「&lt;a href="http://www.geocities.jp/takascience/haskell/monadius_ja.html"&gt;モナディウスの解説ページ&lt;/a&gt;」を発見。Haskellでのプログラミングの進め方が、これまでのプログラミングとはずいぶんと違うことを発見。「代数的データ型」とか「型クラス」とかがわかり始める。&lt;br /&gt;&lt;br /&gt; * それからしばらくして、仕事で作ったPythonの短いスクリプトをHaskellに移植してみる。やっぱりPythonのほうが楽だし実行時のパフォーマンスもはるかにいいし、Haskellを勉強する意欲が失せる。&lt;br /&gt;&lt;br /&gt; * それからしばらくして、「&lt;a href="http://www.amazon.co.jp/Structure-Interpretation-Computer-Electrical-Engineering/dp/0262510871"&gt;SICP&lt;/a&gt;」を読み始めるも、途中の&lt;a href="http://www.shido.info/lisp/scheme_amb.html"&gt;amb&lt;/a&gt;が出てきたあたりで挫折。写経せずに電車内での読書にしていたのが敗因か。しかし、そこまででもいろいろ深い内容でためになる。この時期、自分のPythonのプログラムにやたらとmap、filter、lambdaが増え始め、そのPythonにあるまじき傾向に自制の必要を感じる。&lt;br /&gt;&lt;br /&gt; * それからしばらくして、OCamlに手を出すも、データ型の扱いがシビアすぎて萎える。&lt;br /&gt;&lt;br /&gt; * しばらくは時々Haskellに思いを馳せるだけの日々。結局どういうときに「代数的データ型」を使って、どういうときにただのリストとかpairで済ませるのかにうじうじと思い悩む。。。&lt;br /&gt;&lt;br /&gt; * 数日前、「&lt;a href="http://www.shido.info/hs/index.html"&gt;Haskellのお勉強&lt;/a&gt;」の写経を始める。いろいろわかり始める。敷居を超えた感を初めて味わう。&lt;br /&gt;&lt;br /&gt; * 二日前、モナドの定義やモナド則を、チラシの裏に書いて試行錯誤してなんとか理解。モナドの演算の「m &amp;gt;&amp;gt;= k」は、「(&amp;gt;&amp;gt;= k)がmに右から作用する」と読む事で理解が深まることに気づいた。（←この視点で可換図式を書いてモナド則を理解するのがいいようだが、合っているかの自信はない。）ただこれが実際にプログラミングでどう役に立つのか、特にdo式をどういう文脈で理解すべきか、IOモナドの詳細とか、Listモナドをモナドと見なすことのご利益の理解はこれから。&lt;br /&gt;&lt;br /&gt; * 今日、仕事であるバッチの複雑な計算処理をHaskellで書いてみた。ベクトルの各種演算とか、ファイルのIOがたらふくあるようなやつです。でも予想外にすんなり書けて驚いた。６０行ぐらいの規模のプログラム。こんなに短くなるとは予想していなかった。可読性はPythonには劣るものの、なんだか気持ちいいプログラムになって満足。でも、あちこちでmap, filter, zip系を使うので、書いてある内容の密度はすごい。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ここまで１年かかっているが、昔３回ぐらい挫折を繰り返しながら数年のレンジでC++を身につけたのに比べると、まだましな道のりだろう。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3364146157570590818?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3364146157570590818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3364146157570590818'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/10/pythonhaskell.html' title='あるPython信者がたどったHaskellの入り口までの道のり'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-562129432625230154</id><published>2007-10-04T09:24:00.000+09:00</published><updated>2007-10-04T09:29:13.542+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]Python信者から見た、Javaを使いたくない理由</title><content type='html'>ちょっとメモしておきます。&lt;br /&gt; * generatorがない。&lt;br /&gt; * 関数を返す関数とか、関数の配列を作ったり、それらを活用することが推奨されていない。&lt;br /&gt; * lambdaがない。無名クラスのような大げさな書き方が必要。&lt;br /&gt; * map, filter系関数がない。imapやifilterはもちろんない。&lt;br /&gt; * 動的配列、ハッシュマップ、集合などの便利なコンテナをコンパクトに記述できない。1.4系では取り出すたびにキャストが必要なので不便。&lt;br /&gt; * 最近、業界標準になってしまった某IDEが重過ぎる。&lt;br /&gt; * catchを必ず書く必要がある。&lt;br /&gt; * sortでcomparatorを書くのが面倒くさい。&lt;br /&gt; * 大げさなライブラリは外付けでたくさんあるが、細かい気の利いたライブラリがない。(CSV読み込みとか、簡易に使えるXMLRPCサーバーとか)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-562129432625230154?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/562129432625230154'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/562129432625230154'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/10/pythonjava.html' title='[メモ]Python信者から見た、Javaを使いたくない理由'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6852796446881601923</id><published>2007-09-12T22:46:00.000+09:00</published><updated>2007-09-12T22:52:46.111+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>「Pythonをはじめよう」という記事が指摘しているPythonの良い点</title><content type='html'>&lt;a href="http://codezine.jp/a/article/aid/1617.aspx"&gt;Codezine: Pythonをはじめよう&lt;/a&gt;&lt;br /&gt;という記事の以下の一節が目をひいた。&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;中括弧等を打たなくて良い分ロジックの打ち込みだけに集中できますし&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;たしかにそうだ。&lt;br /&gt;言われてみて気づいた。&lt;br /&gt;他の言語では、括弧の対応が合っているかどうかをエディタの補助機能を使いながら確認しなければいけないが、Pythonの場合は縦にざっと眺めるだけでその対応（＝インデント）が見通せてしまうというのは、いいことだ。&lt;br /&gt;&lt;br /&gt;Pythonのそもそもの思想に、「コードは書かれることより、読まれることのほうが多い」というのがあったような気がしますが、インデントは「読まれること」を非常に重視したとてもいい仕様だと思う。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6852796446881601923?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6852796446881601923'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6852796446881601923'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/09/pythonpython.html' title='「Pythonをはじめよう」という記事が指摘しているPythonの良い点'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-5651320436720668198</id><published>2007-09-12T09:51:00.000+09:00</published><updated>2007-09-12T09:53:18.326+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>django searchというのを見つけた</title><content type='html'>&lt;a href="http://djangosearch.com/"&gt;django search&lt;/a&gt;&lt;br /&gt;というのがあるのを見つけた。&lt;br /&gt;django関連の話題の検索サイトのようだ。&lt;br /&gt;Google custom searchを使っているみたいだが、これはすごく便利そうです。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-5651320436720668198?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/5651320436720668198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/5651320436720668198'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/09/django-search.html' title='django searchというのを見つけた'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-5029581899530481304</id><published>2007-09-07T18:44:00.000+09:00</published><updated>2007-09-08T00:04:05.769+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]popen2</title><content type='html'>以下の記述はうそ。popen2.pyを見ると、bufsizeにはデフォルトで-1が指定してある。自分の環境で止まっているのは、別の理由のようだ。&lt;br /&gt;&lt;s&gt;popen2でプロセスを起動して、返事がなかなか返ってこないなと思っていたら、popen2の引数に渡すbufsizeを超えてデータを渡していたようだ。&lt;br /&gt;このサイズを超えると、無反応でとまってしまうのではまる。&lt;/s&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-5029581899530481304?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/5029581899530481304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/5029581899530481304'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/09/popen2.html' title='[メモ]popen2'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-9156196286408381008</id><published>2007-09-07T18:05:00.000+09:00</published><updated>2007-09-07T18:09:52.611+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]sqlalchemyとloggingを同時に使う場合は、loggingという名前がかぶるよ。</title><content type='html'>&lt;pre&gt;import logging&lt;br /&gt;from sqlalchemy import *&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;というふうにすると、loggingという名前が、sqlalchemy.loggingで上書きされて、loggingが動かなくなる。&lt;br /&gt;import順を逆にするとよい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-9156196286408381008?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/9156196286408381008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/9156196286408381008'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/09/sqlalchemylogginglogging.html' title='[メモ]sqlalchemyとloggingを同時に使う場合は、loggingという名前がかぶるよ。'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6257751079522451252</id><published>2007-09-07T10:16:00.000+09:00</published><updated>2007-09-07T10:18:05.719+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]django.dbでmysqlの文字コード指定。</title><content type='html'>settings.pyで&lt;br /&gt;&lt;pre&gt;DATABASE_OPTIONS = dict(charset="ujis")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;参考: http://groups.google.com/group/django-ja/browse_thread/thread/26ff26fccc6258c3&lt;br /&gt;selectはうまくいくことを確認済み。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6257751079522451252?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6257751079522451252'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6257751079522451252'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/09/djangodbmysql.html' title='[メモ]django.dbでmysqlの文字コード指定。'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-946583390551959498</id><published>2007-09-06T12:47:00.000+09:00</published><updated>2007-09-06T12:50:46.933+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]defaultdictの引数はうまく使えば便利に違いない</title><content type='html'>defaultdictの引数には普通はintやfloatを入れるもんだが、"lambda :[0,0]"のような無名関数を入れることもできる。&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; from collections import defaultdict&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; a = defaultdict(lambda :[0,0])&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; a["AA"]&lt;br /&gt;[0, 0]&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; a["AA"][0] += 1&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; a&lt;br /&gt;defaultdict(&amp;lt;function &amp;lt;lambda&amp;gt; at 0x2a95666938&amp;gt;, {'AA': [1, 0]})&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; a["aa"][1] += 1&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; a&lt;br /&gt;defaultdict(&amp;lt;function &amp;lt;lambda&amp;gt; at 0x2a95666938&amp;gt;, {'AA': [1, 0], 'aa': [0, 1]})&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-946583390551959498?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/946583390551959498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/946583390551959498'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/09/defaultdict.html' title='[メモ]defaultdictの引数はうまく使えば便利に違いない'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-7752830184997417564</id><published>2007-08-30T18:03:00.000+09:00</published><updated>2007-08-31T16:34:51.775+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ][TODO]Django+SQLAlchemy調べ物</title><content type='html'>以下を調べること。&lt;br /&gt;&lt;br /&gt;djangoをSQLAlchemyで使う場合、&lt;br /&gt; * djangoのsqlalchemyブランチとやらは必須なのか？&lt;br /&gt; * model.pyをいきなりsqlalchemyの記述に差し替えて、影響範囲はどれぐらい？&lt;br /&gt; 　* 認証とか大丈夫？&lt;br /&gt; 　* 汎用ビューはあきらめる？&lt;br /&gt; 　* adminツールもあきらめないといけないのか？&lt;br /&gt;追記 ---&lt;br /&gt;&lt;a href="http://django.g.hatena.ne.jp/perezvon/20070211"&gt;http://django.g.hatena.ne.jp/perezvon/20070211&lt;/a&gt;&lt;br /&gt;この日記の記事が参考になる。&lt;br /&gt;やっぱりユーザー認証は独自実装ですか、、、。&lt;br /&gt;しかし、SQLAlchemyを使うことで、これほどまでに失うものが多いのであれば、いったいそもそもdjangoである必要があるのかどうかという疑問がでてきた。&lt;br /&gt;&lt;br /&gt;sqlalchemyブランチを取ってきたがsqlalchemy使ってるかどうかさえ不明な感じ。（ひょっとしてただ本家をコピーしてきただけ？）&lt;br /&gt;結局自分でなんとかしないといけないみたい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-7752830184997417564?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7752830184997417564'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7752830184997417564'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/tododjangosqlalchemy.html' title='[メモ][TODO]Django+SQLAlchemy調べ物'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-7518551301852086939</id><published>2007-08-29T08:55:00.000+09:00</published><updated>2007-08-29T09:14:18.159+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Directory Queue便利そう。</title><content type='html'>&lt;a href="http://www.psychofx.com/directory_queue/"&gt;Directory Queue&lt;/a&gt;&lt;br /&gt;ファイルベースのキュー実装。&lt;br /&gt;&lt;br /&gt;ファイルベースなので、データはファイルの中に書く。&lt;br /&gt;ファイルベースなので、途中でプログラムがクラッシュしても、キューの中身は残るんだろうか。（きっとそうだよね。。）&lt;br /&gt;面白いのは「メタデータ」を別途持たせることができること。&lt;br /&gt;&lt;br /&gt;これはJMSのMessageの仕様を参考にしているのかな？&lt;br /&gt;&lt;br /&gt;こういうプロジェクトがきちんと育ってくれたら、自分が今の仕事で使っているJMS地獄からいくぶん解放されるんじゃないだろうか。&lt;br /&gt;&lt;br /&gt;追記---&lt;br /&gt;「ファイルベース」というよりは、「ディレクトリベース」というほうが適切か。&lt;br /&gt;キュー内の1アイテムは、1ディレクトリで表されている。そのディレクトリの中に、データを表す"file.data"というファイルと、メタデータを表す"meta.data"というファイルを置くようだ。&lt;br /&gt;&lt;br /&gt;キューからのアイテムの取得は、os.listdirでディレクトリ内の一覧を取得して、ディレクトリ名のソートで先頭を取得するようだ。&lt;br /&gt;これはキュー内に大量のメッセージを格納したときにパフォーマンスが心配である。&lt;br /&gt;とは言っても、メッセージが大量にならない場合には問題ないだろう。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-7518551301852086939?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7518551301852086939'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7518551301852086939'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/directory-queue.html' title='Directory Queue便利そう。'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-4087549688088618283</id><published>2007-08-29T08:30:00.000+09:00</published><updated>2007-08-29T08:37:42.328+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]SQLAlchemyのPrecompiling a Query</title><content type='html'>&lt;a href="http://www.sqlalchemy.org/docs/03/sqlconstruction.html#sql_bindparams_precompiling"&gt;Precompiling a Query&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;SQLAlchemyであらかじめSQLを構成しておいて引数だけを差し替える方法。&lt;br /&gt;ループの内側でSQLをいちいち作り直す時間をはぶきたいときに使えそうだ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-4087549688088618283?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/4087549688088618283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/4087549688088618283'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/sqlalchemyprecompiling-query.html' title='[メモ]SQLAlchemyのPrecompiling a Query'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3474790465683879169</id><published>2007-08-28T12:12:00.000+09:00</published><updated>2007-08-28T12:13:43.007+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>this.pyのソースは文字を巡回させているのに気づいたよ。</title><content type='html'>こんなふうに。&lt;br /&gt;&lt;pre&gt;s = """Gur Mra bs Clguba, ol Gvz Crgref&lt;br /&gt;&lt;br /&gt;Ornhgvshy vf orggre guna htyl.&lt;br /&gt;Rkcyvpvg vf orggre guna vzcyvpvg.&lt;br /&gt;Fvzcyr vf orggre guna pbzcyrk.&lt;br /&gt;Pbzcyrk vf orggre guna pbzcyvpngrq.&lt;br /&gt;Syng vf orggre guna arfgrq.&lt;br /&gt;Fcnefr vf orggre guna qrafr.&lt;br /&gt;Ernqnovyvgl pbhagf.&lt;br /&gt;Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.&lt;br /&gt;Nygubhtu cenpgvpnyvgl orngf chevgl.&lt;br /&gt;Reebef fubhyq arire cnff fvyragyl.&lt;br /&gt;Hayrff rkcyvpvgyl fvyraprq.&lt;br /&gt;Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.&lt;br /&gt;Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.&lt;br /&gt;Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.&lt;br /&gt;Abj vf orggre guna arire.&lt;br /&gt;Nygubhtu arire vf bsgra orggre guna *evtug* abj.&lt;br /&gt;Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.&lt;br /&gt;Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.&lt;br /&gt;Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"""&lt;br /&gt;&lt;br /&gt;d = {}&lt;br /&gt;for c in (65, 97):&lt;br /&gt;    for i in range(26):&lt;br /&gt;        d[chr(i+c)] = chr((i+13) % 26 + c)&lt;br /&gt;&lt;br /&gt;print "".join([d.get(c, c) for c in s])&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3474790465683879169?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3474790465683879169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3474790465683879169'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/thispy.html' title='this.pyのソースは文字を巡回させているのに気づいたよ。'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-8499993514578368916</id><published>2007-08-24T18:37:00.000+09:00</published><updated>2007-08-24T18:52:10.039+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>django一日目の感想</title><content type='html'>今日は数時間ほどユーザー登録周りのコードを書いていた。&lt;br /&gt;こうしてチュートリアル以外で、まともにdjangoをさわるのはほぼ初めてです。&lt;br /&gt;&lt;br /&gt;基本的には&lt;a href="http://code.google.com/p/django-registration/"&gt;django-registration&lt;/a&gt;を、公式リリースであるdjango0.96で使えるように改造する作業。&lt;br /&gt;&lt;br /&gt;いくつか気づいた点&lt;br /&gt;&lt;br /&gt; * djangoのデフォルトのテーブルauth_userのフィールドemailはuniqueではない。なので、同じメールアドレスのユーザーをじゃんじゃん登録できる。&lt;br /&gt; * ↑これは別にいいんじゃないと思うが、こうなっていると、複数ユーザーが同じemailアドレスを使っている場合パスワードのリセット機能が動かない。（これはすでに公式のバグレポートに上がっているようだ。）&lt;br /&gt; * なので、登録時にemailの重複チェックを追加実装する必要がありました。初心者なので汚い実装方針でしたが一応チェックできるようになった。&lt;br /&gt;&lt;br /&gt; * パスワードリセットフォームがadmin標準のものだったので、自分の用意したテンプレートに差し替えた。&lt;br /&gt; * urls.pyの書き方が難しい、全てのリンクがうまくつながるようになるために、いろんな箇所を微調整。&lt;br /&gt; * メールで送られてくるURLを正しいものにするには、siteテーブルを書き換える必要があることに気づくのにしばらくかかった。&lt;br /&gt;&lt;br /&gt;djangoを使う人たちはこういうのは普通にすぐに自作してしまうんだろうか。&lt;br /&gt;Turbogearsならこういうのはコマンド一発で完了してしまうのとは対照的。&lt;br /&gt;しかしdjangoの勉強になったのでよかったと思う。&lt;br /&gt;&lt;br /&gt;なんだかいろいろわかってきたよ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-8499993514578368916?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8499993514578368916'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/8499993514578368916'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/django.html' title='django一日目の感想'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-524470351325743449</id><published>2007-08-24T09:03:00.000+09:00</published><updated>2007-08-24T09:23:36.463+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]Intel Mac OSX 10.4でstackless pythonをビルド</title><content type='html'>&lt;a href="http://zope.stackless.com/download/sdocument_view"&gt;stackless pythonのOSXバイナリ&lt;/a&gt;もあるのですがインストール先を変えたりしたかったので、自分でビルドした。&lt;br /&gt;途中１カ所つまずいたのでメモしておく。&lt;br /&gt;（これが正しいのかはよくわからないですが。）&lt;br /&gt;&lt;a href="http://www.stackless.com/pipermail/stackless/2006-July/001796.html"&gt;参考にしたのはこの記事。&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;./configure --prefix=/usr/local/stackless-python251 --enable-universalsdk --enable-framework&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;そして、できあがったMakefileにて -DSTACKLESS_FRHACK=0 という記述がある部分が１カ所あるので、そこを  -DSTACKLESS_FRHACK=1 に書き換える。（←これがほんとにこれでいいのか自信ないのだが、上の参考記事と同様の効果を得るにはこのフラグの変更でいいようだ。）&lt;br /&gt;そんで、&lt;br /&gt;&lt;pre&gt;make&lt;br /&gt;sudo make install&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;サンプルの&lt;a href="http://stacklessexamples.googlecode.com/svn/trunk/examples/factorial.py"&gt;factorial.py&lt;/a&gt;をダウンロードして、実行。&lt;br /&gt;&lt;pre&gt;ayu@~% /usr/local/stackless-python251/bin/python factorial.py &lt;br /&gt;0.0117838382721&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ひとまずうまく動いたみたい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-524470351325743449?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/524470351325743449'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/524470351325743449'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/intel-mac-osx-104stackless-python.html' title='[メモ]Intel Mac OSX 10.4でstackless pythonをビルド'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-1364977689805556372</id><published>2007-08-22T15:52:00.000+09:00</published><updated>2007-08-22T15:53:51.238+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]django-registrationの疑問</title><content type='html'>&lt;a href="http://code.google.com/p/django-registration/"&gt;django-registration&lt;/a&gt;は、djangoのSVN最新版でないと動かないようだ。&lt;br /&gt;みなさんどうしているんだろう。自作？それともみんなSVN最新版を使うのが普通なんだろうか。。。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-1364977689805556372?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1364977689805556372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1364977689805556372'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/django-registration.html' title='[メモ]django-registrationの疑問'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3157610406784964316</id><published>2007-08-22T09:13:00.000+09:00</published><updated>2007-08-22T09:15:20.872+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]【訂正】TurboGearsのwidgets-based formのpre-fill</title><content type='html'>昨日のエントリーに、&lt;a href="http://www.amazon.co.jp/exec/obidos/ASIN/4774130567/?ref=nosim"&gt;TurboGears×Python&lt;/a&gt;の&lt;a href="http://www.webcore.co.jp/"&gt;atsさん&lt;/a&gt;からじきじきにアドバイスが！&lt;br /&gt;&lt;br /&gt;以下のように、フィールド名:値という内容のdictを渡し、、&lt;br /&gt;&lt;pre&gt;class SomethingFields(widgets.WidgetsList):&lt;br /&gt;    code = widgets.HiddenField()&lt;br /&gt;    query = widgets.TextField(label=u"検索")&lt;br /&gt;&lt;br /&gt;class SomethingSchema(validators.Schema):&lt;br /&gt;    code = validators.String(not_empty=True, max=9)&lt;br /&gt;    query = validators.String(not_empty=True, max=5)&lt;br /&gt;&lt;br /&gt;class SomethingForm(widgets.TableForm):&lt;br /&gt;    fields = SomethingFields()&lt;br /&gt;&lt;br /&gt;something_form_obj = SomethingForm(fields=SomethingFields(), validator=SomethingSchema())&lt;br /&gt;&lt;br /&gt;class SomeController(controllers.Controller):&lt;br /&gt;    @expose(template='kid:somepackage.SomeController.templates.detail')&lt;br /&gt;    def detail(self, code, **kw):&lt;br /&gt;        #........&lt;br /&gt;        return dict(form=something_form_obj, value={"code": code})&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;kidのほうで、value=でその辞書を指定してやるといいのだということ。&lt;br /&gt;&lt;pre&gt;&amp;lt;span&amp;gt;&lt;br /&gt;${form(action='search', submit_text = "Search", method="get", value=value)}&lt;br /&gt;&amp;lt;p py:if="defined('message')"&amp;gt;${message}&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;/span&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;やはり、正統なやり方はきれいです。&lt;br /&gt;ありがとうございました！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3157610406784964316?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3157610406784964316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3157610406784964316'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/turbogearswidgets-based-formpre-fill_22.html' title='[メモ]【訂正】TurboGearsのwidgets-based formのpre-fill'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-824020754865922188</id><published>2007-08-21T12:45:00.000+09:00</published><updated>2007-08-21T12:50:52.755+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]TurboGearsのwidgets-based formのpre-fill</title><content type='html'>&lt;a href="http://docs.turbogears.org/FAQ"&gt;TurboGearsの公式FAQページ&lt;/a&gt;で"Answers wanted for the following questions"という欄に未だ回答なしとして載っているFAQの一つに&lt;br /&gt;&lt;br /&gt;「widgets-based formにあらかじめ値を埋め込むにはどうすればよい？」&lt;br /&gt;&lt;br /&gt;というのがあがっている。&lt;br /&gt;&lt;br /&gt;多分こんな感じでどうだろう。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;class SomethingFields(widgets.WidgetsList):&lt;br /&gt;    code = widgets.HiddenField()&lt;br /&gt;    query = widgets.TextField(label=u"検索")&lt;br /&gt;&lt;br /&gt;class SomethingSchema(validators.Schema):&lt;br /&gt;    code = validators.String(not_empty=True, max=9)&lt;br /&gt;    query = validators.String(not_empty=True, max=5)&lt;br /&gt;&lt;br /&gt;class SomethingForm(widgets.TableForm):&lt;br /&gt;    fields = SomethingFields()&lt;br /&gt;&lt;br /&gt;something_form_obj = SomethingForm(fields=SomethingFields(), validator=SomethingSchema())&lt;br /&gt;&lt;br /&gt;class SomeController(controllers.Controller):&lt;br /&gt;    @expose(template='kid:somepackage.SomeController.templates.detail')&lt;br /&gt;    def detail(self, code, **kw):&lt;br /&gt;        #........&lt;br /&gt;        something_form_obj.fields[0].attrs["value"] = code&lt;br /&gt;        return dict(form=something_form_obj)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;この最後から二行目のように、&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;フォームオブジェクト.fields[0].attrs["value"] = "あらかじめ入れたい値"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;とすればいいようだ。fields[0]というふうに番号で指定するのが気持ち悪いけれど。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-824020754865922188?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/824020754865922188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/824020754865922188'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/turbogearswidgets-based-formpre-fill.html' title='[メモ]TurboGearsのwidgets-based formのpre-fill'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3106879081628343334</id><published>2007-08-17T20:25:00.001+09:00</published><updated>2007-08-18T00:46:50.327+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]Turbogearsのidentity.currentはthread safeなのか？</title><content type='html'>turbogears/identity/__init__.pyのモジュールのグローバルに以下の記述がある。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;current= IdentityWrapper()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;この変数currentはthread safeでいてくれるんだろうか。&lt;br /&gt;IdentityWrapperの中では、cherrypy.request.identityを参照していて、cherrypyまでは追ってないけど、cherrypy.request.identityがthread localな仕組みになっていたとすれば大丈夫なんかなあ。。。&lt;br /&gt;なんか自信ないなあ。調査してみるか、、、大変。&lt;br /&gt;&lt;br /&gt;追記---&lt;br /&gt;大丈夫のようだ。&lt;br /&gt;cherrypyのコードを追うのが面倒だったので、テスト的なアプリを作って実験をし、変数currentがthread safeらしいことを確認した。&lt;br /&gt;&lt;br /&gt;というか自分はなぜ週末の夜の自宅で、仕事で出会ったバグの原因つぶしなぞしているのだろう。こういうのはまずい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3106879081628343334?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3106879081628343334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3106879081628343334'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/turbogearsidentitycurrentthread-safe.html' title='[メモ]Turbogearsのidentity.currentはthread safeなのか？'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-7648407282388713238</id><published>2007-08-17T19:44:00.000+09:00</published><updated>2007-08-17T20:06:11.459+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]TurboGears + SQLAlchemyはthread safeなんだろうか？</title><content type='html'>&lt;a href="http://www.sqlalchemy.org/docs/03/unitofwork.html#unitofwork_getting"&gt;SQLAlchemyのSessionはthread safeではない。&lt;/a&gt;&lt;br /&gt;thread safeにするには、&lt;a href="http://www.sqlalchemy.org/docs/03/plugins.html#plugins_sessioncontext"&gt;SessionContext&lt;/a&gt;を使いなさいとのこと。&lt;br /&gt;&lt;br /&gt;だが、Turbogearsのソース中にSessionContextを使っている箇所がないのはどういうことでしょう。。。。&lt;br /&gt;&lt;br /&gt;この件調査中。&lt;br /&gt;&lt;br /&gt;追記---&lt;br /&gt;使っているのをturbogears/database.pyに発見。&lt;br /&gt;&lt;pre&gt;from sqlalchemy.ext import activemapper, sessioncontext&lt;br /&gt;....&lt;br /&gt;session = activemapper.Objectstore(create_session)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Objectstoreはsqlalchemy/ext/activemapper.pyで以下の定義。&lt;br /&gt;&lt;pre&gt;class Objectstore(object):&lt;br /&gt;    def __init__(self, *args, **kwargs):&lt;br /&gt;        self.context = SessionContext(*args, **kwargs)&lt;br /&gt;    def __getattr__(self, name):&lt;br /&gt;        return getattr(self.context.current, name)&lt;br /&gt;    session = property(lambda s:s.context.current)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;たしかにこれならthread safe。安心した。&lt;br /&gt;&lt;br /&gt;追記---&lt;br /&gt;この記事投稿後15分でGoogleのインデックスに入っている。Google恐るべし。（Bloggerだからか？）&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-7648407282388713238?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7648407282388713238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7648407282388713238'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/turbogears-sqlalchemythread-safe.html' title='[メモ]TurboGears + SQLAlchemyはthread safeなんだろうか？'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-4205401018014162140</id><published>2007-08-17T07:05:00.000+09:00</published><updated>2007-08-17T07:12:12.529+09:00</updated><title type='text'>[メモ]名前付きlet</title><content type='html'>全エントリの反省を受けて勉強。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.shido.info/lisp/scheme7.html"&gt;Scheme入門 7. 繰り返し&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;名前付きletの解説に、「Schemeで繰り返しを表す標準的な方法です。」とのことだけどとても気持ち悪い。&lt;br /&gt;素人考えだけど、繰り返しは再帰関数一本にしてしまったほうがいいんではないだろうか。&lt;br /&gt;再帰で書いた方が一行少なくなりそうな例しか自分には思いつかないが、こういった仕様があるということは、この記法が自然だったり役立ったりする場面があるということだろう。奥が深いなあ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-4205401018014162140?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/4205401018014162140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/4205401018014162140'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/let.html' title='[メモ]名前付きlet'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-1915119035313907134</id><published>2007-08-16T15:12:00.000+09:00</published><updated>2007-08-16T23:57:02.135+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]Pythonによる英字の半角全角変換</title><content type='html'>↓これもっと簡潔できれいな書き方はないものだろうか。&lt;br /&gt;&lt;pre&gt;from itertools import izip&lt;br /&gt;#半角英字-&gt;全角英字変換&lt;br /&gt;HAN_CHARS = map(chr, range(ord('A'), ord('Z')+1) + range(ord('a'), ord('z')+1))&lt;br /&gt;ZEN_CHARS = map(lambda x: unichr(0xff00 + x),range(0x21, 0x21+ord('Z')-ord('A')+1) +&lt;br /&gt;                   range(0x41, 0x41+ord('Z')-ord('A')+1))&lt;br /&gt;def han2zen(word):&lt;br /&gt;    """&lt;br /&gt;    Unicodeで与えられた文字列の半角英字を全角英字に変換する。&lt;br /&gt;    """&lt;br /&gt;    for c, cc in izip(HAN_CHARS, ZEN_CHARS):&lt;br /&gt;        word = word.replace(c, cc)&lt;br /&gt;    return word&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;追記----&lt;br /&gt;多少ましなものになった&lt;br /&gt;&lt;pre&gt;import re&lt;br /&gt;HAN_UPPER = re.compile(u"[A-Z]")&lt;br /&gt;HAN_LOWER = re.compile(u"[a-z]")&lt;br /&gt;def han2zen(word):&lt;br /&gt;    word = HAN_UPPER.sub(lambda m: unichr(ord(u"Ａ") + ord(m.group(0)) - ord("A")), word)&lt;br /&gt;    word = HAN_LOWER.sub(lambda m: unichr(ord(u"ａ") + ord(m.group(0)) - ord("a")), word)&lt;br /&gt;    return word&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;追記----&lt;br /&gt;調子に乗って一般化してみた。上のような変換関数を大量生産できる関数だ。&lt;br /&gt;Unicodeの列を平行移動するようなイメージの変換を生成します。&lt;br /&gt;&lt;pre&gt;#!/usr/bin/python&lt;br /&gt;# _*_ coding: euc_jp _*_&lt;br /&gt;import re&lt;br /&gt;&lt;br /&gt;def replace_sequence(*transform_rules):&lt;br /&gt;    """&lt;br /&gt;    Unicode文字コードで連続した文字の列を対応する別の連続する文字に変換する関数を作る。&lt;br /&gt;&lt;br /&gt;    引数:&lt;br /&gt;    transform_rules 変換ルールを表す文字列を任意個の引数で与える。&lt;br /&gt;    一つの変換ルールは３文字のUnicode文字で表現されます。&lt;br /&gt;&lt;br /&gt;    変換ルール記述例&lt;br /&gt;    u"AZＡ"  一文字目は変換元の文字列の先頭、二文字目は変換元文字列の末尾、三文字目は変換先文字列の先頭を表します。&lt;br /&gt;&lt;br /&gt;    この変換ルールを引数に並べます。&lt;br /&gt;    &lt;br /&gt;    """&lt;br /&gt;    rules = map(lambda x: (re.compile(u"[%s-%s]" % tuple(x[:2])), x[2], x[0]), transform_rules)&lt;br /&gt;    def henkan(word):&lt;br /&gt;        for pattern, start, src_start in rules:&lt;br /&gt;            word = pattern.sub(lambda m: unichr(ord(start) + ord(m.group(0)) - ord(src_start)), word)&lt;br /&gt;        return word&lt;br /&gt;    return henkan&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    num_han2zen = replace_sequence(u"09０")&lt;br /&gt;    num_zen2han = replace_sequence(u"０９0")&lt;br /&gt;    alpha_han2zen = replace_sequence(u"AZＡ", u"azａ")&lt;br /&gt;    alpha_zen2han = replace_sequence(u"ＡＺA", u"ａｚa")&lt;br /&gt;&lt;br /&gt;    print num_han2zen(u"0120-116")&lt;br /&gt;    print num_zen2han(u"１８８−００１３")&lt;br /&gt;    print alpha_han2zen(u"ABCを習いました。")&lt;br /&gt;    print alpha_zen2han(u"世界のＳＯＮＹ")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;この関数replace_sequenceを使うと、上で必死こいてつくってた半角英字-&amp;gt;全角英字関数はこの一行で作成できる。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;alpha_han2zen = replace_sequence(u"AZＡ", u"azａ")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;使う時はこのalpha_han2zenを関数として呼び出し、&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;print alpha_han2zen(u"ABCを習いました。")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;で行ける。&lt;br /&gt;&lt;br /&gt;上のプログラムの実行結果。&lt;br /&gt;&lt;pre&gt;ayu@~/work% ./sample.py&lt;br /&gt;０１２０-１１６&lt;br /&gt;188−0013&lt;br /&gt;ＡＢＣを習いました。&lt;br /&gt;世界のSONY&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;これはちょっと便利かも。会社に持っていこう。&lt;br /&gt;こういうプログラムを書いていると、今更関数型言語を勉強しなくても、Pythonで、まあいいのかなという気にもなり、またしても自分の進歩が阻害されてしまう気がする。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-1915119035313907134?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1915119035313907134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/1915119035313907134'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/python.html' title='[メモ]Pythonによる英字の半角全角変換'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3418001927112516723</id><published>2007-08-11T09:07:00.000+09:00</published><updated>2007-08-11T10:19:37.748+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Turbogearsピンポイントドキュメント一覧</title><content type='html'>前エントリで触れたんだが、「ドキュメント重要」ということなので、自分が目を通すことの多いTurbogears関連のドキュメントの目次だけでも作っておこう。（日本語訳までできないのが残念ですが。）&lt;br /&gt;Turbogearsはコードの大半をツールが自動生成してくれますので、ちょっとした作法なんかは自動生成された部分をチラ見するだけで、自分なりに追加機能を書き始めることも可能です。&lt;br /&gt;ですが、やはり一貫した知識も必要なので、そのときはこういったドキュメントを読みます。&lt;br /&gt;&lt;br /&gt;* &lt;a href="http://www.python.jp/Zope/workshop/200706/turbogears.pdf"&gt;Python Workshop the Edge 2007での柴田さんのハンズオン資料(PDF/日本語です)&lt;/a&gt;&lt;br /&gt;入門記事です。自分がTurbogearsを使うきっかけになったのがこれでした。&lt;br /&gt;&lt;br /&gt;* &lt;a href="http://docs.turbogears.org/1.0#reference"&gt;Turbogears公式リファレンス&lt;/a&gt;&lt;br /&gt;Turbogearsの公式リファレンスです。Turbogearsでは各種デコレーターを使いますのでその使い方はここでよく見ることになります。&lt;br /&gt;&lt;br /&gt;以下、各論。&lt;br /&gt;* &lt;a href="http://patrickhlewis.googlepages.com/registration.html"&gt;ユーザー登録機能のためのregistrationパッケージ&lt;/a&gt;&lt;br /&gt;このトップページに文書が掲載されている。最近のWEBアプリでは、まずユーザー登録はどうしようかと考えるので、このすぐ使える機能一式のパッケージは重宝。&lt;br /&gt;（登録、メールでの認証、ログイン、ログアウト、パスワード忘れ対策全部入り。）&lt;br /&gt;&lt;br /&gt;* &lt;a href="http://www.sqlalchemy.org/docs/03/"&gt;Modelを作る際に使うSQLAlchemyのドキュメント&lt;/a&gt;&lt;br /&gt;モデルの作成は奥が深い。そのぶん、ドキュメントもちょっと規模が大きめです。&lt;br /&gt;　* &lt;a href="http://www.sqlalchemy.org/docs/03/sqlconstruction.html"&gt;低レベルなSQLを意識した使い方&lt;/a&gt;&lt;br /&gt;　　SQL脳から完全に脱却できない自分のための機能。。。&lt;br /&gt;&lt;br /&gt;　* &lt;a href="http://www.sqlalchemy.org/docs/03/datamapping.html"&gt;高レベルなMapperを使った操作&lt;/a&gt;&lt;br /&gt;　　テーブルのリレーションを事前に定義して楽したい場合はこちら。&lt;br /&gt;　　パフォーマンスを改善するには、&lt;br /&gt;　　&lt;a href="http://www.sqlalchemy.org/docs/03/adv_datamapping.html#advdatamapping_properties_relationoptions"&gt;lazy=True&lt;/a&gt;&lt;br /&gt;　　&lt;a href="http://www.sqlalchemy.org/docs/03/adv_datamapping.html#advdatamapping_properties_deferred"&gt;deferred設定&lt;/a&gt;&lt;br /&gt;　　&lt;br /&gt;&lt;br /&gt;* &lt;a href="http://docs.turbogears.org/1.0/CRUDTemplate"&gt;各modelのCRUDを作るためのtgcrud&lt;/a&gt;&lt;br /&gt;モデルを定義したら、これで一気にCRUDを作成する。&lt;br /&gt;&lt;br /&gt;* &lt;a href="http://docs.turbogears.org/1.0/FormValidationWithSchemas?highlight=%28form%29"&gt;Formのバリデーターについて&lt;/a&gt;&lt;br /&gt;Formの扱いは、上に挙げているregistrationやtgcrudが生成するコードを見るとだいたいわかるのですが、ちゃんと知りたいならこのページがおそらくいいのでは。&lt;br /&gt;&lt;br /&gt;* &lt;a href="http://www.kid-templating.org/guide.html"&gt;Kidテンプレート書式一覧&lt;/a&gt;&lt;br /&gt;* &lt;a href="http://www.webcore.co.jp/techinfo/python/kid-specification.html"&gt;その日本語訳を発見！&lt;/a&gt;&lt;br /&gt;一通り仕組みができてきたら、実際のモデルのデータをページに埋め込んだりする段階にくるはず。その頃には、このテンプレートの書式一覧が必要です。&lt;br /&gt;（柴田さんの日本語訳があることを今調べてて知った。。。。）&lt;br /&gt;&lt;br /&gt;自分はSQLAlchemyとKidを使っていますので、上のようなラインナップです。&lt;br /&gt;でもKidはXML的に妥当なテンプレートを書く必要があって、ちょっと厳しいなと思う。できれば差し替えたいところ。&lt;br /&gt;SQLAlchemyには大満足。やりたいことが全てきれいにできる。パフォーマンスの調整も思いのまま。このツールはすばらしい。（普段仕事でJAVAのS2Daoも使うが、SQLAlchemyを知ってからはS2Daoがしんどくてしょうがない。。。）&lt;br /&gt;&lt;br /&gt;自分もTurbogearsはまだここ１ヶ月ぐらいしか使ってませんので全くの素人レベルです。今後ここに役立つ文書のページを追記していきます。。。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3418001927112516723?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3418001927112516723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3418001927112516723'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/turbogears_11.html' title='Turbogearsピンポイントドキュメント一覧'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6537255470741301782</id><published>2007-08-11T08:21:00.000+09:00</published><updated>2007-08-11T08:44:18.191+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>ドキュメントが重要</title><content type='html'>最近職場でTurbogearsでつくった社内ツールを公開している。&lt;br /&gt;いろいろな機能を次々追加しているので、けっこうな規模のツールになる予感がしてきた。&lt;br /&gt;&lt;br /&gt;やはりこういうフレームワークを使うと仕事がとても早いので、うちの職場全体でもこういうPythonのフレームワークをつかっていったらどうだろうかという話も出てきた。&lt;br /&gt;&lt;br /&gt;ただそうなるとTurbogearsの文書のラインナップでは仕事に使っていくにはちょっときついかなと思った。&lt;br /&gt;&lt;br /&gt;まず職場の全員が英語に慣れているわけでもないので、公式文書の日本語訳がないのはつらい。&lt;br /&gt;&lt;br /&gt;次に、Turbogearsのような「詳細は他の(KidなりSQLALchemyなりの）文書を見てね」という文書体系では、ドキュメント内の探索の仕方を、各部品ごとに変える必要がある。&lt;br /&gt;&lt;br /&gt;こういうのは慣れなので日々Pythonに興味を持って情報を自ら集める人にとってはなんてことない。&lt;br /&gt;文書が英語だろうと、ちょっとふぞろいだろうと、サンプルコードやいろんな人のblog記事を探索しながらなんとかなる。&lt;br /&gt;ただ、職場では「本来はJAVAが一番好きだけど、仕事なのでしょうがなくPython使うよ」という人も当然のように存在する。&lt;br /&gt;そういった人のための情報を用意できたときに初めてフレームワークが「実務に使える」という形で浸透していくんじゃないかなあと思った。&lt;br /&gt;&lt;br /&gt;こういったことを考えるとdjangoの文書の日本語訳の存在はすばらしいことと思う。&lt;br /&gt;自分の場合はこれから勉強していかないといけないけれど。&lt;br /&gt;&lt;br /&gt;（休日に仕事のことを考えるのはほどほどにしなければ、、、）&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6537255470741301782?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6537255470741301782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6537255470741301782'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/blog-post_11.html' title='ドキュメントが重要'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-4686852613256748804</id><published>2007-08-09T09:08:00.000+09:00</published><updated>2007-08-09T09:09:42.510+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[メモ]SQLAlchemyのMSEnum型</title><content type='html'>&lt;a href="http://www.sqlalchemy.org/docs/03/sqlalchemy_databases_mysql.html#docstrings_sqlalchemy.databases.mysql_MSEnum"&gt;MSEnum&lt;/a&gt;は引用符内にさらに引用符を書かねばならないという罠。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Column('myenum', MSEnum("'foo'", "'bar'", "'baz'"))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-4686852613256748804?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/4686852613256748804'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/4686852613256748804'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/sqlalchemymsenum.html' title='[メモ]SQLAlchemyのMSEnum型'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3116754447977967727</id><published>2007-08-09T08:13:00.000+09:00</published><updated>2007-08-09T08:18:39.441+09:00</updated><title type='text'>[メモ]最近気に入っている方法</title><content type='html'>1. Gnu Screenの0番目に常にemacsを開いておく。&lt;br /&gt;2. 仕事の進捗はemacsのChangelogでメモ。&lt;br /&gt;3. 一日の仕事が終わるときにもChangelogにメモ。&lt;br /&gt;4. Screenのデタッチで閉じて帰宅。&lt;br /&gt;5. 次の日出社したらscreen -r でChangelogが即開いて見える。&lt;br /&gt;&lt;br /&gt;こういうのっていいですね。&lt;br /&gt;サーバーがずっと動きっぱなしの会社だから可能な方法。&lt;br /&gt;emacsはまだまだ便利に使えそうなのでもっと勉強していこう。。。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3116754447977967727?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3116754447977967727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3116754447977967727'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/blog-post_09.html' title='[メモ]最近気に入っている方法'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-7734247798765958767</id><published>2007-08-08T16:06:00.001+09:00</published><updated>2007-08-10T10:56:41.929+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>SQLAlchemyでMySQLのyear型が使えない</title><content type='html'>&lt;a href="http://www.sqlalchemy.org/docs/03/sqlalchemy_databases_mysql.html#docstrings_sqlalchemy.databases.mysql_MSYear"&gt;MSYear&lt;/a&gt;というmysql用の型のクラスがあるのだが、実際にcreate table文を作ると、VARCHAR型として作られてしまう。&lt;br /&gt;&lt;br /&gt;この件調査中。&lt;br /&gt;&lt;br /&gt;追記----&lt;br /&gt;これがSQLAlchemyの方針にとって正しいのか不明なんだけど、sqlalchemyのソースのsqlalchemy/databases/mysql.pyのMSYearに以下のget_search_list(self)メソッドを追記すれば一応解決する。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class MSYear(sqltypes.String):&lt;br /&gt;    """MySQL YEAR type, for single byte storage of years 1901-2155"""&lt;br /&gt;&lt;br /&gt;    def get_col_spec(self):&lt;br /&gt;        if self.length is None:&lt;br /&gt;            return "YEAR"&lt;br /&gt;        else:&lt;br /&gt;            return "YEAR(%d)" % self.length&lt;br /&gt;&lt;br /&gt;    def get_search_list(self):&lt;br /&gt;        return [self.__class__]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;year型がMySQLの型の中でもすごく特殊な実装なので、非常に難しい部分なんだろう。&lt;br /&gt;ちょっとSQLAlchemyの作者の方々にメールを送ってみようかなあ。&lt;br /&gt;&lt;br /&gt;追記---&lt;br /&gt;&lt;a href="http://groups.google.com/group/sqlalchemy/browse_thread/thread/c94e11db580acc95/48c17bff8e181ccd#48c17bff8e181ccd"&gt;メールを送ってみた。&lt;/a&gt;&lt;br /&gt;こういうのを送るのはどきどきするなあ。英語きっとぐちゃぐちゃだし。通じればいいんだけど。&lt;br /&gt;&lt;br /&gt;追記---&lt;br /&gt;&lt;a href="http://groups.google.com/group/sqlalchemy/browse_thread/thread/c94e11db580acc95"&gt;返事がきた。&lt;/a&gt;&lt;br /&gt;0.3のメンテナンスブランチ＆0.4では修正済みとのことです。&lt;br /&gt;あああ、こういう最新版をチェックせずに指摘メールを送ったり、（さらには自分で修正を試みたり）というのはいけないことだなあと思った。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-7734247798765958767?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7734247798765958767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/7734247798765958767'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/sqlalchemymysqlyearga.html' title='SQLAlchemyでMySQLのyear型が使えない'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-3189547218236659611</id><published>2007-08-05T13:43:00.000+09:00</published><updated>2007-08-05T13:45:31.126+09:00</updated><title type='text'>[メモ]Mac OSXにgtagsをインストール</title><content type='html'>&lt;pre&gt;&lt;br /&gt;$ sudo port install global&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;これで、/opt/local/bin/gtags にインストールされる。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-3189547218236659611?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3189547218236659611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/3189547218236659611'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/mac-osxgtags.html' title='[メモ]Mac OSXにgtagsをインストール'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5771870301252721821.post-6011122411248466750</id><published>2007-08-05T12:22:00.000+09:00</published><updated>2007-08-05T13:02:08.556+09:00</updated><title type='text'>[メモ]LL魂感想</title><content type='html'>今思い出せるものだけメモ。&lt;br /&gt;&lt;br /&gt;== Language Update ==&lt;br /&gt; Python::&lt;br /&gt;「Pythonは１０年使える言語」というポイントは、今まで意識していなかった。&lt;br /&gt;これまで５年ぐらいPythonを使っていますが、ずっと安定して使えていたり、新バージョンが出た時に、当たり前のように後方互換だったりしたことに、陰ながら支えてもらっていたことに気づき、感謝の気持ちを覚えた。&lt;br /&gt;&lt;br /&gt; Ruby::&lt;br /&gt;Lazy collectionの話は思わず「おおお！」と思ってメモを取ったのだが、その後手厳しい修正が。でもああやって言及したということは、実装したいってことだからこれから数年以内に実現するんだろうか。&lt;br /&gt;&lt;br /&gt; PHP::&lt;br /&gt;何もあそこまで「どんより感」を全面に出さなくてもよかったのではないだろうか。（LLが初めて開催された年もそうであった。)&lt;br /&gt;GreeとかSidefeedとかcheckpadのような華々しい実績に言及しないと。&lt;br /&gt;数年前は自分もPHPを使っていましたが、言語の仕組みとしての難点はほんとうに多々あれど、「とにかくWEBが作れる」というのは事実。&lt;br /&gt;&lt;br /&gt; Perl::&lt;br /&gt;Perl6か、、、。大変そうだなあ。&lt;br /&gt;Perl5.10で"//"という記法が新登場とのこと。こういう方向性はPythonとは正反対でおもしろい。Pythonではありえない。&lt;br /&gt;&lt;br /&gt; R::&lt;br /&gt;今会社の隣の席の人がしきりにオススメしてくる言語なので興味があった。scheme+S言語という点が興味を引く。schemeか、、去年途中まで勉強してやめてるな。。。&lt;br /&gt;&lt;br /&gt; Clean::&lt;br /&gt;速度が速いということに興味を持った。&lt;br /&gt;昨年仕事でサンプル的にHaskellを使ったことがあるが、７００万行（20G)のテキストファイルを処理するのに速度的にまったく不足していた。が、この言語ならいけるんじゃないだろうか。Haskellにそっくりなのですんなりつかえるかもしれない。Intel Macのサポートが次バージョンからだそうなので心待ちにしよう。&lt;br /&gt;&lt;br /&gt; Lua::&lt;br /&gt;「俺様言語」のコーナーで各種自作言語がライバル視していたのが特徴的。&lt;br /&gt;&lt;br /&gt;== 俺様言語の作り方 ==&lt;br /&gt; Xtal::&lt;br /&gt;あちこちのブログで話題になっているが、プレゼンが（というか作者が）抜群に天然。&lt;br /&gt;C++との連携を主眼にしているということは、C++の資産が全て使えるということだから実はすごく便利かもしれない。ただ自分の場合はPytonとC++の連携が今のところうまく行っているので、使い道を考えにくい。&lt;br /&gt;Pythonと簡単に連携できないだろうか。Pythonでパフォーマンスが欲しいところをC++で書くのではなく、Xtalで書ければ、Pythonとのギャップがまだ小さいだろうから、簡単にならないだろうか。&lt;br /&gt;&lt;br /&gt; ひまわり、なでしこ::&lt;br /&gt;会場で最も注目を浴びていたと思う。自分も強く惹かれた。&lt;br /&gt;ほんとうに読みやすそうだ。（日本人Only）&lt;br /&gt;&lt;a href="http://nadesi.com/doc/reference/index.htm"&gt;文書&lt;/a&gt;の充実もすごい。関数定義はできないんだろうか。。。&lt;br /&gt;&lt;br /&gt;== VM魂 ==&lt;br /&gt;プレゼンがどれもおもしろかったが、なんだか各実装の対決みたいなピリピリした空気がでていてちょっと苦手だった。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;以後用事のため途中退席。ライトニングトーク見たかった。。。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5771870301252721821-6011122411248466750?l=hiroshiykw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6011122411248466750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5771870301252721821/posts/default/6011122411248466750'/><link rel='alternate' type='text/html' href='http://hiroshiykw.blogspot.com/2007/08/ll_05.html' title='[メモ]LL魂感想'/><author><name>hiroshiykw</name><uri>http://www.blogger.com/profile/01527114074913563640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry></feed>
