Googleリーダーからフィードのログを所得する

http://www.google.com/reader/atom/feed/の後にフィードのURLをつけるとGoogleからフィードのログが所得できる。

http://www.google.com/reader/atom/feed/http://d.hatena.ne.jp/blankblank/rss2

デフォルトでは新着20件が返ってくるが、パラメータを指定する事で所得件数を変えられる。

パラメータ 名前 意味
n num 所得件数
c continuation 開始位置

nは所得件数、cは開始位置を表す文字列を指定する。文字列は一つ前のatomの中に記述されており、例えばまず

http://www.google.com/reader/atom/feed/http://d.hatena.ne.jp/blankblank/rss2?n=10

で新着10件のxmlを所得すると、タグの中に文字列が入っているので

http://www.google.com/reader/atom/feed/http://d.hatena.ne.jp/blankblank/rss2?n=10&c=文字列

とすると11件目から20件目までが所得できる。



参考

Sequencerで再生しながらMIDIMessageを追加するときの注意

以下、import javax.sound.midi.*;


結論:Sequence.createTrackで所得したTrackオブジェクトにはデフォルトで終端記号が一つ含まれている。
これは、Trackに新しいメッセージを追加されたときに適宜伸びるので終了前に更新してしまえば止まらないが、一旦終端記号が読み出されたらSequencer全体として演奏が続いていてもそのTrackは無反応になる。


ちょっとした実験。

import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.SysexMessage;
import javax.sound.midi.Track;


public class Hoge {

