1次元配列の分布をターミナルで可視化して簡単にデバッグする
初書:2020/11/09
php:7.4.10
前置き
タイトルで何言ってるか微妙に伝えづらかったので、説明。
何をしたいのかというと、例えば乱数生成器を作成したとする。その関数がどれくらい偏っているかを簡単に調べたい。
ただグラフを書こうとするとターミナルで実行しても表示できない(知識がないだけかもしれないが)ので、簡
単に可視化する方法がないか考え、棒と色で可視化させようとしたもの。
目標の出力
前置きでも分かりづらいので、画像で(色がmarkdownだと表示できなかった)
ちなみにこれは正規分布乱数を出力している。
こんな感じで、出力の偏りを色で簡単に見れるというもの。
ちなみにターミナル用に作成しているので、いわばデバッグ用である。
コード
先にコードを置いておく。今回はgithubも作成してみたので、ダウンロードして速攻使えるようにしてある。
distribution_show/distribution_show.php at main · yuu-1st/distribution_show
(初めてgithubを使ったので変な使い方してるかも)
で、改めてコード。少し長い。
/**
* ターミナル上で、一次元分布を可視化します。(need PHP 7.3.0)
*
* @param array $arr 分布配列。キーは全て整数値である必要があります。
* @param integer $interval 出力間隔。値は切り捨てで圧縮されます。
* @param int $maxwidth 出力時の横幅。指定文字数を超えると改行されます。
* @return void
*/
function distribution_show(array $arr, int $interval = 1, int $maxwidth = PHP_INT_MAX) : void
{
ksort($arr);
$min = array_key_first($arr);
$max = array_key_last($arr);
$value_max = 0;
$array = [];
for ($i = $min; $i <= $max; $i++) {
$key = (int)floor(($i - $min) / $interval);
$array[$key] ??= 0;
$array[$key] += isset($arr[$i]) ? $arr[$i] : 0;
$value_max = $array[$key] > $value_max ? $array[$key] : $value_max;
}
$console = "";
$co = 0;
$coplus = 0;
for ($i = 0; $i < count($array); $i++) {
if ($array[$i] > 0) {
$color = (int)floor((255 - 232) * ($array[$i] * 1.0 / $value_max) + 232);
printf("\e[38;5;%dm%s\e[m", $color, "|");
} else {
printf(" ");
}
if ($coplus % 10 == 0) {
$key = $min + $i * $interval;
$console .= "↑" . $key;
$coplus += mb_strlen($key) + 1;
} elseif ($co == $coplus) {
$console .= " ";
$coplus++;
}
$co++;
if ($co % $maxwidth === 0) {
printf("\n%s\n", $console);
$console = "";
}
}
printf("\n%s\n", $console);
}
ターミナルで色を出力する
今回のメインとなるところ。グラフで表示するには最低でも二次元平面が必要になるので、一次元で表示するには色しかない。
調べてみると、ターミナルでも色の出力は可能な様子。
参考サイト:
ターミナルのechoやprintfに256色で色をつける 完全版 - vorfee's Tech Blog
bash:tip_colors_and_formatting - FLOZz' MISC
つまり、出力時に\e[38;5;255m文字列なんとか\e[m
を含め、255を指定の色コードに変えれば色を変更することが可能。
ただ残念なことにRGBでの出力は出来ず、256色しかないので、0~255を1ずつ変えて〜は出来ない。
後者の参考サイトに色の一覧が載っているので、有難く拝見させてもらうと、どうやら232-256の間では白黒でグラデーションができるらしい。白黒で十分なので、この領域を使用することにする。
(なお、コード内の指定値は232~255になっているのだが、これは256を選択すると色が変になったので、念のために除外した)
ちなみにphpの場合はechoでもprintfでも上記の出力を行うと色が変化する。今回はターミナルでの出力なので、それらしいprintfを採用した。
配列を操作する
正直これが出来たらあとは作業になる。配列をごちゃごちゃしてprintfで出力するだけなのだから。
詳しい内容はコードを読んでもらうとして、配列操作に使った関数をいくつかメモ。
ksort
PHP: ksort - Manual
配列のキーを昇順に並び替える。
元々作成していた配列が、値0のキーを作成しておき、それに1ずつ足していく、という方法ではなく、その値が出来たらキーを作成して1ずつ足す、という方法であったため、キーが数値順に並んでいなかった。そのため、ここで一度並び替えを行っている。
$array = ["25" => 13, "19" => 43, "8" => 24];
ksort($array);
var_dump($array); // array(3) {[8]=>int(24) [19]=>int(43) [25]=>int(13)}
array_key_first / array_key_last
PHP: array_key_first - Manual
PHP: array_key_last - Manual
配列の先頭のキーもしくは最後のキーを取得する。
ちなみにこの関数はphp7.3で追加されたので、php7.2以前は使えない1
今回は、一つ前でキーソートを行っているので、実質キーの最小値と最大値を取得している。
とまぁとりあえず前処理を行い、あとは一つ目のforループで配列の再生成(間隔圧縮のため)と値の最大値を取得し、二つ目のforループで出力を行っていく。
使ってみる
今回は正規乱数を作成したかったので、以下のサイトを参考に、分布を表示してみる
平均値から正規分布乱数を生成する方法(PHP) | colori
$arr = [];
for ($i = 0; $i < 100000; $i++) {
$a = (int)round(normal(500, 170)); // 参考サイトにあるnormalと同じ
$arr[$a] ??= 0;
$arr[$a]++;
}
distribution_show($arr, 5, 150);
normal関数で乱数を取得し、整数値化。その値のキーをインクリメントすることで、カウントしていく。
そのあと、先ほど作成した関数を呼び出し、第一引数に配列、第二引数には一つの棒がどの範囲を示すか、第三引数は改行する文字数。
今回は基準を500にしているので、500を中心に色が濃い事が分かる。
一応第二引数の詳しい説明をしておくと、今回の画像だと左端が-168を指しているので、この棒一つで-168~-164の5数値がまとめているという事。1ずつだとかなり横長になったので追加した。
まとめ
せっかく作ったけど、実際にこの関数が役に立つことはほとんどないので、誰か使ってあげてください。
-
一応7.2以前でも、独自で実現する方法はあるようなので、7.2以下で使う場合は置き換えれば使用できる。 ↩
Author And Source
この問題について(1次元配列の分布をターミナルで可視化して簡単にデバッグする), 我々は、より多くの情報をここで見つけました https://qiita.com/yuu_1st/items/dc949ea21a98510ddb36著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .