RubyからRDFを使うライブラリをいくつか紹介してきましたが,最近急ピッチで開発されているRDF.rbが本命になりそうです.まだSPARQLは使えず,基本的なことしかできませんが,やっとどれを使ったらいいのかよくわからないという状況が変わりそうです.

ちゃんとした紹介を日本語で書こうと思っていたら,作者達が良くできたチュートリアルを書いてくれたので,それを翻訳することにしました.とりあえずここに置いておくことにします.

RubyによるRDFデータの解析と永続化 (Parsing and Serializing RDF Data with Ruby)

original text 2010/04/21 by Arto

このチュートリアルでは、Ruby用のライブラリRDF.rbを使ったRDFデータの解析と永続化の方法を学びます。RDFを基礎としたLinked Dataの永続化形式には色々ありますが、RDF.rbでは多くの形式が使えます。

このチュートリアルに沿ってコード例を試すには、RubyとRubygemsだけが必要です。最近のRuby 1.8.xや1.9.x、またはJRuby1.4.0以上なら動きます。

サポートしているRDF形式

現在RDF.rbで解析や永続化できるRDF形式は以下の通りです。


形式        | 実装                  | RubyGems gem
------------|-----------------------|-------------
N-Triples   | RDF::NTriples         | rdf
Turtle      | RDF::Raptor::Turtle   | rdf-raptor
RDF/XML     | RDF::Raptor::RDFXML   | rdf-raptor
RDF/JSON    | RDF::JSON             | rdf-json
TriX        | RDF::TriX             | rdf-trix

RDF.rb自体は比較的軽量なgemで、N-Triples形式のみビルトインでサポートしています。その他の形式についてはRDF::Raptor, RDF::JSON, RDF::TriXのようなプラグインとして、個別のgemにパッケージ化されています。このアプローチによって、コアライブラリを他から切り離して、RDF.rb自体がいかなるXMLやJSONパーサへの依存しないようにしています。

これら全ての形式サポートを一度に簡単にインストールできます。

$ sudo gem install rdf rdf-raptor rdf-json rdf-trix
Successfully installed rdf-0.1.9
Successfully installed rdf-raptor-0.2.1
Successfully installed rdf-json-0.1.0
Successfully installed rdf-trix-0.0.3
4 gems installed

注: RDF::Raptor gemはRaptor RDF Parser ライブラリとそのコマンドラインツールがシステムにインストールされている必要があります。MacやLinux, BSDディストリビューションのための簡単なRaptorのインストール方法は以下の通りです。

$ sudo port install raptor             # Mac OS X with MacPorts
$ sudo fink install raptor-bin         # Mac OS X with Fink
$ sudo aptitude install raptor-utils   # Ubuntu / Debian
$ sudo yum install raptor              # Fedora / CentOS / RHEL
$ sudo zypper install raptor           # openSUSE
$ sudo emerge raptor                   # Gentoo Linux
$ sudo pkg_add -r raptor               # FreeBSD
$ sudo pkg_add raptor                  # OpenBSD / NetBSD

Raptorのインストールや使用方法についての更なる情報は、我々の以前のチュートリアル RDF for Intrepid Unix Hackers: Trasmuting N-Triplesを見てください。

RDFデータの読み込み

もしあなたが急いでいて、すぐにRDFデータの正しい読み込み方を知りたいのなら、あなたが知る必要があることは本当に以下だけです。

require 'rdf'
require 'rdf/ntriples'

graph = RDF::Graph.load("http://datagraph.org/jhacker/foaf.nt")

この例では、まずはじめにRDF.rbとN-Triples形式のサポートを読み込んでいます。その後、RDF::Graphクラスの便利なメソッドを使って、RDFデータを一度に直接ウェブURLから取得して解析します。(loadメソッドはファイル名かURLを受け付けます。)

全てのRDF.rbパーサプラグインは、処理可能なMIMEタイプとファイル拡張子を宣言します。それが、上の例でRDF.rbが、与えられたURLにあるfoaf.ntファイルを読むためのN-Triplesパーサのインスタンスの作り方を知っている理由です。

同じ方法で、RDF.rbは他のいかなるRDFファイル形式を自動検知します。そのためには、以下のどれかを使って形式のサポートを読み込めば良いです。


