2011年4月15日金曜日

Python で行列演算 = numpy

python で行列演算をしたい.

ちょうど待ち行列MAP/G/1の系内客数分布を数値計算しようとしていて, どうせなので汎用性高い物にしようと思ったの動機.
まぁありきたりな話, 新しいライブラリを使うと大抵最初はまる.

・numpy のインストール
と思ったらすでにnumpy は入っていた. バージョンは1.2.
古いようなので, easy-install でupgrade する.

% sudo easy_install --upgrade numpy
とここで, 鬼のようにwarning と error っぽいメッセージが. 萎える.

・numpy を使う

matrixってのが行列の定義のようだ.

>>> C_matrix = [
...  [-0.2,0.2],
...  [0.0, -0.2]
...  ]
>>> C_matrix = matrix(C_matrix)
>>> D_matrix = [
...     [0,0],
...     [0.2,0]
...     ]
>>> 
>>> C_matrix = matrix(C_matrix)
>>> D_matrix = matrix(D_matrix)
>>> C_matrix 
matrix([[-0.2,  0.2],
        [ 0. , -0.2]])
>>> D_matrix
matrix([[ 0. ,  0. ],
        [ 0.2,  0. ]])

のように定義できた. array ってのもあるが, これは完全に転置っぽいので直感的でないため, やめる.
(注) matrix で[[1,2],[3,4]] は array では [[1,3],[2,4]] と列で定義するとうこと.

演算もらくらくで便利そうだ.

>>> E_VEC = matrix([[1],]*2)
>>> E_VEC
matrix([[1],
        [1]])

>>> C_matrix + D_matrix
matrix([[-0.2,  0.2],
        [ 0.2, -0.2]])
>>> (C_matrix + D_matrix) * E_VEC
matrix([[ 0.],
        [ 0.]])
>>> dot((C_matrix + D_matrix), E_VEC)
matrix([[ 0.],
        [ 0.]])

* は各成分の掛け算になるらしい. dot()で行列のかけざん.


で, solve ってのが連立方程式の解のよう.
とりあえず, 行ベクトルPI * (C + D) = 0, PI*e = 0 を解いてCおよびDで構成される, (C+Dをジェネレータとして持つ)マルコフ連鎖の定常状態確率を解くことにする.



ここではまった.


solve は正方行列でないと扱えないらしく, おそらくフルランクでないと無理だろう.
とりあえず, C+Dは明らかにフルランクではなく, PI*e = 0と組み合わせることでようやく解ける.
どうしようかと思ったけどとりあえず暫定的に, C+Dの一列を抜いてeへ替える. そして右辺は[0,...,0,1]とおく.

以下のようになる.

from numpy.linalg import solve

def calculate_pi():
    sumC_D = C_matrix + D_matrix 
    pi_solver = []
    for column in sumC_D.tolist():
        column.append(1)
        pi_solver.append(column[1:])

    zeros_plus1 = [0] * (M_SIZE -1) + [1]    
    pi_solver = mat(pi_solver)
    zeros = mat(zeros_plus1)

あまりに煩雑すぎるが, 特にメソッドもなさそうなので暫定的に...
pi_solverは最左行を省く. (まぁこれがのちのち問題だと思う)
zeros はさっきかいた[0,...,0, 1]の行ベクトル.

で, 早速solve.

>>> pipi = solve(t,zeros)
Traceback (most recent call last):
  File "", line 1, in 
  File "/Library/Python/2.6/site-packages/numpy-1.5.1-py2.6-macosx-10.6-universal.egg/numpy/linalg/linalg.py", line 316, in solve
    raise LinAlgError, 'Incompatible dimensions'
numpy.linalg.linalg.LinAlgError: Incompatible dimensions

はーなんでやーと思って, 色々やってみると, 同じことを matrix のかわりに arrayなら通る.
で, もしかたしらとちょっと不安だったが, どうやら

