Displaying posts written in

4月 2010

『Webを支える技術』のER図が変な件

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESSプラスシリーズ)

すごく良い本なんですが、どうしても気になってしまったので、この部分だけ先に書きます。297ページ、17.2『関係モデルからの導出』で示されている郵便番号の関係モデルは変だと思います。ER図は次のようになっています:

「郵便番号データのER図」、『Webを支える技術』298ページより

これのどこが変かというと……要するに正規化が不十分なので、いろいろなところが変です。

  • 郵便番号エンティティが都道府県エンティティと市区町村エンティティを別々に参照しているので、「東京都のIDと大阪市のIDをもつ郵便番号」のようなものが作れてしまいます。
  • 市区町村エンティティが都道府県エンティティに依存していないので、「どの都道府県にも属さない市区町村」が作れてしまいます。
  • 町域エンティティが郵便番号エンティティに入り込んでいます(町域名フリガナは町域名に関数従属する)
    • 町域と都道府県-市区町村の関係が保証されていないので、「東京都のIDと大阪市のIDと愛知県の町域名」みたいなものが作れてしまいます。

実装のことはさておき、純粋にデータの数的な関係に着目するなら、モデルは次のようになるのではないかと思います。

郵便番号データのER図・作図例

(モデルの”意味”を明確に示すために、あえて数値のIDではなく都道府県名や郵便番号などをそのままPRIMARY KEYとしています。また町域と郵便番号の関係などは日本郵便のサイトを参考にしています)

『Webを支える技術』300ページでは「階層構造は関係モデルからはわかりにくい」とありますが、それは誤解だと思います。普通は正規化を進めれば進めるほどエンティティの階層は深くなっていくはずです。市区町村->町域という階層も上のモデルからは自明です。むしろいかに階層を(正規化を)崩してリソースを抽出するかのほうが難しいと思います。

私はモデリングの専門家ではありませんので、勘違いしている点があったら教えてください。

まぐれ—投資家はなぜ、運を実力と勘違いするのか

まぐれ―投資家はなぜ、運を実力と勘違いするのか』の感想。

著者は『ブラック・スワン』のナシーム・ニコラス・タレブ氏。この本は『ブラック・スワン』の一つ前にあたる著作。

日本語の副題「投資家はなぜ、運を実力と勘違いするのか」が的確に内容を要約している。哲学やら社会学やら心理学やら、かなり幅広い話題を扱っているが、結局のところ「市場においてトレーダーはどう振る舞うべきか」というテーマが中心にあって、トレーダーとしての自身の経験と運用哲学が根底にある。非合理的な振る舞いを繰り返す同僚たちをバカだアホだとこき下ろしながらも、実はその一部は自分自身のことで、人間はどうやっても合理的になりきれないと告白する。自分が愚かであることを理解し、受け入れた上で、うまく向き合っていく方法を身につけるしかないのだと。

この本は著者がそういう自分のやり方に、自分で納得するために書いているのではないか、と思える部分がある。結構ドギツイ文章を書く人で、読んでいてうんざりしてしまうことも多かったが(特に前半)、実際はとても正直な人なのだろう。