require 'rdf/ntriples' # Support for N-Triples (.nt)
require 'rdf/raptor'   # Support for RDF/XML (.rdf) and Turtle (.ttl)
require 'rdf/json'     # Support for RDF/JSON (.json)
require 'rdf/trix'     # Support for TriX (.xml)

注: もし複数の名前付きグラフを含むRDFファイル(TriXのように名前付きグラフをサポートする永続化形式)を読む必要があるなら、おそらくRDF::Graphの代わりにRDF::Repositoryを使いたいでしょう。


repository = RDF::Repository.load("http://datagraph.org/jhacker/foaf.nt")

この2つの違いは、RDF::Repositoryインスタンス内のRDF文が、オプションとしてcontextを含められることです(すなわち4つ組(quad)になれます)。RDF::GraphインスタンスのRDF文は常に同じcontextとなります(すなわちこれらは3つ組(triple)です)。言い換えると、レポジトリは一つ以上のグラフを含み、以下のようにアクセスできます。

repository.each_graph do |graph|
  puts graph.inspect
end

RDF形式の内部処理

RDF.rbの解析や永続化APIは以下の3つの基底クラスを基にしています。

  • RDF::Formatは特定のRDF永続化形式を記述するために使われます。
  • RDF::ReaderRDFパーサ実装用の基底クラスです。
  • RDF::WriterRDF永続化実装用の基底クラスです。

もしあなたが解析や永続化をしたいファイル形式について何か知っているなら、形式指定用のクラスを以下の何れかの方法で取得できます。

require 'rdf/raptor'

RDF::Format.for(:rdfxml)       #=> RDF::Raptor::RDFXML::Format
RDF::Format.for("input.rdf")
RDF::Format.for(:file_name      => "input.rdf")
RDF::Format.for(:file_extension => "rdf")
RDF::Format.for(:content_type   => "application/rdf+xml")

一度そのような形式指定用のクラスを持てば、そこから解析/永続化実装を取得可能です。

format = RDF::Format.for("input.nt")   #=> RDF::NTriples::Format
reader = format.reader                 #=> RDF::NTriples::Reader
writer = format.writer                 #=> RDF::NTriples::Writer

また、RDF::ReaderとRDF::Writerにも、直接対応するファクトリメソッドがあります。

reader = RDF::Reader.for("input.nt")   #=> RDF::NTriples::Reader
writer = RDF::Writer.for("output.nt")  #=> RDF::NTriples::Writer

以上が、URLやファイル名をRDF::Graph.loadに渡したときに、RDF.rbが正しい解析実装を得るために内部で依存するものです。もちろん、永続化形式を自動検出して、解析や永続化用の適切な実装クラスに委譲する必要がある、他のいかなるメソッドも同様です。

RDFデータの解析

もし、より明示的にRDFデータの解析、例えばデータセットをメモリに読み込めないので文毎に処理したい、ということをする必要があるのなら、RDF::Readerを直接使う必要があります。

ファイルからRDF文を解析

RDFパーサ実装は一般的にRDF::Enumerableインタフェースのストリーミング互換なサブセットをサポートします。これは#each_statementメソッドを基にしています。以下はRDFファイルを文毎に列挙しながら読み込む方法です。

require 'rdf/raptor'

RDF::Reader.open("foaf.rdf") do |reader|
  reader.each_statement do |statement|
    puts statement.inspect
  end
end

RDF::Reader.openをRubyブロックと一緒に使うことで、入力ファイルが処理後に自動的に閉じられることが保障されます。

URLからRDF文を解析

前の通り、ファイル名を使えていた場所全てでhttp://https://のURLを使えます。

require 'rdf/json'

RDF::Reader.open("http://datagraph.org/jhacker/foaf.json") do |reader|
  reader.each_statement do |statement|
    puts statement.inspect
  end
end
文字列からRDF文を解析

時々、すでにメモリバッファ上のどこかに永続化されたRDFコンテンツを持っているときがあります。例えばデータベースから取得した場合です。そのような場合、前に示したパーサ実装を取得して、その後RDF::Reader.newを直接使います。

require 'rdf/ntriples'

input = open('http://datagraph.org/jhacker/foaf.nt').read

RDF::Reader.for(:ntriples).new(input) do |reader|
  reader.each_statement do |statement|
    puts statement.inspect
  end
end

RDF::Readerコンストラクタはダックタイピングを使用しているので、#readlineメソッドに応答するいかなる入力(例えばIOStringIOオブジェクト)を受け付けます。もし入力の引数が何も与えられないときは、入力データはデフォルトで標準入力から読み込まれます。