行* 行列 = 行

はだめで

行列 * 列 = 列

しかやってくれないぽい.

ふざけんなよーと思って, またもや暫定的に

def calculate_pi():
    sumC_D = C_matrix + D_matrix 
    pi_solver = []
    for column in sumC_D.tolist():
        column.append(1)
        pi_solver.append(column[1:])
    zeros_plus1 = [0] * (M_SIZE -1) + [1]
        
    pi_solver = mat(pi_solver)
    zeros_plus1 = mat(zeros_plus1)
    pi_vec = solve(pi_solver.T,zeros_plus1.T)

    return  pi_vec.T
とした. Tで転置らしい.


これは先が思いやられるな...

2011年4月13日水曜日

最近読んだ本 2011/1 ~ 2011/3

なかなか最近 Hadoop も触ってないな...

最近読んだ本

1,  Webを支える技術
2,  プログラムはなぜ動くのか
3,  TCP/IPソケットプログラミング Java編
4,  TCP/IPアナライザ作成とパケット解析
5, Web開発者のための大規模サービス技術入門
6, 基礎からのMySQL


[感想]
>> 1
RESTって何?ってところだったので, 歴史からその界隈の用語等を俯瞰できてよかった.

>> 2
情報学科出身ながらこのへんの話を全く勉強できなかったので, これはおもしろくためになった. とは言え, Cのfizzbuzは解けることが前提だろうか. レジスタ, アセンブラって言葉さえ意味を知らない人におすすめ (笑)

>> 3
ソケットって何? というところから読み始めた. Javaは初心者. 要はソケットTCPの実装ね, というとこで落ち着いた. さすがに古いということで, 今のJavaでSocket APIを叩くならネットから情報集めてやればよいか, というところ.

>> 4
wireshark, tshark, tcpdump  などという便利なpcap解析ソフトがある. これらの仕組みがわかる?!というかpcapってどうなってんの?みたいなノリで読んだ. 結局は (というかそういうもんだが) Cのpcapライブラリの使い方が分かって落ち着いた. 丁寧だが, Cの構造体, ポインタ, 配列, アドレスなどそのへんの用語が一瞬で結びつかないとピンとこないかも.
あんまりC使わない気がするので参考にならないやも...

>> 5
これは面白かった. 実際の大規模サービスをやってるはてなでのインターン内容ってことで, そういった企業がどんな思い (?) でここまできたかがわかる. また, サービスを実践するためにどういった知識を必要としたか, など. これまで一切興味がなかった"検索", "形態素解析"などの言葉を覚えたのと, OS, DBってものがなんなのか分かった. なかでもDBサーバはほぼオンメモリで考えるところはへーというかんじだった.


>> 6
DBって何? って話から, 一応構文くらい知っておこうと思って読んだ. 「joinが重いんだ...」とか「**GBのファイルから "select * from ..."で結果こない」とかの意味が分かった.  とそれだけかよってかんじですが... 丁寧で分かりやすかったですが, Mac, Linux向けの情報がなかったのでインストールらへんのページ数がもったいなかったかなぁと. PHPも読み書きできるようにしておこう.

2011年1月10日月曜日

Hadoop fs shell コマンド

年があけました. 今年もよろしくお願いします.

UNIXというものに触れ始めてからようやく4ヶ月程度たちました.
なぜこんなことになったかというと結局ちまたで話題のHadoopのせいです.

tipsなどが日本語でまとまってあまり見当たらないのでやっていることはまとめておきます.

まずはhadoop ファイルシステム(fs)のシェルコマンドをまとめ.

Hadoop fs -*