以下、特に印象に残った内容を6章以降から。この本は6章から俄然面白くなるので、6章までは頑張って読み進めることをお勧めする。

  • 「確率」と「期待値」を混同してはいけない。0.7の確率で1%の上昇、0.3の確率で10%下落なら、期待値は2.3%の下落だから下落にかけた方が良い。勝つ可能性が高くても、それで儲かるとは限らない。
  • 確率と期待値を混同してしまう原因の一つは、確率を習うときにコインの裏表のような対称な分布を使うから。正規分布も典型的に対称な分布。
  • 稀な事象は、めったに起こらないというだけで、起こるときには起こる。そしていつも思いがけないときに起こるので(そうでなければ稀な事象ではない)、起こったときには心理的なバイアスによって適正な値段がつかないことが多い。よって大きく儲けるチャンスがある。
  • 人間は刺激の大きさよりも刺激の有無に敏感な傾向がある。だからトータルで利益が出るかどうかではなく、「損失の回数が少なく、利益の回数が多い」ような戦略を選んでしまう(日本で毎月分配型の投資信託が好まれる理由?)
  • ある理論が「検証可能」であるということは、数量的な要素に分解して統計的に調べることができるということ。よって間違っていると証明すること(反証)はできるが、正しいと証明することはできない。「(今まで)〜ということはなかった」は「(これからも)〜ことはない」とイコールではない。
  • 科学的と言える理論は2種類しかない。(1).反証されて、間違いであることが分かっている理論。(2).まだ反証されていないが、いずれ反証される可能性のある理論。反証できない理論は科学ではない。
  • 取引戦略を立てる時も反証可能性について考えることは重要。どういう状況になったら自分の戦略が間違っていたことになるのかをはっきりさせておき、そうなったときには即座に手仕舞う(ストップロス)。

そして個人的にこの本の中で最も面白いと思ったのは、無限匹のサルがタイプライタを叩く話(170ページ)。サルが無限匹いれば、中には偶然に名作を書き上げてしまう奴が必ず一匹は現れる。ここまでは割とよく聞く例え話だ。しかしここからが面白い:名作を書き上げたその一匹があなたのもとを訪れて、自分で書き上げたその「過去の実績」を示し、パトロンになってくれと頼んできたらどうだろう!そのサルがその名作を書き上げたのは紛れもない事実なのだ。そしてその他大勢のサルたちは皆(特に目立った成果を挙げられなかったのだから当然)どこかに行ってしまった。あなたの目の前にいるのは”奇跡のサル”だけだ……。

どんなに無能な集団でも、母集団が十分大きければ、必ず一定数は成功する。成功しなかった大多数は消えてしまうので、あとから見ると成功した一部しか目に入らない(これを生存バイアスという)。よって「過去にどれだけの実績を上げてきたか」が分かっても意味がない。当初その人が属していた母集団の大きさをこそ知らなければいけない。

複雑なコンポーネントの単体テスト

環境: CakePHP1.3

単純な場合のテスト方法はクックブックに載っていますが、 より複雑な場合(コントローラや他のコンポーネントと連携する場合)は多くの準備作業が必要です。

その作業を省略するための ComponentTestCase クラスを作りました。ソースコードはとりあえずgistに置いておきます。

component_test_case.php

適当な場所 app/tests/libs などに置いてテストファイルの中で読み込んでください。

Fooコンポーネントをテストする場合の例は次のようになります。

require_once (TESTS .'libs/component_test_case.php');
 
class FooTestCase extends ComponentTestCase
{
  //コントローラの $components と全く同じ書式
  var $components = array('Foo' => array('a' => 'b'));
 
  function testAdd() {
    //$this->Controller でコントローラにアクセスできる
    $this->Controller->set(array('var1' => 1, 'var2' => 2));
 
    //$this->{コンポーネント名} でコンポーネントのインスタンスにアクセスできる
    $this->assertEqual(3, $this->Foo->add());
 
    //Fooの中で別のコンポーネントBarを読み込むことも可能
    //$components = array('Bar');
    $this->Foo->Bar->barmethod();
  }
}

モデルを使用することもできます。

class BarTestCase extends ComponentTestCase
{
  var $components = array('Bar');
  var $uses = array('User');
  var $fixtures = array('app.user');
 
  function testSomething() {
    //Barの中で、Controller経由でモデルにアクセスできる
    //$this->Controller->User
    $result = $this->Bar->doSomething();
  }
}

初期化パラメータを変えてテストしたい場合は _createController メソッドを使って直接 Controller を生成します。

