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)

./figure/xx.png

図: 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 に変換した時にフォントが組み込まれるようになる.

日付: 2014-09-05T13:10+0900

著者: Yusuke Sakumoto

Org version 7.9.3f with Emacs version 24

Validate XHTML 1.0