ファイル表示 -ls, -lsr
$ hadoop fs -ls
Found 1 items
drwxr-xr-x   - hadoop supergroup          0 2010-11-05 11:28 /user/hadoop/tera_1000
$ hadoop fs -ls /user/kimura/
Found 5 items
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 15:31 /user/output
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 16:27 /user/output1
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 17:29 /user/output2
drwxr-xr-x   - hadoop supergroup          0 2010-12-07 09:38 /user/output3
drwxr-xr-x   - hadoop supergroup          0 2010-12-07 09:41 /user/output4
$ hadoop fs -lsr /user/output1/
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 16:27 /user/output1/_logs
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 16:27 /user/output1/_logs/history
-rw-r--r--   2 hadoop supergroup      17010 2010-12-06 16:27 /user/output1/_logs/history/c1-m01_1291256668975_job_xxxxx_conf.xml
-rw-r--r--   2 hadoop supergroup      27483 2010-12-06 16:27 /user/output1/_logs/history/c1-m01_1291256668975_job_xxxxx_hadoop_test
ディレクトリを指定することで見れる. -lsrは再帰的なファイル表示.
いちいちhadoop fs -ls ディレクトリ名として打たないといけない(tabも効かないorz) このシーンでは
-lsrはけっこう便利である.

ファイル操作:移動, コピー, 削除 ;mv, cp, rm...
$ hadoop fs -mv /user/output1 /user/test1
$ hadoop fs -ls /user/
Found 5 items
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 15:31 /user/output
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 17:29 /user/output2
drwxr-xr-x   - hadoop supergroup          0 2010-12-07 09:38 /user/output3
drwxr-xr-x   - hadoop supergroup          0 2010-12-07 09:41 /user/output4
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 16:27 /user/test1
$ hadoop fs -rm /user/test1.txt
Deleted hdfs://xxxx/user//test1.txt
$ hadoop fs -rmr /user/test1
Deleted hdfs://xxxx/user/test1
このへんはUNIXの普通のファイルシステムの操作と同じである. -rmrはディレクトリの削除.
質問なしでいっきにディレクトリを消されるので注意.
hadoop MapReduceのように, outputのディレクトリを勝手に作られてしまう操作では,
テストするたびにディレクトリがどんどんできていくので, テスト実行してディレクトリ丸ごと削除は便利である.

ファイル中身表示: -cat, -tail
$ hadoop fs -cat /user/test1.txt
test
$ hadoop fs -tail /public/itpro/log_finish.txt
P/1.1" 200 4780
110.0.215.26 - - [28/Jan/2010:11:59:47 +0900] "GET /article/COLUMN/20090403/327762/?ST=lin-os&P=1 HTTP/1.1" 200 24872
110.0.134.240 - - [28/Jan/2010:11:59:48 +0900] "GET /article/COLUMN/20060228/231125/ HTTP/1.0" 200 24213
110.0.188.192 - - [28/Jan/2010:11:59:53 +0900] "GET /linux/backnum/199912/article/article_corel.shtml HTTP/1.1" 200 21881
110.0.169.231 - - [28/Jan/2010:11:59:54 +0900] "GET /article/COLUMN/20060224/230573/?ST=oss HTTP/1.1" 200 82220
110.0.163.203 - - [28/Jan/2010:11:59:54 +0900] "GET /article/COLUMN/20060227/230729/?ST=oss HTTP/1.1" 200 27778
110.0.147.216 - - [28/Jan/2010:11:59:58 +0900] "GET /article/COLUMN/20060227/230691/?ST=oss HTTP/1.1" 200 25140
110.0.169.231 - - [28/Jan/2010:11:59:58 +0900] "GET /article/COLUMN/20060227/230896/?ST=oss HTTP/1.1" 200 38033
110.0.169.231 - - [28/Jan/2010:12:00:00 +0900] "GET /article/COLUMN/20060227/230875/?ST=oss HTTP/1.1" 200 41170
110.0.85.59 - - [28/Jan/2010:12:00:00 +0900] "GET /article/COLUMN/20060228/231082/ HTTP/1.1" 200 27409
-head などはないが, -tailでファイル後ろ1kB分を表示する. 軽くみたいときに便利.
ペタ, テラ級のインプットに対し, いきなりプログラムを実行するのは無駄なので,