class FooTestCase extends ComponentTestCase
{
  function testAdd() {
    $controller = $this->_createController(array('Foo' => array('c' => 'd')));
    $controller->set(array('var1' => 1, 'var2' => 2));
 
    //$this->{コンポーネント名} でアクセスすることはできない
    $this->assertEqual(3, $controller->Foo->add());
  }
}

デフォルトの初期化は startTest メソッドの中で行われるため、オーバーライドすることで柔軟な設定が可能です。 例えばメソッド名に _disableAutoLoad が入っているときだけ自動処理を停止する、といったことができます。

class FooTestCase extends ComponentTestCase
{
  var $defaultConfig = array('Foo' => array('a' => 'b'));
 
  function startTest($method) {
    if(preg_match('/_disableAutoLoad/', $method)) {
      $this->components = array();
    } else {
      $this->components = $this->defaultConfig;
    }
    parent::startTest($method);
  }
 
  function testAdd() {
    $this->Foo;
  }
 
  function testAdd2_disableAutoLoad() {
    $c = $this->_createController(array('Foo' => array('c' => 'd')));
  }
}

テストに使用するコントローラのクラスを切り替えることもできます。

class BarTestCase_TestController extends Controller
{
   //独自のテスト用ロジックを実装する...
}
 
class BarTestCase extends ComponentTestCase
{
  var $controllerClassName = 'BarTestCase_TestController';
}

TestCase内でのコントローラの初期化については Testing CakePHP Controllers the hard way | Mark Story を参考にしました。

Google App Engine習作: Thumbs.db reader

Google App EngineでWindows XPのThumbs.dbを読み出すWebサービスを作りました。

Thumbs.db reader

アップロードされたThumbs.dbを解析して、サムネイル画像(JPEGファイル)を取り出します。結果はdata:スキームを使ってimgタグで一覧表示するか、zipでまとめて取得するか選べます。アップロードされたファイルはサーバ側には保存されません。

Thumbs.dbの解析にはvinettoというプログラムを改造して使っていますが、GAEの制約によってtype 2という形式のものしか解析できません。

コマンドラインから使用する場合は http://thumbsdbreader.appspot.com/zip というURLに対してPOSTリクエストを送信してください。zipファイルが標準出力に出力されます。

curl -X POST --data-binary @Thumbs.db http://thumbsdbreader.appspot.com/zip > files.zip

ヤバい経済学 [増補改訂版]

ヤバい経済学 [増補改訂版]の感想。

科学としての経済学

経済学は計測の学問だと言う。それは経済学が”科学”であるための方法なのだろうと思う。

自然科学において仮説を検証するには実験を行う。狙った現象が観測可能になるようなうまい状況を整えて、仮説に整合的な結果が生じるかどうか調べる。しかし経済学の対象は現実そのものなので、仮説を検証するための実験を行うことは難しい。代わりに現実の中で得られた膨大なデータに統計学的な分析を加えて、ある現象の原因と結果がうまい具合に立ち現れるよう工夫する。

そういう意味で、経済学におけるあらゆる種類の実験は、あらゆる条件下で常時行われていると言えるかもしれない。

インセンティブは発明されたものである

インセンティブとは「発明」されるものだと言う。もっと稼ぎたいからがんばって働く、警察に捕まるのが怖いから不正はしない。現代社会では当然のことと考えてしまいがちだが、これらは普遍的な原理でも何でもなく、そういう風に行動するようにインセンティブが設計されているのだ。ここで私はおれカネゴンさんの日記の次の箇所を思い出した:

ところで、「よいことをするとよい報いがある」「悪いことをするとそれなりの報いがある」という因果は、実はまったくの非合理的な信念 (irrational belief)で、この因果は合理的なのだ(筋が通っている)とすべての人によって信じられているということ以外にこれを支える根拠は本来どこにもなかったりする。かといって、論理療法とかを真似て、にわかハッカーのように「これは非合理的です」と斬って捨てたままにしていいことにはならない。というのは、人類は数千年かけて、本来は非合理的であるはずのこの信念が本当になるように全力を尽くしてきたからで、その最たるものが法律なのだと思う。

