Muji Blog

いろんなトピックを備忘録的に発信していきます。トピック例:{画像処理、信号処理、心理学}

perlで手軽に統計量を計算する

はじめに

ブログもほぼ1年ぶりの更新。色々あって転職しました。

今回の記事は、perlを使った記事です。

環境を変えるたびに作り直すのが面倒なので、ここに記録しておくことにしました。

perlとは

wikipediaによると以下のように説明されています。

Perl(パール)とは、ラリー・ウォールによって開発されたプログラミング言語である。実用性と多様性を重視しており、C言語sedawkシェルスクリプトなど他のプログラミング言語の優れた機能を取り入れている。ウェブ・アプリケーション、システム管理、テキスト処理などのプログラムを書くのに広く用いられている。

このsed, awk, シェルスクリプトとの相性の良さから、perlで作成されたツールをシェルスクリプト内で呼び出すような使われ方を良く見かけます。
音声認識ツールキットのKaldiでも、中身を覗くとperlのツールがたくさんあり、シェルスクリプト内で呼び出すように使われています。)

シェルスクリプトを書いたり、bashを使って作業する人には、perlは欠かせないように思います。

perlで統計量計算

今回作成したツールは、コマンドライン上の標準出力をperlに入力して動作するものになっています。
合計、行の数(=データの数)、平均、標準偏差を算出する仕様になっています。
使い方は後述します。

#!/usr/bin/perl                                                                                            

use strict;
use warnings;
use utf8;
binmode STDIN, ':utf8';
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

my $sum;
my $count;
my @arr;
while( <STDIN> ){
    chomp;

    $sum += $_; 
    $count++;
    @arr = (@arr, $_);
}

print "SUM : $sum \n";
print "COUNT : $count \n";

my $mean = $sum / $count;
print "MEAN : $mean \n";

my $dist_sum;
for ( @arr ){
    my $dist_sq = ($_ - $mean) ** 2;
    $dist_sum += $dist_sq;
}

my $sd = sqrt($dist_sum / $count);
print "SD : $sd \n";

使い方

Macであればターミナル上で動作します。
WindowsではWSL(Windows Subsystem for Linux)が使える環境であることが前提です。

また、前項のツールは、meansd_stdin.plというファイル名で保存し、ホームディレクトリ(~)の下に作成したtoolsフォルダの中に配置しています。

データの準備

今回はサンプルデータの王道、irisデータセットを使いたいと思います。
以下からダウンロードしました。
https://archive.ics.uci.edu/ml/datasets/Iris

iris.dataをダウンロードし、コマンドライン上でiris.dataがある場所に移動の上で以下のように入力すると、データの冒頭部分が見れると思います。

head iris.data
5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
5.0,3.6,1.4,0.2,Iris-setosa
5.4,3.9,1.7,0.4,Iris-setosa
4.6,3.4,1.4,0.3,Iris-setosa
5.0,3.4,1.5,0.2,Iris-setosa
4.4,2.9,1.4,0.2,Iris-setosa
4.9,3.1,1.5,0.1,Iris-setosa

統計量の計算

今回作成したツールは、1列分のデータのみを受け付けるようになっています。
したがって、iris.dataから1列分だけ読み取るようにする必要があります。
今回は、3列目のデータを抜き出してみましょう。

以下のように入力すると、3列目だけを抜き取ることができます。

cat iris.data | cut -d , -f 3
1.4
1.4
1.3
1.5
1.4
1.7
1.4
1.5
...続く

cut コマンドは、各行のある部分だけを抜き出して出力してくれるコマンドです。
今回は、-dオプションで','を指定し、-fオプションで'3'を指定しているので、「,で区切られた3フィールド目を表示」するようにしています。

次に、このデータは最終行が空行になっているため、以下のように入力して空行を削除します。

cat iris.data | cut -d , -f 3 | sed '/^$/d'

sedコマンドは、置換したり削除したり、追加するときに便利なコマンドです。
こちらのページが非常に参考になります。

qiita.com


では、この3列目のデータを入力に、統計量を計算しましょう。
コマンドライン上で以下のように入力します。

cat iris.data | cut -d , -f 3 | sed '/^$/d' | ~/tools/meansd_stdin.pl 

以下のように出力されるかと思います。

SUM : 563.8 
COUNT : 150 
MEAN : 3.75866666666667 
SD : 1.75852918340552 

おまけ

irisは、品種ごとに比較することを想定したデータセットなので、ある品種における統計量を見たくなるかもしれません。

そんなときは以下のように使用する行を絞り込みましょう。

cat iris.data | grep Iris-setosa | cut -d , -f 3 | sed -e '/^$/d' | ~/tools/meansd_stdin.pl

前項で紹介した入力内容との差分を取ると、grepコマンドが増えています。
grepコマンドは、文字列を指定して、それを含む行(あるいは含まない行)を絞り込むために使用します。
(指定している文字列「以外」の行に絞り込む場合は-vオプションを使います。)

以下のように、結果が変わります。

SUM : 73.2 
COUNT : 50 
MEAN : 1.464 
SD : 0.171767284428671 

以上です。