RDFデータの永続化

RDFデータの永続化は解析とほとんど同様です。名前付きの出力ファイルに永続化されるとき、与えられたファイル拡張子によって正しい永続化実装がファイル拡張子によって自動検出されます。

出力ファイルにRDF文を永続化する

RDF永続化実装は一般的にRDF::Mutableインタフェースのサブセットであり、追加だけ可能です。主に#insertメソッドとそのエイリアス#<<が対応します。以下がRDFファイルに文毎に出力する方法です。

require 'rdf/ntriples'
require 'rdf/raptor'

data = RDF::Graph.load("http://datagraph.org/jhacker/foaf.nt")

RDF::Writer.open("output.rdf") do |writer|
  data.each_statement do |statement|
    writer << statement
  end
end

またですが、RDF::Writer.openをRubyブロックと一緒に使うことで、処理後に出力ファイルが自動的にフラッシュされ閉じられることが保障されています。

RDF文を文字列結果に永続化

ある共通のユースケースは、文字列バッファにRDFグラフを永続化することです。例えばRailsアプリケーションからRDFデータを供給するときです。RDF::Writerには便利なbufferクラスメソッドがあり、StringIOに出力を溜め込んで最後に文字列として返してくれます。

require 'rdf/ntriples'

output = RDF::Writer.for(:ntriples).buffer do |writer|
  subject = RDF::Node.new
  writer << [subject, RDF.type, RDF::FOAF.Person]
  writer << [subject, RDF::FOAF.name, "J. Random Hacker"]
  writer << [subject, RDF::FOAF.mbox, RDF::URI("mailto:jhacker@example.org")]
  writer << [subject, RDF::FOAF.nick, "jhacker"]
end
永続化出力をカスタマイズ

もし特定の永続化実装が名前空間接頭辞宣言や基底URIのようなオプションをサポートしているなら、これらのオプションをRDF::Writer.openRDF::Writer.newにキーワード引数として与えることで指定できます。

RDF::Writer.open("output.ttl", :base_uri => "http://rdf.rubyforge.org/")
RDF::Writer.for(:rdfxml).new($stdout, :base_uri => "http://rdf.rubyforge.org/")

サポートチャンネル

皆さん、今はこれで終わりです。このチュートリル以上のAPIについての情報は、RDF.rb API文書を参照してください。何か質問があれば、#swigpublic-rdf-ruby@w3.orgメーリングリストで遠慮なく聞いて下さい。

次はRubyRDFです.特徴は以下の通りです.

  • Store: Memory, Sesami
  • Query: 独自の構文

特定のフォーマットの入出力には対応しておらず,メモリ上(またはSesami)でグラフを作り,それに対して独自のクエリを投げられるだけのようです.また,残念ながら開発が止まっており,かつRuby1.8.xでしか動きません.Ruby1.9.1では駄目でした.メリットが何もないので少し試しただけで止めました.

使い方

gemから入れます.


$ gem install rubyrdf

とりあえず試すには以下のコード(ほぼサンプルのまま)を入れれば良いです.


#!/usr/bin/ruby

require 'rubygems'
require 'rubyrdf'

RDF::Namespace.register(:dc, "http://purl.org/dc/elements/1.1/")
g = RDF::Graph::Memory.new
g.add(RDF::UriNode.new("http://paul.stadig.name/"), DC::author,  
         g.new_blank_node("test"))

q = RDF::Query.new
q.select(:x, :y).where(:x, DC::author, :y)
result = g.execute(q)
result.bindings.each do |b|
  puts "x = #{b[:x]}"
  puts "y = #{b[:y]}"
end

新しい扉 PlaceEngine ActionScript API公開“という記事で,ActionScript用のAPIソースが公開されていたので,それをベースにPlaceEngineをActionScriptから使ってみました.とりあえず,PlaceEngineのローカルDBを用いて緯度経度を取得することはできるようです.

まず,PlaceEngineをサイトからダウンロードしてインストールします.起動後に,環境設定→ローカルDB→アップデートをします.WifiをOnにした状態で”現在地を取得”を押すと,登録されている位置が取得できるはずです.取得できない場合はPlaceEngine.com Mapから追加してください.