法律はインセンティブを導入するための強力な手段の一つだ。そして経済学者は、インセンティブを発明したり設計したり導入したりすることで、あらゆる問題は解決できると考える(らしい)。

『割れ窓理論』という通念

150ページからは有名な「割れ窓理論」をもとにしたニューヨーク市の防犯対策と、実はそれは全く効果がなかったという著者の主張が述べられている。主張の根拠は次の3点にまとめられる:

  1. 犯罪の急減はニューヨーク市にけではなく、全米で起こっていた。
  2. 対策が始まったのは1994年からだが、1990年には既に減少が始まっていた。
  3. 対策の内容とは無関係に、警官が増員されていた(警官が増えれば犯罪が減ることは証明できる)。

これだけの証拠があったのに、なぜ割れ窓理論に元づく説明が広く世間に受け入れられ、「通念(conventional wisdom)」となったのか。『通念は、単純で都合がよくて居心地良さそうで、実際居心地がよくなければならない』と著者は言う。確かに、割れ窓理論が提示する筋書きは心地よい。身近なところで起こる軽微な犯罪を徹底的に取り除いていけば、やがて街から犯罪の臭いが消え、殺人や強盗といった重大な犯罪も減少する……。警察が、街のみんなが頑張ったから犯罪は減ったのだ!というのは、ぜひとも信じたくなる考え方だ。

「銃とプール、危ないのはどちらか」、「ヤクの売人はなぜママと住んでいるのか」、「黒人と白人の成績格差は何が原因か」といった本書の話題の多くは、基本的に米国人の通念を前提としており、日本人が読んでも「ふーん」という以上の感想を持つのは難しい。例えばアメリカでは近年、子供に変な名前をつける親が増えているらしい。日本でも同じような話は聞く。しかしそこから親の傾向とか子供の成績との相関を調べたら、アメリカとは全く別の結論になるのではないかという気がする。

世界一シンプルな経済入門 経済は損得で理解しろ!

世界一シンプルな経済入門 経済は損得で理解しろ! 日頃の疑問からデフレまでの感想。

飯田泰之先生の経済入門本。発売がなぜかエンターブレインだったり、帯にでかでかと勝間和代さんの写真が載っていたり、外観は良く分からないことになっているが、内容はとてもとても分かりやすかった。

主に3章以降から、特に印象に残った部分をメモ。

  • 不況には2種類あり、また2種類しかない。すなわちスタグフレーションか需要不足型不況である。
  • 経済政策には成長政策、安定化政策、再配分政策の3種類があり、それぞれ目的も効果も異なる。間違った状況で間違った政策をとると効果が出ない
  • 60〜70年代の世界はスタグフレーションに陥っており、「成長政策」こそが必要だったが、「安定化政策」をとってしまった。また90年代以降の日本は需要不足型不況で「安定化政策」が必要なのだが、「成長政策」をとってしまった(小泉改革)。
  • 成長政策は中長期的な潜在GDPの上昇に効果がある。代表的な政策は「民営化」と「規制緩和」。
  • 安定化政策は潜在GDPと実質GDPを安定的に一致させる。経済の安定は中長期的な潜在GDPの上昇にも欠かせない。代表的な政策は「財政政策(公共事業/給付金)」、「金融緩和政策」
  • 再配分政策が必要なのは、セーフティネットを整備して成長のための挑戦をしやすくするため。過剰に再配分をやると逆効果。
  • 2002年から2007年までの「いざなぎ超え」は、それだけの期間回復基調が続いたというだけで、需給ギャップはほとんど埋まっていなかった。成長率そのものも低く、結局のところ需要不足型不況が続いていた。
  • デフレ下では名目金利がどれだけ低くても、実質金利=名目金利-予想インフレ率は高くなり、企業の投資活動は萎縮する。
  • ミクロの視点では正しくとも、それが合成されたマクロの世界では正しくなくなることを「合成の誤謬」という。デフレ下の個人個人の選択は合理的なので責めようがないが、最終的には自分たちの首を絞めることになる。
  • 税収の増加率≒名目GDP成長率<国債の名目利子率 が成り立っている限り、どれだけ無駄を省いたとしても、必ず財政は破綻する。