hadoop fs -cat xxx | head -100 > sampleinput.txt 
などでサンプルインプットを作ってから実行を推奨. UNIXでパイプで結果を渡すことはできるので.
あと, 余談だがhadoop fs コマンドラインでは*(アスタリスク)が効く.

ディスク容量, ファイルサイズ表示: -du -df
$ hadoop fs -df
Filesystem  Size Used Avail Use%
/  11597229867008 4592012775424 6422221864960 39%
$ hadoop fs -du /user/
Found 6 items
44492       hdfs://xxxx/user/output
44502       hdfs://xxxx/user/output2
88556       hdfs://xxxx/user/output3
88531       hdfs://xxxx/user/output4
44493       hdfs://xxxx/user/test1
5           hdfs://xxxx/user/test1.txt

ファイル転送: -copyToLcal, -get, -copyFromLocal, -put
$ hadoop fs -copyToLocal /user/test1.txt ~/workspace/test
$ ls test
test1.txt
$ hadoop fs -get /user/test1.txt ~/workspace/test
$ ls test
test1.txt
$ hadoop fs -copyFromLocal test1.txt /user/
$ hadoop fs -ls /user/
Found 5 items
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 15:31 /user/output
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 17:29 /user/output2
drwxr-xr-x   - hadoop supergroup          0 2010-12-07 09:38 /user/output3
drwxr-xr-x   - hadoop supergroup          0 2010-12-07 09:41 /user/output4
-rw-r--r--   2 hadoop supergroup          5 2010-12-07 10:35 /user/test1.txt
$ hadoop fs -put test1.txt /user/
$ hadoop fs -ls /user/
Found 6 items
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 15:31 /user/output
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 17:29 /user/output2
drwxr-xr-x   - hadoop supergroup          0 2010-12-07 09:38 /user/output3
drwxr-xr-x   - hadoop supergroup          0 2010-12-07 09:41 /user/output4
drwxr-xr-x   - hadoop supergroup          0 2010-12-06 16:27 /user/test1
-rw-r--r--   2 hadoop supergroup          5 2010-12-07 10:06 /user/test1.txt

-copyToLocal, -getはhdfsからファイルを現在のクライアントのローカルへコピーする.
逆に-copyFromLocal, -putはローカルからhdfsへコピーする.

その他
あとchmod等色々あるが, 基本的にUNIXのコマンドはhadoop fs -*とすれば使えることが多い.
コマンド一覧は以下のとおり.
$hadoop fs                                                                      [~]
Usage: java FsShell
           [-ls ]
           [-lsr ]
           [-df []]
           [-du [-s] [-h] ]
           [-dus ]
           [-count[-q] ]
           [-mv  ]
           [-cp  ]
           [-rm [-skipTrash] ]
           [-rmr [-skipTrash] ]
           [-expunge]
           [-put  ... ]
           [-copyFromLocal  ... ]
           [-moveFromLocal  ... ]
           [-get [-ignoreCrc] [-crc]  ]
           [-getmerge   [addnl]]
           [-cat ]
           [-text ]
           [-copyToLocal [-ignoreCrc] [-crc]  ]
           [-moveToLocal [-crc]  ]
           [-mkdir ]
           [-setrep [-R] [-w]  ]
           [-touchz ]
           [-test -[ezd] ]
           [-stat [format] ]
           [-tail [-f] ]
           [-chmod [-R]  PATH...]
           [-chown [-R] [OWNER][:[GROUP]] PATH...]
           [-chgrp [-R] GROUP PATH...]
           [-help [cmd]]

Generic options supported are
-conf      specify an application configuration file
-D             use value for given property
-fs       specify a namenode
-jt     specify a job tracker
-files     specify comma separated files to be copied to the map reduce cluster
-libjars     specify comma separated jar files to include in the classpath.
-archives     specify comma separated archives to be unarchived on the compute machines.