ActionScriptからローカルDBを使うには以下のようにします.

  1. PlaceEngine連携サイト用アプリケーションキー取得ページで以下の情報を入力してアプリケーションキーを生成
    • 認証コード: 表示されているcaptureを入力
    • URL: app:/アプリケーション名.swf (helloというアプリならapp:/hello.swf)
    • サービス名: アプリケーション名
  2. PlaceEngineAPI.asをプロジェクトの適切な場所に置く.デフォルトパッケージ名はPlaceEngineAPIになっているので適宜変える.
  3. PlaceEngineAPIに以下を追加
    		public function getLocationFromLocal():void{
    			printMsg("WiFi情報取得中...");
    			//タイムスタンプとして現在時刻を取得
    			timeStamp = new Date();
    	
    			//URL文字列を作成
    			var URL:String = "http://localhost:5448/locdb?t=";
    				URL += timeStamp.milliseconds + "&appk=";
    				URL += appk;
    			trace("URL: " + URL);
    			var request:URLRequest = new URLRequest(URL);
    			var loader:URLLoader = new URLLoader();
    			
    			//イベントハンドラをセット
    			setListeners(loader, "Server");
    			
    			//実際にリクエストを発行
    			sendRequest(loader, request);
    		}
    
  4. プログラム側からはgetLocationの代わりにgetLocationFromLocalを使う

以上の手順で動くことは確認しました.苦労したのは,正しいアプリケーションキーの取得方法がなかなかわからなかったことです.

getLocation がうまく動かないためWebAPIから直接取得できないのですが,原因はcrossdomain.xmlにあるようです.どうやらcrossdomain.xmlの内容が古いらしく,以下のエラーを吐きます.サーバ側で対応してもらえるように,後で連絡する予定です.

Warning: Domain www.placeengine.com does not specify a meta-policy. Applying default meta-policy ‘master-only’. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.

Error: Ignoring policy file at http://www.placeengine.com/api/crossdomain.xml due to meta-policy ‘master-only’.

ビジュアライジング・データ

1月に読んだままの本.情報視覚化(情報可視化とも言う)について教えてくれる本だと期待して買ったのですが,実際にはProcessing入門のような本でした.Web上で取得できるデータを加工して視覚化する方法が実例で書かれています.以前取り上げた集合知プログラミングを補完する本だと思いました.

1章で,情報視覚化のプロセスについて述べられています.この7つのステップが本書の内容の全てです.後は,実際にこれらのステップをどのように取捨選択して適用していくのか,また,ステップ間でどのような相互作用があるのかという話になります.

  1. データ収集 (acquire)
  2. 解析 (parse)
  3. フィルタリング (filter)
  4. マイニング (mine)
  5. 表現 (represent)
  6. 精微化 (refine)
  7. インタラクション (interact)

Processingについては去年知ったのですが,なかなか面白いです.Javaで手軽に2D graphicsを書くための簡易言語なのですが,HTML5 CanvasとProcessing.jsを使うと,コードをそのままブラウザ上で動かすこともできるそうです .Raphaëlといい,手軽にブラウザ上で動かせるgraphicsの選択肢が増えるのは良いことだと思います.

アマゾンのサーバでエラーが起こっているかもしれません。
一度ページを再読み込みしてみてください。

プログラミング Erlang

Erlangの作者 Joe Armstrongが書いた本の翻訳本を読みました.マルチコアなプロセッサや分散環境が手軽に使える時代なので,平行指向かつ分散指向なプログラミング言語である Erlangは気になっていました.ロックによる状態共有のプログラミングは皆が正しく行うには難しいので,プログラミング言語としてサポートするのは正しいと思うのです.今すぐ使うわけではないので,簡単な逐次実行から並列処理のサンプルを試しただけですが,新しい言語を学ぶのは楽しいですね.文法部分にPrologの影響を受けた関数型言語という感じです.

束縛した変数が不変で,かつプロセス間メッセージパッシングで処理を行うモデルなので,状態の共有はほとんどありません.そのため,安全に平行処理ができるというのがウリです.サーバーを書くには向いていると思います.文字列はただの数字の配列という扱いなので,文字列処理には向いていなさそうです.Erlang Tipsを見ると正規表現ライブラリもあるようですが,試してはいません.

アマゾンのサーバでエラーが起こっているかもしれません。
一度ページを再読み込みしてみてください。

Beautiful Code

著名なプログラマー達が,自分が今まで出会った中で”美しい”と思っているコードについて述べている本.人によって”美しい”の定義が異なるので,アルゴリズム,テスト,アーキテクチャ,並列処理など,内容が多岐にわたります.

