How to use Mac/Unix - Yusuke Sakumoto's Homepage
目次
1 はじめに
Mac 等の UNIX において実験等でデータを処理することを目的としたシェル/Python の使い方についてまとめています.(まだ未完成)
シェル は,一般的には コマンドインタプリタ と呼ばれるものであり,ユーザからの指示をコンピュータに与える役割をもっています.
通常,ターミナルというアプリケーションを起動し,コマンドと呼ばれるものを入力することで,コンピュータに指示を与えることができます.
シェルを使うことの最大のメリットは作業の自動化です.
作業の実行画面を眺めているのは最初は楽しいですが,同じ作業を繰り返すうちに自分の存在意義を見失ってしまい非常に寂しい気持ちなる可能性もあります.
作業はなるだけ自動化し,実験は寝てるときや他の(自動化できない)クリエイティブな作業中にやらせたほうが精神衛生上良いです.
一方,Python は,スクリプト言語の一種であり,シェルよりも高機能なプログラムを記述できます.
(Python 以外のスクリプト言語としては Perl などが有名です.Perl でも同じことができるでしょう.ですが,僕は個人的な好みで,Python を使ってます)
Python で書いたプログラムはシェルのコマンドの一つとして利用できます.
なので,高度なことをやろうとする場合は Python でコマンドを自作して,シェルで自作プログラムを実行させるように指示を与えるというのが一般的な流れです.
Python をどういう時に使うか?について簡単に述べます.
Python はシェルよりも高速に処理ができます.
少しまともな実験をするようになると,1000万以上もの実数で構成されたデータを扱わなければなりません.
個人的な経験では,100万以上のデータを扱うときは,Python などのスクリプト言語を使うと精神衛生上とても良いです.
では,本題に入っていきましょう.
2 How to use a shell command
2.1 基本的なこと
- ターミナルの起動
- Mac とかで起動時にターミナルが起動していないことがしばしばあると思います.
Mac では Finder を開いて 「アプケーション -> ユーティリティ -> ターミナル.app 」とクリックしていけば起動できます.ターミナルを起動すると,以下のように 「…. $」 (注:…. は使ってるコンピュータの環境によって異なります) とあって入力できるようになります.
.... $
「…. $」 はプロンプトと呼ばれるものです.以降では説明ためにプロンプトは省略します. プロンプトの後にコマンドを入力することで,コンピュータに指示を与えることができます.
2.2 変数の代入と参照
- 変数の代入と参照
- 変数の代入は以下のようにします.変数名の前に '$' を付けない.'='の間にスペースを入れないのがポイントです.
N=3
参照は,以下のようにします.上のサンプルに付け加えると,参照では 変数の前に'$' を付けるのを忘れずに.
N=3 echo $N
- echo コマンド
- print 文みたいなコマンドです.書いたものを標準出力します.例えば,
echo "Hello shell world!"
(以下,出力)
Hello shell world!
というように,書いた文字がそのまま返されます.変数の値を出力したりするのによく使います.
- man コマンド
- シェルの使い方を知る.分からなかったら まずは man を見る.例えば,'man'コマンドの使い方を知るには,
man man
とします.
- jot コマンド
- 1〜N までの数値を生成する.Linux とかだと,'seq'コマンドに対応するもの.
サンプル
N=3 jot $N
(以下,出力)
1 2 3
'for'制御文などと組み合わせたりします.他の使い方もあるので,'man jot' を見ておくといいです.
- cat コマンド
- ファイルの中身を表示する.
以下のようなファイル sample.txt があるとします.
abc def ghi
cat コマンドを打つと,ファイルの中身を表示できます.
cat sample.txt
(以下,出力)
abc def ghi
- リダイレクト
- コマンドの出力結果をファイルに書き込みます.'>' をコマンドの最後に追加して,書き込みたいファイル名を指定します.
echo $RANDOM > random.res cat random.res
(以下,出力)
11875
既存のファイルに追加したい場合は,'>>' を使います.
echo $RANDOM > random.res echo $RANDOM >> random.res cat random.res
(以下,出力)
11875 2524
- パイプ
- コマンドの出力結果を別のコマンドに渡します.以下のように 各コマンドを '|' で挟んで,使います.
ls -l | wc -l
とすると,カレントディレクトリ内のファイルおよびディレクトリ数が返されます.カレントディレクトリ内のファイル詳細一覧を表示する 'ls -l' コマンドが 行数をカウントする 'wc -l' コマンドに渡されています.
2.3 数値の生成と加工(乱数から累積分布の導出まで)
- RANDOM 変数
- 疑似一様乱数(0〜32767)を生成する.
echo $RANDOM echo $RANDOM
(以下,出力)
11875 2524
- for 制御文
- 同じ処理を何度も繰り返し行う.以下のように 4行いっきに入力します.enter ボタンを押して改行していけば,4行いっきに入力できます.'jot 10' ではなく `jot 10` であることに気をつけて.
for i in `jot 10` do echo $RANDOM done
と打つと,'echo $RANDOM' を 10回行った結果(以下)が得られます.
24706 14293 7339 15610 18217 26099 21707 30091 10011 30472
リダイレクトと組合せれば,それぞれの結果を一つのファイルにまとめて格納できます.
for i in `jot 10` do echo $RANDOM >> random.res done cat random.res
(以下,出力)
24706 14293 7339 15610 18217 26099 21707 30091 10011 30472
以下のように,リダイレクトを done の後に書いても等価なことができます.
for i in `jot 10` do echo $RANDOM done > random.res
- awk コマンド
- ライン処理をするコマンドです.これがあれば,だいたいの処理はターミナルで終わります(Excel はいらない).先程の random.res と組み合わせると,
cat random.res | awk '{print $1/32767.0}'
(以下,出力)
0.75609 0.437416 0.224599 0.477721 0.557504 0.798721 0.66431 0.92089 0.306372 0.93255
というように,0 〜 1 までの疑似一様乱数を得ることができます.ちなみに,'$1' はスペースで区切られた各行の最初の列を意味します. awk コマンドには数学関数が内蔵されており,それを使うことで,幅の広い数値処理を行うことができます.例えば,
cat random.res | awk '{print exp($1/32676)}'
(以下,出力)
2.12993 1.5487 1.25182 1.61239 1.74631 2.2227 1.94315 2.51152 1.35849 2.54098
というように,指数関数に代入した結果を得ることができます.他にも 三角関数 'sin', 'cos' や 対数関数 'log',平方根関数 'sqrt' などがあります.
対数関数 'log' や 累乗関数 '^' を使うことにより,指数分布 \(e^{-\lambda\,x}\) やパレート分布 \(x^{-\alpha}\) に従う乱数を生成できます.
指数分布( \(\lambda = 0.5\) )に従う乱数の生成
lambda=0.5 for i in `jot 10` do echo $RANDOM | awk '{print -1/'$lambda'*log($1/32767)}' done
(以下,出力)
0.974322 0.32683 4.00792 0.109064 0.625488 4.91818 2.60046 1.17139 0.315292 0.427802
awk 内で '' で区切ると,ターミナル内で定義した変数を参照できます. 上では,ターミナルで定義されている変数 lambda を awk 内で呼び出しています.
パレート分布( \(\alpha = 1.5\) )に従う乱数の生成
alpha=1.5 for i in `jot 10` do echo $RANDOM | awk '{print ($1/32767)^(-1/'$alpha')}' done
(以下,出力)
1.75621 2.14957 27.929 2.13171 4.08205 2.31263 1.06195 1.0522 1.52362 1.0867
awk を使うことによって,アーランB式 が計算できます.例えば,要求トラヒック数 t (平均到着個数が \(\lambda\) ,平均サービス時間が \(1/\mu\) の M/M/s/s の場合は,\(t= \lambda/\mu\) )を 50.0,および 回線数 s を 10 とした時の,呼損率 B は以下で計算できます.
t=50.0 s=10 jot $s | awk 'BEGIN{B=1.0}{B='$t'*B/($1+'$t'*B)}END{print B}'
(以下,出力)
0.804716
上で使っている awk 内での 'BEGIN' と 'END' では,ライン処理をする前処理と後処理を指定します. ここでは,アーランB式を漸化式を用いて計算するときの初期化を 'BEGIN'で行い,呼損率の出力を 'END' で行っています.
出力行数が大きい時は,awk に条件を与えて,以下のようにして出力結果を間引くことができます.
jot 1000 | awk 'NR % 100 == 0 {print $0}'
(以下,出力)
100 200 300 400 500 600 700 800 900 1000
上では,awk に 'NR % 100 == 0' という条件を加えて,100 行間隔で出力結果を間引いています. awk の NR 変数は,処理している行数を表し,1,2,…,1000 と変化します.NR % 100 は 100 で割った時の余りを返すという意味です. 余りが 0 のとき,つまり 行数 NR が 100行で割り切れる時のみ出力を行うということをしてくれます. また,'print $0' は入力された行の全てを表示するという意味です.
- sort コマンド
- 入力系列をソートします.例えば,
cat random.res | sort -g
(以下,出力)
7339 10011 14293 15610 18217 21707 24706 26099 30091 30472
というように,昇順にソートされた結果を得ることができます. '-g' オプションは,入力を実数として認識するためのオプションです.実験データを扱うときは,常に入れとくといいです.
また,'sort' と 'awk' コマンドを組み合わせれば,以下のように累積分布を得ることができます.
lines=`wc -l random.res | awk '{print $1}'` cat random.res | sort -g | awk 'BEGIN{tmp=-1} tmp<$1 {print $1 " " NR/'$lines'}'
(以下,出力)
7339 0.1 10011 0.2 14293 0.3 15610 0.4 18217 0.5 21707 0.6 24706 0.7 26099 0.8 30091 0.9 30472 1
'awk' の NR 変数は,処理している行数を返します.毎回のライン処理で,1,2,3,..,10 と変化していきます.
- uniq コマンド
- 冗長な行を削除する.例えば,
cat test.res
(以下,出力)
aaa aaa bbb bbb ccc
というようなファイルがあったとします.このファイルの中で冗長な行を取り出したい時は,uniq を使うと便利です. 例えば,以下のように uniq コマンドを使えば,
cat test.res | uniq
(以下,出力)
aaa bbb ccc
というように,冗長な行が取り除かれた結果が得られます.
uniq コマンドを使う際の注意事項として,各行がソートされてなければならないということがあります. 例えば,以下のファイルがあったとします.
cat test2.res
(以下,出力)
aaa bbb bbb ccc aaa
しかし,以下のように uniq を直接使っても思い通りの結果が得られません..(aaa が2つでてくる)
cat test2.res | uniq
(以下,出力)
aaa bbb ccc aaa
なので,sort でファイルをソートしてから uniq をします.
cat test2.res | sort | uniq
(以下,出力)
aaa bbb ccc
めでたし,めでたし.
uniq コマンドの便利なオプションとして '-c' があります. uniq のオプション '-c' は,どれだけ同じ行があったかをついでに出力するオプションです. 先程の test2.res の中にどれだけ同じ行があったを調べるには,
cat test2.res | sort | uniq -c
(以下,出力)
2 aaa 2 bbb 1 ccc
とします.
'uniq -c' は度数分布を得るのに便利です. 例えば,0,1,2 のいづれかの値が 1000個ランダムに出力された時の度数分布を得るためには以下のようにします.
for i in `jot 1000` do echo $RANDOM | awk '{print $1%3}' done | sort -g | uniq -c
(以下,出力)
324 0 330 1 346 2
パイプ以降は 'for' の 'done' の後につづけて書きます. こうすることによって, 'for' 内で出力される 1000個のランダムな 0,1,2 に対しての度数分布を得ることができます.
さらに,指数間隔で発生するイベントの計数過程の分布(ポアソン分布)は以下のようにして出せます.
lambda=0.5 for i in `jot 1000`; do echo $RANDOM | awk '{print -1/'$lambda'*log($1/32767)}' done | awk 'BEGIN{tmp=0}{tmp+=$1; print int(tmp)}' | uniq -c | awk '{print $1}' | sort -g | uniq -c | awk '{print $2 " " $1}'
となります.awk 内の '$1%3' は「3で割った余り」を計算します. なので, for の中身は,0,1,2の数値のいづれかがどばっと出力することになります. なので,uniq を入れることで,冗長な行が削除され
- grep コマンド
- パターンを含む行のみを出力する.
シミュレーションログから必要なデータだけを取り出すことに使用できます. 例えば,シミュレーションログ simulation.log においてデバッグコードの出力行の先頭に 'DEBUG: …' と書いておけば,
$ cat simulation.log | grep "^DEBUG:"
とすることにより,デバッグコードだけを取り出すことができます. '^' は行頭から始まるパターンのみを取り出すという意味になります.
- sed コマンド
- パターンをあるパターンに置き換える.
- paste コマンド
- 複数ファイルの内容を統合する.
- xargs コマンド
- 列を行に変換する.
2.4 統計処理のツール
- stats コマンド
- 阪大の大崎先生が公開している,シェルの統計処理用のツールです.ここ からダウンロードできます.
ダウンロードした stats に実行権限を与えて,適当にパスの通っている場所に置きましょう.
平均を計算するには,先程の random.res (0〜32676の疑似一様乱数)の結果って,以下のように,
cat random.res | stats -t mean
(以下,出力)
19854.5
とすると得ることができます.他に分散や信頼区間などいろいろと計算してくれます.
- xdoplot コマンド
- 阪大の大崎先生が公開している,gnuplot のラッパーツールです.ここ からダウンロードできます.
gnuplot を使って実験データを画面に出力したり,png や eps 形式の画像ファイルに出力したりしてくれます.
例えば,
jot 10000 | awk '{print NR " " $1*$1}' > xx.res xdoplot xx.res
とすると,1〜10,000までの \(x^2\) のグラフを画面表示することができます.(図xx)
図: x2 のグラフ (x の範囲は 1〜10,000)
また,
xdoplot -tg xx.res > xx.png
とすることで,png 形式の画像ファイルを得ることができます.
さらに,
xdoplot -te xx.res > xx.eps
とすることで,eps 形式の画像ファイルを得ることができます.
描画する元データ xx.res に書式を指定することで,縦軸・横軸の名前指定や,軸の片対数表示・両対数表示なども指定することができます.詳しくは,xdoplot のマニュアルを読んでみてください.
2.5 How to make a python script
- まとめているところです
3 Tips
- gnuplot で作成した EPS 画像へのフォント組み込み.(注:組み込まないと,IEEE xPress のテストが通らない)
- ghostscript フォルダにある gspdfwr.ps において,デフォルトでは以下のような記述がある.
/.standardfonts [ /Courier /Courier-Bold /Courier-Oblique /Courier-BoldOblique /Helvetica /Helvetica-Bold /Helvetica-Oblique /Helvetica-BoldOblique /Times-Roman /Times-Bold /Times-Italic /Times-BoldItalic /Symbol /ZapfDingbats ] readonly def
EPS 画像へ 組み込みたい フォントを上の記述から消すことによって,dvipdfmx 等で pdf に変換した時にフォントが組み込まれるようになる.
- ghostscript フォルダにある gspdfwr.ps において,デフォルトでは以下のような記述がある.