PRML勉強会で発表してきた@VOYAGE GROUP

今日の発表で使った資料をupします。


今日は主にラプラス近似の話でした。
先日、研究室で雑談してた時に、「ラプラス近似って論文で見たことないしどうでもいい手法なのでは」的な話にって、それでもNLPみたいなそもそも連続量の分布を扱わない分野しか見てないのでラプラス近似は目に入らないだけで、ひょっとすると大事なのかもみたいな話をしていました。
今日の勉強会では、画像とか他の分野で機械学習やってる人の間でも、ラプラス近似はメジャーな手法としては共有されてない印象でした。結局あまり大事ではない?
4章、5章を読んだ感触としては、とりあえず①目的関数を設定②最適化、の流れを、各手法について正確に理解することが大事な印象です。
近似や最適化について、断片的な知識でわかった気になっていて体系的・包括的な理解が足りてないと感じたので精進したいところです。

LDAを利用した、twitter上のユーザ類似度判定システム

大学院で自然言語処理の研究をしつつ、ブログタイトルのようなものを趣味的にチマチマと作っていまいた。個人的になかなか面白い解析結果が出たと思ったのでご紹介します。

目標:
1.twitter上で、ある入力ユーザ(自分でなくてもよい)と興味の対象が似ているユーザを発見する
2.興味あるトピックには、どういう単語が含まれているか発見する

手法:
1.1ユーザのツイート全体を1つの文書としてモデリングし、LDAで解析
2.全てのユーザについて、トピック-ユーザの特徴ベクトルの距離を使って類似度を計算

特徴:
1.巷にあるソーシャルネットワーク系の解析でありがちな、ユーザ同士のリンク情報を全く使っていない
2.トピックの次元は語彙の次元と比べてかなり小さい(1/(10^3)くらい)ので、単に単語の頻度を数えるのと比べて柔軟