Amazonのレビューにも書いてあるが、一部で図が間違っている。あと誤植が割と多い。そこだけが気になった。

Google App EngineでMakoを使う

Google App EngineでテンプレートエンジンMakoを使う方法……といっても、特別なことは何も必要ない。アーカイブを展開してできた mako ディレクトリをアプリケーションディレクトリにコピーすれば使えるようになる。

日本語を使う場合の注意点についてはこちらを参照のこと。GAEではRequestもResponseもDatastoreもUnicodeに対応しているので、あまり神経質にならなくても大丈夫。

コード例

  • テンプレートファイルは views/ ディレクトリに置く
  • デフォルトの拡張子は .html
  • エンコーディングは utf-8 固定

次のようなベースクラスを用意しておく。

from mako.template import Template
from mako.lookup import TemplateLookup
 
class RequestHandler(webapp.RequestHandler):
    viewDir = os.path.join(os.path.dirname(__file__), "views")
    lookup = TemplateLookup(directories=[viewDir], input_encoding='utf-8')
 
    def render(self, view, vars={}, type=".html"):
        tmpl = self.lookup.get_template(view + type)
        return tmpl.render_unicode(**vars)
 
    def display(self, *args, **named):
        self.response.out.write(self.render(*args, **named))

サブクラスでは display または render メソッドでレンダリングを行う。

class MainPage(RequestHandler):
    def get(self):
        self.display('index', {"var": "value"})

Flash(ActionScript3)で新しいウィンドウを開く

ActionScript3でポップアップブロックを回避して新しいウィンドウを開くには、次のようにすれば良いらしい。

  • SafariやGoogle ChromeなどKHTML系のブラウザではnavigateToURLを使う
  • IEやFirefoxではExternalInterfaceでJavaScriptのwindow.openを使う

というわけで関数にまとめた。

import flash.external.ExternalInterface;
 
private function openNewWin(url:String):void {
        var testFunc:String = "function(){ return !/KHTML/.test(navigator.userAgent) }";
        var openInJS:Boolean = ExternalInterface.available && ExternalInterface.call(testFunc);
        if(openInJS) {
                ExternalInterface.call("window.open", url, "_blank");
        } else {
                navigateToURL(new URLRequest(url), '_blank');
        }
}

他にwmodeが可否に影響するという情報もあるのだが、私の環境では確かめることができなかった。

環境

  • Mac: Safari4, Firefox3.6, Chrome3
  • WinXP: IE8, Chrome4

参考

動的にコンポーネントを読み込むコンポーネント

CakePHP1.3で動的にコンポーネントを読み込むためのコンポーネント DynamicComponent を作成しました。

cakephp-dynamic-component

注意: Cake本来の機能を超える機能を提供するため、Cakeコアのprivateなメソッドやプロパティにアクセスしています。Cakeのバージョンが上がると使用できなくなる可能性があります。十分ご注意ください。

このコンポーネントを使うと次のようなことが可能になります:

  • admin プレフィクスが付いているときだけ Auth コンポーネントを読み込む
  • debug > 0 のときだけ DebugKit を読み込む

読み込みはコントローラの _initialize メソッドで loadComponents メソッドを使って行います。

class AppController extends Controller
{
  var $components = array('DynamicComponent.Dynamic');
 