>>apache hadoopの公式ページ
http://hadoop.apache.org/common/docs/r0.18.3/hdfs_shell.html

も参考に.

hadoopの仕組み, MapReduce, その他のモジュールについてもまた別途書いていきたいと思います.

2010年12月24日金曜日

Mac OS X snow leopard + Eclipse 3.6 Helios

ご無沙汰になりました. 色々やってたんですが, どれも公に書きにくいことが多く, こちらを更新するに至れませんでした.

しばらく年末年始時間があるので補完します.


Carbon Emacs でjava書いてコンパイルってのをやってたのですが, どうも間違いなくめんどい.
JavaならやっぱEclipse. てかそれ以外の言語もばっちり!という噂を聞いたので, 早速入れてみることに.

2010/12時点でEclipse 3.6 Heliosが最新です.

早速

http://www.eclipse.org/downloads

からEclipse IDE for Java Developersをダウンロード.
解凍して/Applicationsへeclipseフォルダをぶっ込む.

まぁこれで英語版は使えますが, 日本語化するとかわいいかんじになってどうもよさげだったのでチャレンジ.
まずは,

http://mergedoc.sourceforge.jp/index.html#/pleiades.html

から
Eclipse 3.6.1 Helios SR1 Windows 32bit ベース / Pleiades All in One 3.6.1.20101025
のJREなしパッケージをダウンロード.

解凍するとpleiades-all-in-one-java_*/eclipseの中にdropinsというフォルダがあります.
これを/Applications/eclipse/内のdropinsにそのまま全部上書きしてしまいます.

続いて,
/Applications/eclipse/Eclipse.app/Contents/MacOS/eclipse.ini
を開いて

-javaagent:dropi....で始まる, Pleiades内のeclipse.iniファイル内最終行を追加.
そして,
-Xms128m

へ変更しておく.

以上でEclipseを立ち上げると無事Pleiadesが立ち上がり, 日本語のかわいいやつが出てきます.


pluginは取り急ぎHadoop MapReduce pluginを.


しかし実はまだあまり使っておらず, コンパイルすらしていません.
補完機能やハイライトがすごくイケてるので, 今後は手放せなくなりそうですが, 慣れるのはまだ先.

2010年11月21日日曜日

Mac os X snow leopard, javaの文字化け

今更ながらjavaを書き始めたが, javacで文字化けしてしまう.
エラーメッセージはSJISで表示されてしまうということをどこかで見たので,

% javac -J-Dfile.encoding=UTF8

としてUTFにする必要がある. めんどいのでこれはaliasとして

alias javac="javac -J-Dfile.encoding=UTF8"
として定義を上書きしておく.

同様にjavaも

alias java='java -Dfile.encoding=UTF-8'

とする.

が, しかし, 日本語をインプットすると文字化けしてしまう. やっぱJDK 1.5を使うべきか...そちらならUTF-8環境なので.
しばらく考えよう.

2010年11月19日金曜日

zsh プロンプト変更

なんとなくプロンプトを変更してみた.

書き方が分かったから今度から自分で変更しよう.

参考にできるのはここ.

zsh:Prompt Expansion

変えたのはこれ

autoload colors
colors
case ${UID} in
0)
    PROMPT="%B%{${fg[green]}%}%n@%m#%{${reset_color}%}%b "
    PROMPT2="%B%{${fg[green]}%}%_#%{${reset_color}%}%b "
 RPROMPT="%{${fg[yellow]}%}[%~]%{${reset_color}%}"
    SPROMPT="%B%{${fg[red]}%}%r is correct? [n,y,a,e]:%{${reset_color}%}%b "
    [ -n "${REMOTEHOST}${SSH_CONNECTION}" ] && 
        PROMPT="%{${fg[cyan]}%}$(echo ${HOST%%.*} | tr '[a-z]' '[A-Z]') ${PROMPT}"
    ;;