解析結果ですが、とりあえずpythonの処理系が動作する環境で確認できるようにしました。
また、msgpack(http://msgpack.org)が必要です。
ubuntu11.10で動作確認していますが、UNIX系のOSなら多分大丈夫です。
興味がある方はどうぞ。とりあえず約4000人分のデータがあります。@risuoku周辺の人は大体入ってるはず。

続きを読む

FizzBuzzもどき

TLでFizzBuzzネタがまた盛り上がってた気がしたので。
普通に書いてもつまらないからFizz→ai Buzz→aiii に変換したバージョン。
1分くらいで書いた。
a.py

import sys
for i in xrange(1,100):
	tmp=str()
	if i%3==0:tmp+='ai'
	if i%5==0:tmp+='aiii'
	if len(tmp)==0:tmp=str(i)
	sys.stdout.write(tmp+' ')
sys.stdout.write('\n')

あいいいいいいにしてもつまらないと思った人、自分もそう思った。
※研究室+αのローカルネタです

2次元格子上の全探索を書いた

昨日、研究室でAtcoder#006のD問題が話題になった。ある点から8方向の繋がりを手がかりに、繋がっている部分の個数を数えていく問題と考える。
ところで、この手の2次元格子上の繋がりを全探索する問題は実装がちょっと面倒なわりによくある気がする。今回は、汎用的に使えそうなツールがあれば便利だと思って作ったという話。
個人的なメモなので見やすくはないかもしれない。

<仕様>
・型
BFS_matrix:幅優先探索
DFS_matrix:深さ優先探索

・入力データ
2次元配列としてvector >を使う。

・出力データ
それぞれの「クラスタ」が含む要素数と、初めに触れた座標をvectorに保存。

・メソッド
void set_datas(vector >, data_type, data_type, bool)
引数は、前から順に①入力データ②走査済を表すシンボル③未走査を表すシンボル④8方向を見るかどうか。
コンストラクタと同じ形式。

void run()
そのまんま。

vector out()
出力がvectorで返ってくる

<注意点>
・入力データは、実際のデータの周りに、1マス分の走査済「ダミー」を仕掛けておく必要がある。例えば、実際のデータが5*7のサイズだとすると、入力データは7*9になる。

<使用例>

続きを読む

いい加減、stringstreamを覚えようという話

個人的に、プロコン用のコーディングではC言語系の入力が好きで、stream系は全く使っていなかったのだけど、ちょっと不便を感じることが多くなってきたので改心しようと思う。

例えば、次のような問題。具体的にはこういうの(http://www.deqnotes.net/acmicpc/p0017/ja)がある。

n個のデータセットがある。各データセットは改行で区切られている。各データセットは、半角スペースで区切られた整数を1行に並べた構成。並べられた整数の個数はデータセットごとに異なるかもしれない。このようなデータを読み込むにはどうすればよいか。

もしも各データセットごとに整数の個数が固定されていたら話は単純で、A[n_dataset][n_nums]みたいな配列を準備して各要素に対する入力をn_nums回やればいい。

でも、今回みたいに入力の個数が固定されない場合もある。こういう時、今までは凄く面倒なことをしていた。バッファを作って、スペースが出るまで1つづつ順番に読み込んでいってスペースがきたらatoi(buf)して・・とか、毎回やってると発狂しそうになるので簡単な方法を覚えることにした。

そこで、stringstream。
このエントリ(http://d.hatena.ne.jp/g940425/20110212/1297531253)を参考にした。
以下のような感じになる。

続きを読む

PRML勉強会で発表してきた@DeNA(渋谷ヒカリエ)

今日の発表で使った資料をupします。


間違いのご指摘・ご意見等ありましたら、ブログのコメント欄やtwitter等で気軽に話しかけてください。
実は、今日は動くモノを準備していたのですが、変な空気の読み方をしてしまい不発となってしまいました。なので、ここで簡単にご紹介します。
発表後半の直線フィッティングの話です。
データ生成の際に乗せるノイズの強さや、データの数を変えることで、パラメータの推定値がどう振る舞うかを解析するプログラムです(R実装)
具体的には次のようになります。黒で引いた直線のパラメータには、wのMAP解を使っています。

N=20, Beta=25(テキストの例)

N=20, Beta=5(ノイズ大)

N=100, Beta=5(ノイズ大、データ数多)

N=1000, Beta=5(ノイズ大、データかなり多)

この結果から、以下のことが読み取れると思います。また、直観的にも理解しやすいと思います。
1.ノイズが大きいほど予測しづらい
2.データが増えるほど予測しやすい。

最後に、ヒカリエ21Fから見た夕日がきれいでした。

C言語データ入力メモ2

またもやscanf系の入力でハマったのでメモ。

問題:
ステップ1.整数の入力を1つ、scanfで受け取る
ステップ2.ステップ1で受け取った整数が0ならば終了、0以外ならば文字列をgetsで受け取ってputsで出力し、ステップ1に戻る

例えば、次のコードは正しく動作するだろうか?

#include <cstdio>
#include <algorithm>
const int MAX_BUFSIZE(128);

int main(){
    int n;
    while(true) {
        scanf("%d", &n);
        if(n == 0) break;
        else {
            char buf[MAX_BUFSIZE]; std::fill(buf, buf + MAX_BUFSIZE, 0); 
            gets(buf);
            puts(buf);
        }   
    }   
}

答えはNoである。
getsで新しい文字列を標準入力から受け取るつもりが、scanfで受け取ってない分のストリームが残っていて、こっちを先に受け取ってしまう。

次に、scanfの部分で%dの直後に空白を入れたコードを考える。

#include <cstdio>
#include <algorithm>
const int MAX_BUFSIZE(128);

int main(){
    int n;
    while(true) {
        scanf("%d ", &n); //%dの次に空白
        if(n == 0) break;
        else {
            char buf[MAX_BUFSIZE]; std::fill(buf, buf + MAX_BUFSIZE, 0); 
            gets(buf);
            puts(buf);
        }   
    }   
}

これによって、整数を入力した後の改行が区切れとみなされて、正常にgetsが受け付けられるようになる。ただ、この変更後の問題は、整数として0を入力した時で、何故か思い通りに動かない。この理由はいまだにわからないので詳しい方教えてください。。。

結局、思い通りに動くとわかったのは次のコード

#include <cstdio>
#include <algorithm>
const int MAX_BUFSIZE(128);

int main(){
    int n;
    while(true) {
        scanf("%d", &n);
        getchar(); //getcharで改行を受け取る
        if(n == 0) break;
        else {
            char buf[MAX_BUFSIZE]; std::fill(buf, buf + MAX_BUFSIZE, 0); 
            gets(buf);
            puts(buf);
        }   
    }   
}

ちなみにこの入力フォーマットは競技プログラミングでよく出くる。なので、これが出来ないとスタート地点にも立ててないということになる。ぐぬぬ。

その他、C++は標準でsplitが使えないのでstringstrem+STLコンテナで疑似splitやる必要があったり何かと大変である。

C言語入門 (ASCII SOFTWARE SCIENCE Language)

C言語入門 (ASCII SOFTWARE SCIENCE Language)