  function _initialize() {
    if(!empty($this->params["prefix"]) && $this->params["prefix"] == 'admin') {
      $this->Dynamic->loadComponents('Auth');
    }
    if(Configure::read('debug') > 0) {
      $this->Dynamic->loadComponents('DebugKit.Toolbar');
    }
  }
}

この方法で読み込んだコンポーネントの initialize メソッドからは、さらに別のコンポーネントを読み込むことができます。そのためコントローラから直接 Auth や DebugKit を読み込むよりは、状況に合わせた専用のコンポーネントを用意して、その中で Auth や DebugKit の読み込み・初期化を行うことをお勧めします。以下、Admin と Debug という2つのコンポーネントを作っています。

// app/controllers/components/admin.php
class AdminComponent extends Object
{
  function initialize($controller) {
    $controller->Dynamic->loadComponents('Auth');
 
    //Authコンポーネントのセットアップ
    $controller->Auth->loginAction = array(/*...*/);
  }
}
// app/controllers/components/debug.php
class DebugComponent extends Object
{
  function initialize($controller) {
    $controller->Dynamic->loadComponents('DebugKit.Toolbar');
 
    //その他debugに有用な設定など
    $controller->set(...);
  }
}

また prefix 名に応じた読み込みを行うオプションがあらかじめ用意されているので、コントローラの prefix 判定コードは省略できます。最終的に _initialize メソッドは次のようになります。

class AppController extends Controller
{
  var $components = array('DynamicComponent.Dynamic'
                          => array('prefix' => true));
 
  function _initialize() {
    if(Configure::read('debug') > 0) {
      $this->Dynamic->loadComponents('Debug');
    }
  }
}

JW Player(Flash)のプラグインをビルドする

オープンソースのFlash製メディアプレーヤー、JW Playerのプラグインをビルドする方法。

JW Playerのプラグインは通常、専用サーバにホストされたものを読み込んで利用するが、自力でビルドした自作・改造版プラグインも利用できる。読み込みはflash変数 plugins に完全URLを書けば良い。

//独自にビルドしたlogoboxプラグインを読み込む例
var flashvars = {
  "plugins": "http://example.com/plugins/logobox.swf"
, "logobox.file": "http://example.com/image/logo.png"
};

以下、ビルド手順。基本的には公式サイトの開発wikiに載っている内容そのまま。

環境: JW Player 5.1, Mac OS X 10.6, Adobe Flashは使わない

1. Flex SDKのダウンロード

AdobeのサイトからFlex SDKをダウンロードして、zipファイルを適当なディレクトリに展開する。カレントディレクトリに展開されるので、専用のディレクトリを作ってから展開した方がいい。

2. JW PlayerプラグインSDKのダウンロード

longtailのリポジトリからプラグインSDKをダウンロード、これも好きなディレクトリに展開する。

展開すると中に sdks/fl5-plugin-sdk/plugins というディレクトリがある。以後、基本的にはこのディレクトリの中でビルドを行っていく。

3. ビルドしてみる

sdks/fl5-plugin-sdk/plugins の中にはあらかじめいくつかサンプルプラグインが入っている。1つのディレクトリが1つのプラグインに対応する。各ディレクトリ中にある build.sh がビルド用のシェルスクリプトで、変数FLEXPATHの値を手順1でFlexをインストールしたディレクトリに書き換えて実行する。

FLEXPATH=/path/to/your/flex
chmod 755
./build.sh

正常に終了すれば swf ファイルができあがる。

4. 既存のプラグインを改造する

LongTailのSVNリポジトリ内には一部プラグインのソースコードも含まれているが、古いバージョン向けのものも混じっていてわかりにくい。新しめのプラグインの多くは、以下のURLで取得できるようだ。

svn co http://developer.longtailvideo.com/svn/plugins

中には as ファイルや build.sh が含まれているので、適当に書き換えてビルドを行う。

また開発WikiのTitle IndexからPluginsで検索するといろいろ有用なページが見つかる。例: PluginsLogobox