自分が考える美しいコードとは,簡潔で,短く,容易に可読なコードです.本書でも,多くの方々が同様の意見を述べていましたので,抜粋してみました.

ロブは,さまざまな選択肢の中から,非常に小さいが,重要であり,うまく定義された,拡張可能な一群の機能を選択したという点で賞賛されるべきです.

ロブの実装それ自体も,コンパクトでエレガントで,効率的で,実用性があるという点で美しいプログラムの最上の例です.(p.3 Brian Kernighan)

コードを削ることで機能を追加しなさい.(p.40 Jon Bentley)

美しいコードは,理解が容易でなければいけません.開発者の言語知識をひけらかすために書かれたようなコードは,私は大嫌いですし,あるコードが実際に何をやっているのかを理解するために25行以上コードを読み進む必要があるべきではありません. (p.277 by Adam Kolawa)

要約すると美しいコードとは,短くて,明確で,質素で,現実を考えて書かれている物だと,私は信じています.(p.282 by Adam Kolawa)

私はコードをリファクタリングして追加した行数より削除した行数の方が多いとき,いつも得意な気分になります.(p.306 by Diomidis Spinellis)

Pythonを開発していて,最初はいろいろ最適化するのがよいと思ったけれども,結局は比較的素朴な実装の方が好ましい,と気づく場合がありました.要するに物事はシンプルに保っておくことが得な場合が多いのです.(p.310 Andrew Kuchling)

並列プログラムは非決定的に実行されるため,テストは困難であり,バグはほとんど再現できません.ですから私にとっては,美しいプログラムとは,単に明らかな間違いがないという物ではなく,明らかに間違いがないと一目でわかるような単純でエレガントなプログラムのことを言います(この表現はC.A.R.ホーアによるものです).(p.405 Simon Peyton Jones)

プログラムの美しさを構成する要素の一つは「簡潔さ」です.Paul Grahamもエッセイで「簡潔さは力なり」と語っています.ですから簡潔に記述できることはプログラミング言語にとって絶対の善なのです. (p.504 by まつもとゆきひろ)

それぞれ実際に言及している分野はばらばらなのですが,それでもほとんど同じことを言っていると思います.

取り上げられていたアルゴリズムで美しいと思うのはニ分探索 (binary search) です.しかし,これだけ単純で古いアルゴリズムでも,最近まで実装にバグがあったというのには驚きます.”Extra, Extra – Read All About It: Nearly All Binary Searches and Mergesorts are Broken – Google Research Blog”にその詳細が載っています.


1:     public static int binarySearch(int[] a, int key) {
2:         int low = 0;
3:         int high = a.length - 1;
4:
5:         while (low <= high) {
6:             int mid = (low + high) / 2;
7:             int midVal = a[mid];
8:
9:             if (midVal < key)
10:                 low = mid + 1
11:             else if (midVal > key)
12:                 high = mid - 1;
13:             else
14:                 return mid; // key found
15:         }
16:         return -(low + 1);  // key not found.
17:     }

上記のコード(元ブログから引用)の6行目 int mid = (low + high) / 2;でlow+highが231-1より大きくなるとき,符号が反転してmidがマイナスになります.そのため7行目の配列アクセスで失敗します.これを回避するためにはint mid = (low + high) >>> 1とすれば良いです.>>>は右シフト演算で符号を落とします.または明示的にunsignedで実装する必要があります.

その他にも,MapReduceなど,色々載っています.通して読むよりは,興味がある章を拾い読みするのが良いかなと思います.

アマゾンのサーバでエラーが起こっているかもしれません。
一度ページを再読み込みしてみてください。

プログラミング言語Ruby

この本がPerlのラクダ本扱いになるのかはわからないですが,Rubyでプログラムを書いている人は一度目を通す価値ありだと思います.Rubyは使い始めてから結構年数が経ちますが,細部で知らないことが結構ありました.例えばcloneとdupの違い.対象がfreezeの場合,cloneはそのままコピーしますが,dupはfreezeを外します.また,cloneはオブジェクトの特異メソッドもコピーします.splat演算子というのも使ったことがないです.

Procとlambdaの扱いの違いも知りませんでした.returnやbreakなどの制御構文で違う動作をします.また,lambda はメソッド扱いなので引数の数が厳密にチェックされるそうです.Ruby1.9 にはlambdaかProcかを判別できるようにlambda?メソッドが追加されています.

