April 25, 2014
アドホックに書いたルーチン。数値計算の精度を全く考慮しない。 モジュールとか読み込まなくてもよい。
引数に、数値の配列を渡す。
sub mean { local($s) = 0; local($n) = 0; foreach $_ (@_) { if ($_ =~ /[0-9]/) { $s += $_; $n++; } } if ($n == 0) { ""; } else { $s /= $n; } }
sub dist { local($i, $m, $n, $s); ($m, $n, $s) = (0,0,0); if (@_ < 2) { return 0; } $m = &mean(@_); for ($i = 0; $i < @_; $i++) { if ($_[$i] =~ /[0-9]/) { $s += ($_[$i] - $m) * ($_[$i] - $m); $n++; } } if ($n < 1) { ""; } elsif ($n < 2) { $s; } else { $s /= ($n - 1); } } sub stdev { sqrt(&dist); }
sub median{ my $n = @_; # 元データ配列には空 (null) や "NA" などが入っててもよい my @data; # 整理したデータを格納する my $i; # だたのカウンタ my $k = 0; # だたのカウンタ my @ties; # 中央値のタイがあれば格納される my $ties; # タイの数 my $x; # 中央の場所 my $median; # 返り値 if ($n < 0) { return "" } # ここには来ないはず elsif ($n < 1) { return "" } # 空の配列が渡されたとき elsif ($n < 2) { return $_[0] } # 引数が一つの値だったとき for ($i = 0; $i < $n; $i++) { # 引数が複数の値だったとき if ($_[$i] eq "") { next } # 空 (null) は無視する elsif ($_ =~ /[A-DF-Za-df-z]/) { next } # e/E 以外の英文字を含むと無視 $data[$k++] = $_[$i]; # 条件に合うものだけ拾い出す } @data = sort { <=> } @data; # 昇順にソート $n = @data; # データ数 # 暫定中央値を決める データ数が偶数なら中央をはさむ値の平均値 $x = $n/2; if(($n % 2) < 1) { $median = ($data[$x - 1] + $data[$x]) / 2.0 } else { $median = $data[$x] } # x の小数部は切り捨てて使われる @ties = grep(/$median/, @data); # 暫定中央値がタイか $ties = @ties; if ($ties < 1) { return $median } # タイじゃない場合 else { # タイがある場合 for($i = 0; $i < $n; $i++) { if($_[$i] >= $median) { last } } return ($median - 0.5) + ($n/2 - $i) / $ties; } }
sub max { local ($i,$max); for ($i = 0; $i < @_; $i++) { if ($_[$i] =~ /[0-9]/) { $max = $_[$i]; last; } } foreach $_ (@_) { if (($_ =~ /[0-9]/) && ($max < $_)) { $max = $_; }} if (!($max =~ /[0-9]/)) { $max = ""; } $max; } sub min { local ($i,$min); for ($i = 0; $i < @_; $i++) { if ($_[$i] =~ /[0-9]/) { $min = $_[$i]; last; } } foreach $_ (@_) { if (($_ =~ /[0-9]/) && ($min > $_)) { $min = $_; }} if (!($min =~ /[0-9]/)) { $min = ""; } $min; }