*)
    PROMPT="%{${fg[green]}%}%n@%m %%%{${reset_color}%} "
    PROMPT2="%{${fg[green]}%}%_%%%{${reset_color}%} "
 RPROMPT="%{${fg[yellow]}%}[%~]%{${reset_color}%}"
    SPROMPT="%{${fg[red]}%}%r is correct? [n,y,a,e]:%{${reset_color}%} "
    [ -n "${REMOTEHOST}${SSH_CONNECTION}" ] && 
        PROMPT="%{${fg[cyan]}%}$(echo ${HOST%%.*} | tr '[a-z]' '[A-Z]') ${PROMPT}"
    ;;
esac

結局RPROMPTで右っかわにカレントディレクトリ (%~)を表示させ, 左側にはユーザ名@マシン名 (%n@%m) としました.
時刻とか出してる人もいたけどあんまり必要な情報ではないし... とは言えユーザ名もマシン名も自宅PCであれば意味ないか...

今更聞けないUNIXコマンド (3) 公開鍵認証方式+ssh ログイン

職場、学校等のサーバが公開鍵認証方式を採用している場合は多いです。
その設定を昨日やったので、一応書いておきます。windowsではputtyなんかでやってましたが、macではTerminalから全部できて便利。

まずは

% ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/tatsuaki/.ssh/id_rsa): 
Created directory '/Users/tatsuaki/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 

てなかんじでssh-keygenにより公開鍵, 秘密鍵のペアを生成します.
公開鍵は他人に見られてもオッケーですが、秘密鍵は秘密なのでこれは絶対秘密です.
-t オプションは鍵の種類を設定します. dsaとかありますがデフォルトではrsa2である-t rsaが決まっていて,
これが推奨らしいのでこれでやりましょう.

コマンドを入れるとkeyを作る場所を聞かれるのでいれます. デフォルトで~/.ssh/に入ります.

次にパスフレーズを聞かれるので, パスワードを2回いれます. (これでサーバへ認証します)

% cd .ssh
id_rsa  id_rsa.pub
と2つファイルがあり, id_rsa, id_rsa.pubがありますが, 後者が公開鍵です.
これをサーバへ転送します.

とは言え自分はつながっていないので誰かに頼みましょう. 私の場合は違うマシンで入れたのでそっちへ
メールで送り, そこから設定しました.

ここからはサーバ側の設定です.

サーバへファイルid_rsa.pubを送りましょう. sftpやらscpやら単純にftpやらありますが,
scpでやるならば

$ scp [オプション][転送したいファイル名][転送先のパス]
とします.

たとえば
$ scp test.txt USER1@remotehost.co.jp:.ssh
で手元にあるtest.txtをUSER1としてログインするremotehost.co.jpの~/.ssh/へ送ります.
パスワードを聞かれますので入力すればok. ちなみに, scpは-rオプションでディレクトリを転送します.

サーバ管理者がどうしているか分かりませんが, サーバのユーザホームディレクトリに.sshがあるはずなので,
(なければ作る)

$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

でauthorized_keysへ内容を書き込みます. これにて終了.
ちなみに
$ chmod 600 ~/.ssh/authorized_keys
でパーミッションを変更して他から表示できないようにしといた方が安全です.


あとはログインするときは

$ ssh USER1@remotehost.co.jp 

あるいは

$ ssh -l USER1 remotehost.co.jp
で入れます.

あと, 普通にやっていれば公開鍵がユーザの~/.ssh/known_hostsに追加されるはずですが, エラーが出たり
古かったりすると問題です. 書式は以下の通り.

ホスト名, IP  キー種別  ホスト公開鍵
    #  コメント
   例:
    remotehost.co.jp, 192.168.1.2 ssh-rsa AAAAB3NzaC1...nXIDE=.......
改行すれば何個も指定できます.