Ruby1.9についてはまったく知らなかったので,かなり参考になりました.仕様としては,エンコーディングのサポートと,文字の単位がエンコーディング依存になるのが一番大きい変更のようです..lengthはバイト数ではなく文字数になります.逆にバイト単位用の仕様やメソッドも色々追加されています.その他,便利なメソッドが増えているようなので,一度標準ライブラリを確認し直した方が良さそうです.

アマゾンのサーバでエラーが起こっているかもしれません。
一度ページを再読み込みしてみてください。

Evernote APIのライブラリとサンプルはAPIのページからダウンロード可能です.サンプルはJava,Perl,PHP,Python,Rubyが用意されています.Rubyのサンプルはsample/ruby/EDAMTest.rbです.まず,EDAMTest.rbの13-16行目を,取得したAPI key,secret,開発サーバのユーザ名,パスワードで置き換えます.


consumerKey = "your-api-key-here!"
consumerSecret = "your-api-secret-here!"
username = "your-username"
password = "your-password"

次に,EDAMTest.rbの先頭にEvernote APIのライブラリのパスを追加します.


$:.unshift("../../lib/ruby/")

ライブラリにはバグがあるので以下のパッチを当てます.thriftのほうを直すべきだと思いますが,とりあえず動かすために.


--- lib/ruby/thrift/struct.rb.orig      2009-02-07 17:07:30.000000000 +0900
+++ lib/ruby/thrift/struct.rb   2009-02-08 09:40:56.000000000 +0900
@@ -97,11 +97,11 @@
         end
         iprot.read_struct_end
       end
-      validate
+#      validate
     end

     def write(oprot)
-      validate
+#      validate
       if oprot.respond_to?(:encode_binary)
         # TODO(kevinclark): Clean this so I don't have to access the transport.
         oprot.trans.write oprot.encode_binary(self)

--- lib/ruby/thrift/transport/httpclient.rb.orig        2009-02-08 09:46:12.000000000 +0900
+++ lib/ruby/thrift/transport/httpclient.rb     2009-02-08 09:46:53.000000000 +0900
@@ -19,6 +19,7 @@
     def flush
       http = Net::HTTP.new @url.host, @url.port
       http.use_ssl = @url.scheme == "https"
+      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
       headers = { 'Content-Type' => 'application/x-thrift' }
       resp, data = http.post(@url.path, @outbuf, headers)
       @inbuf = StringIO.new data

後は,残りの必要なライブラリをインストールします.Ubuntu8.10だと以下のように入力します.


$ sudo aptitude install libreadline-ruby libhttp-access2-ruby

ここまで設定すれば,ruby EDAMTest.rbと入力することでサンプルプログラムが起動すると思います.
入力した文章を新しいノートとして取り込むという単純なプログラムです.

Firefox 3 Hacks

Firefox 3 Hacksは前回のFirefox Hacksと異なり,全部日本人による書き下ろしだそうです.内容は,Firefox 3 の新機能や,新しいAdd-onについての解説となっています.Hack#26-27のJavascriptコードモジュールについての記事と,Hack#31-32のGoogle GearsとHTML5 DOM Storageについては,どうプログラムを書くかを知らなかったので勉強になりました.

本の前半はユーザ向けで,後半は開発者向けです.後半部分は,一度XULなどを使った経験があるほうが理解できるでしょう.

アマゾンのサーバでエラーが起こっているかもしれません。
一度ページを再読み込みしてみてください。

集合知プログラミング – Programming COllective Intelligence

この二日間、集合知プログラミングを輪講していました。この本、こんな名前ですが、要するにWeb上のデータを対象とした機械学習の入門書です。普通の入門書と違うのは、数式がほとんどなく、代わりにPythonのサンプルコードが大量にあることです。数式読むよりもプログラム読む方が理解しやすい自分には最適。実際、式はあってもそれを実運用のプログラムに落とし込むのは段階を踏む必要があるので、サンプルコードがたくさんあるのはありがたいです。

Pythonはほとんど触ったことがないのですが、結構わかりやすいですね。ライブラリの量はPerl未満Ruby以上のようなので、Python真面目に使ってみようかしら。インデントが意味を持つのはなかなか気持ち悪いですが。

アマゾンのサーバでエラーが起こっているかもしれません。
一度ページを再読み込みしてみてください。