  public static void main(String[] args) {
    try {
      int TPB = 480;

      Sequencer seqr = MidiSystem.getSequencer();
      Sequence seq = new Sequence(Sequence.PPQ, TPB);
      seqr.setSequence(seq);

      // とりあえず2小節目まで全体は終了しない
      seq.createTrack().add(new MidiEvent(new SysexMessage(), TPB*8));

      // オンとオフ
      ShortMessage on = new ShortMessage();
      on.setMessage(ShortMessage.NOTE_ON, 0, 60, 127);
      ShortMessage off = new ShortMessage();
      off.setMessage(ShortMessage.NOTE_OFF, 0, 60, 0);

      // 1小節目の終わりにNoteOffを持ってくる
      Track track = seq.createTrack();
      track.add(new MidiEvent(on, 0));
      track.add(new MidiEvent(off, TPB*4));

      seqr.open();
      seqr.start();

      // 1秒休んで4拍目にon追加
      Thread.sleep(1000);
      track.add(new MidiEvent(on, TPB*3));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}

1小節目の始めと終わりにonとoffを配置して演奏開始した後、1秒後(だいたい3拍目)4拍目にonを追加する。この場合2小節目の先頭にoffメッセージがあるため、後から追加した音も鳴る。ここで、

      // 2拍目にNoteOffを持ってくる
      Track track = seq.createTrack();
      track.add(new MidiEvent(on, 0));
      track.add(new MidiEvent(off, TPB));

の様に、offを2拍目に配置する。すると、演奏開始時点での終端記号も2拍目になり、sleepが復帰した時点でtrackは終了しているので追加した音は読み込まれない。


終了前にダミーメッセージを入れるか、Track生成時点で終端記号を捕まえといてそれをいじると簡単に対処できる。

Wekaの簡単な使い方

オープンソースのデータマイングライブラリWekaを使って予測というか分類というかまあClassifierを作ろうという話。


準備

  1. Wekaを入れる
  2. 学習データを用意する

実装

  1. 分類機を作る
  2. 学習データを作る
  3. (必要なら)評価機を作って性能を確かめる
  4. 分類したい事例を作る
  5. 分類する


学習データは付属のサンプルを使う

@relation weather

@attribute outlook {sunny, overcast, rainy}
@attribute temperature real
@attribute humidity real
@attribute windy {TRUE, FALSE}
@attribute play {yes, no}

@data
sunny,85,85,FALSE,no
sunny,80,90,TRUE,no
overcast,83,86,FALSE,yes
...

天気のデータを表し、それぞれ景色、気温、湿度、風、遊ぶかどうかという属性を持ち、@data以降に学習用のデータを並べていく。


実装。まずは学習データと分類機を生成する。

      DataSource source = new DataSource("weather.arff");
      Instances instances = source.getDataSet();
      instances.setClassIndex(4);
      Classifier classifier = new SMO();
      classifier.buildClassifier(instances);

setClassIndexは分類したい属性の番号。この場合遊ぶか遊ばないかを決めるので4を指定する。Classifierは分類機のインターフェースで、色んな実装があるのでパラメータ等も含め適宜調整する。buildClassifierを呼び出して分類機を構築する。学習に時間がかかるモデルはここで時間を食うので注意。


次に評価。

      Evaluation eval = new Evaluation(instances);
      eval.evaluateModel(classifier, instances);
      System.out.println(eval.toSummaryString());

Evalutionオブジェクトを生成してモデルと学習データを入れる。toSummaryStringでモデルに沿った結果が見れる。この場合

Correctly Classified Instances          12               85.7143 %
Incorrectly Classified Instances         2               14.2857 %
Kappa statistic                          0.6889
Mean absolute error                      0.1429
Root mean squared error                  0.378 
Relative absolute error                 30.7692 %
Root relative squared error             78.8263 %
Total Number of Instances               14

こんな感じ。上二つが成功した数と失敗した数なので、そこそこ分類できてる。ただ、これはデフォルトのテストでそこまで精度が良くないので、ちゃんとしたい場合は適宜いじる。


次に事例データを作る。まずは属性。

      FastVector out = new FastVector(3);
      out.addElement("sunny");
      out.addElement("overcast");
      out.addElement("rainy");
      Attribute outlook = new Attribute("outlook", out, 0);
      Attribute temperature = new Attribute("temperature", 1);
      Attribute humidity = new Attribute("humidity", 2);
      FastVector win = new FastVector(2);
      win.addElement("TRUE");
      win.addElement("FALSE");
      Attribute windy = new Attribute("windy", win, 3);

属性が離散的な値の場合はまずFastVectorを作ってそれぞれの名前を定義してから属性オブジェクトを作る。連続的な値はそのままいける。属性オブジェクトのコンストラクタの最後の引数は属性番号を表すので順に入れていく。


次いでデータ。

      Instance instance = new Instance(5);
      instance.setValue(outlook, "sunny");
      instance.setValue(temperature, 100);
      instance.setValue(humidity, 100);
      instance.setValue(windy, "TRUE");
      instance.setDataset(instances);

Instanceコンストラクタの引数は属性数。それぞれの属性とその値を入れ、データセットを指定する。ここでは超絶蒸し暑くて風がビュンビュン吹いてる日を想定する。


最後に分類結果を出力する。

      double result = classifier.classifyInstance(instance)
      System.out.println(result);

classifyInstanceは連続値にも対応できるようにdoubleで返ってくるが離散値の場合インデックスを表す。この場合0.0がyesで1.0がnoになる。ちなみに結果は

1.0

というわけで、暑い日は家でおとなしくしてましょう。

import weka.classifiers.Classifier;
import weka.classifiers.Evaluation;
import weka.classifiers.functions.SMO;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.converters.ConverterUtils.DataSource;

public class CopyOfWekaTest {

  public static void main(String[] args) {
    try {
      DataSource source = new DataSource("weather.arff");
      Instances instances = source.getDataSet();
      instances.setClassIndex(4);
      Classifier classifier = new SMO();
      classifier.buildClassifier(instances);

      Evaluation eval = new Evaluation(instances);
      eval.evaluateModel(classifier, instances);
      System.out.println(eval.toSummaryString());

      FastVector out = new FastVector(3);
      out.addElement("sunny");
      out.addElement("overcast");
      out.addElement("rainy");
      Attribute outlook = new Attribute("outlook", out, 0);
      Attribute temperature = new Attribute("temperature", 1);
      Attribute humidity = new Attribute("humidity", 2);
      FastVector win = new FastVector(2);
      win.addElement("TRUE");
      win.addElement("FALSE");
      Attribute windy = new Attribute("windy", win, 3);

      Instance instance = new Instance(5);
      instance.setValue(outlook, "sunny");
      instance.setValue(temperature, 100);
      instance.setValue(humidity, 100);
      instance.setValue(windy, "FALSE");
      instance.setDataset(instances);

      double result = classifier.classifyInstance(instance);
      System.out.println(result);
    } catch (Exception e) {
      e.printStackTrace();
    }

  }

}


参考

集合知イン・アクション

集合知イン・アクション

フリーソフトでつくる音声認識システム パターン認識・機械学習の初歩から対話システムまで

フリーソフトでつくる音声認識システム パターン認識・機械学習の初歩から対話システムまで

Rによるテキストマイニング入門

Rによるテキストマイニング入門

Rによるテキストマイニング入門

テキストマイニングの本。色んな事例を交えながら理論を解説する。

本書には「テキスト」という単語が276回出てきます.時間がある方は,一つずつ数えて下さい.そうでない方は,本書をお読み下さい.

と帯に書いてあったけど全文がデータで公開されてる訳ではない。


前半は主にRと使うライブラリについての解説。特にRにこだわってる訳じゃないし、MeCabもある程度は知っていたので読み飛ばした。後半でRの式がいっぱい出てくるけど、そこまで複雑でもなかったし、解説もわりと丁寧だったので特にRを知らなくても差し支えはなかった。


後半では実例を使った解説

  • インターネット上のクチコミ情報の分析
  • アンケートの自由記述文の分析
  • 沖縄観光のアンケートの分析
  • テキストの自動分類
  • 書き手の判断

どれも生のデータを用いてるので分かりやすかった。特にインターネットの口コミ分析で、携帯電話を例にとったときに「黒船」「衝撃」「デザイン」「ビジネス」とかの名詞と「売れる」「使える」+「ない」が一緒に出てきたのが面白かった。


というわけで、MeCabバインドのダウンロード数で圧倒的不人気を誇るPythonでここまでを抽出する。とそのまえにPythonカッコイイよなあ。Python超クールだなあ。Python可愛いなあ。Python面白いなあ。大事な事なのでもう2、3度言っとくか。PythonカッコイイPythonカッコイイPythonカッコイイ。

# coding: utf-8

import MeCab

def func():
  fp = open("_blog.txt")
  text = fp.read()
  fp.close()
  m = MeCab.Tagger("")
  n = m.parseToNode(text)
  words = {}
  while n != None:
    term = n.feature.decode("utf-8").split(",")
    if term[0] == u"名詞" and term[1] != u"非自立" and term[1] != u"数":
      word = n.surface.decode("utf-8")
      words.setdefault(word, 0)
      words[word] += 1
    n = n.next
  for k, v in sorted(words.items(), key=lambda x:x[1], reverse=True)[:10]:
    print "%d : %s"%(v, k)

func()

8 : Python
5 : -
4 : 分析
4 : 解説
4 : R
3 : テキスト
2 : アンケート
2 : データ
2 : インターネット
2 : 後半

データは嘘をつかない。

集合知インアクション

集合知イン・アクション

集合知イン・アクション

ネット上に散らばっているユーザーの情報をどのように活用するかをまとめた本。帯には「ウェブ業界に関わるJavaエンジニアならこの本を必ず手に入れるべきだ」って書いてあるけど、機械学習とか集合知に興味がある人でも全然楽しめると思う。この本が出た時点で携帯に電話してこないなんてAmazonのレコメンドもまだまだだなと思うくらい面白かった。


本書ではネット上のデータを集めて解析して利用する様々な手法について解説されている。概要的な内容は最初の方の章だけで、それ以降はテーマごとに理論、例題、設計、実装がバランス良く出てくる。特に設計については実際のUMLも出しての解説なので、後のコードがすごく読みやすい。個々の内容はそこまで深く突っ込んだところまでやらず、気軽に読めるのも良い。


実際のプログラムはWEKAやLucene等の既存のライブラリを拡張して実装されている物が多かった。2部の後半では各章につきWEKAとJDMでの例が載っているほど。ライブラリの有る無しに関わらずコードは全体的にやや固め。読み手の拡張を期待してなのかJavaっ娘のプライドなのかよく分からないけど、Javaフレームワークを開発してる身(!)としてなんとなく共感できるところがあった。擬似言語や簡単なコードだけで済まさず、一通りはちゃんと動く物を例として挙げている本は、副産物的にライブラリの存在や簡単な使い方を知れるところが良い。


集合知プログラミングを読んだ事がある人は訳者あとがきを見るとどういった内容かイメージしやすいと思う。

2007年から2008年にかけて、O'ReillyからToby Segaranによる『集合知プログラミング』が発行されたことで状況が変わった。この分野の先駆的な著作として、秀逸な本であると思う。
 本書は、Toby本と比べて、よりアプリケーション実装向けの本であるといえる。言語はJavaで、RDBへのデータ保存のためのER図や、ドメインモデルのクラス図による表記が多くあらわれる。そして、集合知を実用的に実装する際に考慮が必要となる、システム全体のアーキテクチャにまで触れられている。集合知実装の実践を続けてきたAlagが、はまりやすい落とし穴をあらかじめふさいでおいてくれる。


最後のフレーズも印象的

この世界に飛び込む環境は整っている。誰もがいますぐに、手を動かし始めることができる。しかし、データは単に分析するだけでは役に立たない。大事なのは、データを提供してくれたユーザーに、社会に、どんな付加価値をつけて返すのかを考え続けることなのだと思う。

”考え続けること”あたりにシビれた。

わかりやすいパターン認識

わかりやすいパターン認識

わかりやすいパターン認識

前読んだ本(以下、音声本)よりやや固め深めなイメージ。この本は各方面から入門書としての評価が高く、パタレコの1歩目としてよく勧められるらしいけど、個人的には0.5歩目に音声本があるといいと思う。


音声本と被ってる部分が多い、というか最初の方は進め方から例の出し方まで殆ど一緒だった。簡単に比較するとこっちは例示が少なく、数式が多い。理論の情報量という点でもこっちの方が上で、特に後半に関しては音声本に載っていない内容が殆ど。


あとがきのフレーズが印象的。

また、本書はわかりやすさを優先させ、パターン認識を体系的に整理することをあえてしなかった。体系立てて述べるうえでは最初に説明すべきものでも、後回しにしたほうが初心者が理解しやすいと判断したものはそのようにした。

本そのものに関する説明、ある種思い入れのようなものが伝わってくる本は当たりが多い(という俺俺クラシフィア)。他にも端々、特にコラム内では著者の意見が垣間見えることが多く、それもクリティカルな内容が多い。


専門書だからこそ、見え隠れする人間味につい魅かれてしまう。

フリーソフトでつくる音声認識システム

フリーソフトでつくる音声認識システム パターン認識・機械学習の初歩から対話システムまで

フリーソフトでつくる音声認識システム パターン認識・機械学習の初歩から対話システムまで

サブタイトルにもあるように、パターン認識機械学習の初歩から実践までを一通り学べる本。ややこしい説明も殆ど出てこず、久しぶりに身の丈にあった本を読めた。


読みやすいと感じたのはおそらく各章、節が短くまとまっていたからだと思う。こういうとアレだけど、1ページまるまる文章で図、式、見出し、コラムが無いページって開いたときちょっとガッカリする。その点、この本は殆どのページにそれらがあるので読んでいて疲れない。


理論を説明した後にすぐ例題が出てくるのも良い。しかも先に説明した理論それぞれに対して最もハローワールドらしい簡単な問題を添えてくれているのでそのために何度も読み直すという事がほとんど無かった。仮にそれが簡単すぎて実際の問題に対して有用でなかったとしても、入り口を理解するという点では、少なくとも僕はちょうどいいように感じた。


実践編となる後半では、実際に問題を設定してツールを使ってそれを実現する。ツールを使うといっても単純に動かし方を羅列するだけでなく、設定した問題に沿って必要な理論も適宜添えられているので、表面を追うだけの状態になりにくい。前半でも要所要所ツールを動かしましょうな話が出てくるので、ネタ帳として見ても(特にwekaは実際に使っているので)非常に助かった。


見栄を張って背伸びした資料に噛み付くというのを見直せたという点も含め、得られた物は多かった。