2014/05/30(金)Perl Data Language 統計編 #06 「時系列データの折れ線グラフ」

データ↓
http://www.tokyo-tosho.co.jp/download/DL02122.zip

問1.1の7)は平均気温の変化を時系列データとして折れ線グラフで描けという問題。これは瞬殺できる問題ですな。

#!/usr/bin/env perl

use strict;
use warnings;
use PDL::Lite;
use PDL::IO::Misc ();
use PDL::Graphics::PLplot;
use DDP filters => { -external => [ 'PDL' ] };

my $infile        = 'weather.csv';
my $colnum_hizuke = 0;
my $colnum_kion   = 1;

my ($hizuke, $heikin_kion) = PDL->rcols($infile, { COLSEP => ',', INCLUDE => qr/[0-9]/ }, $colnum_hizuke, $colnum_kion);

my $pl = PDL::Graphics::PLplot->new(
    DEV   => 'xcairo',
    TITLE => '平均気温の時系列データ',
    XLAB  => '日付',
    XTICK => 2,
    NXSUB => 2,
    YLAB  => '平均気温(℃)',
    YTICK => 1,
    NYSUB => 1,
    COLOR => 'BLUE',
);

$pl->xyplot($hizuke, $heikin_kion, BOX => [ $hizuke->minmax, 0, int($heikin_kion->max) + 2 ]);
$pl->close;

時系列データの折れ線グラフ

2014/05/30(金)Perl Data Language 統計編 #05 「四分位数と箱ひげ図」

データ↓
http://www.tokyo-tosho.co.jp/download/DL02122.zip

問1.1の6)です。

四分位数は、統計検定の試験とかで手計算でやるときは

  1. 昇順ソート
  2. 中央値(Q2)を求める
  3. 中央値点より小さいほうの中央値(Q1)を求める
  4. 中央値点より大きいほうの中央値(Q3)を求める

が一番楽かな。統計検定では四分位数の計算方法は定まっていないようなので、一番楽な計算方法でやりましょう。

コードは以下の通りですが、箱ひげ図はPLplotだと大変なのでRで描画しました。

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw/say/;
use Statistics::R;
use PDL::Lite;
use PDL::IO::Misc ();
use PDL::Graphics::PLplot;
use DDP filters => { -external => [ 'PDL' ] };

my $infile      = 'weather.csv';
my $infile_utf8 = 'weather_utf8.csv';

# 箱ひげ図はRで描画
my $R = Statistics::R->new;
$R->run(qq|weather <- read.csv('$infile_utf8')|);
$R->run(qq|boxplot(weather$平均気温, ylab='heikin kion', xlab='', range=0, data=weather)|);

# 四分位数はPerlで
my $colnum = 1;
my $heikin_kion = PDL->rcols($infile, { COLSEP => ',', INCLUDE => qr/[0-9]/ }, $colnum);

$heikin_kion .= $heikin_kion->qsort;

say '昇順での順位と値';

for my $i ($heikin_kion->listindices)
{
    say $i + 1 . ' ' . $heikin_kion->at($i);
}

print 'n';

say 'Q1: ' . PDL::Ufunc::pct($heikin_kion, 0.25);
say 'Q2: ' . PDL::Ufunc::pct($heikin_kion, 0.5);
say 'Q3: ' . PDL::Ufunc::pct($heikin_kion, 0.75);

出力:

昇順での順位と値
1 2.2
2 2.9
3 2.9
4 3.4
5 3.7
6 3.8
7 3.8
8 4
9 4
10 4.2
11 4.4
12 5
13 5
14 5.1
15 5.1
16 5.3
17 5.4
18 5.5
19 5.5
20 5.7
21 5.9
22 5.9
23 5.9
24 6
25 6.1
26 6.3
27 6.3
28 6.5
29 6.6
30 7
31 7.3

Q1: 4
Q2: 5.3
Q3: 5.95

箱ひげ図

2014/05/29(木)Perl Data Language 統計編 #04 「平均、分散、標準偏差」

データ↓
http://www.tokyo-tosho.co.jp/download/DL02122.zip

問1.1の5)はPDL::Stats を使うと一撃。ですが、勉強にならないので一応普通に計算した場合も載せました。分散を計算するには平均を計算しないといけないので、そこで自由度が1減ると考えて不偏分散を使って計算しました。(統計検定2級のテキストを参照)

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw/say/;
use PDL::Lite;
use PDL::Stats;
use PDL::IO::Misc ();
use DDP filters => { -external => [ 'PDL' ] };

my $infile = 'weather.csv';
my $colnum = 1;
my $heikin_kion = PDL->rcols($infile, { COLSEP => ',', INCLUDE => qr/[0-9]/ }, $colnum);

say "  平均:" . sprintf("%.3f", $heikin_kion->avg);
say "  分散:" . sprintf("%.3f", $heikin_kion->var_unbiased);
say "標準偏差:" . sprintf("%.3f", $heikin_kion->stdv_unbiased);
print "\n";


say "専用メソッドを使わずに分散と標準偏差を計算";

my $avg = $heikin_kion->avg;
my $sum = 0;

for my $i (0 .. $heikin_kion->nelem - 1)
{
    my $hensa = $heikin_kion->at($i) - $avg;
    $sum += $hensa ** 2;
}

my $variance = $sum / ($heikin_kion->nelem - 1);

say "  分散:" . sprintf("%.3f", $variance);
say "標準偏差:" . sprintf("%.3f", sqrt $variance);
  平均:5.055
  分散:1.669
標準偏差:1.292

専用メソッドを使わずに分散と標準偏差を計算
  分散:1.669
標準偏差:1.292

2014/05/29(木)Perl Data Language 統計編 #03 「累積相対度数グラフ」

データ↓
http://www.tokyo-tosho.co.jp/download/DL02122.zip

問1.1の4)はPDL::IO::Misc::rcols でCSVファイルから平均気温のデータのとこだけ抜き出して、相対度数を計算してグラフに出力という流れです。

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw/say/;
use PDL::Lite;
use PDL::IO::Misc ();
use PDL::Graphics::PLplot;
use DDP filters => { -external => [ 'PDL' ] };

my $infile = 'weather.csv';
my $colnum = 1;
my $heikin_kion_list = PDL->rcols($infile, { COLSEP => ',', INCLUDE => '/[0-9]/' }, $colnum);

my $kion_list = pdl [ int($heikin_kion_list->min) - 1 .. int($heikin_kion_list->max) + 1 ];

my $num_elem = $heikin_kion_list->nelem;
my @sotai_freq_list;

for my $kion ($kion_list->list)
{
    my $sotai_freq = $heikin_kion_list->where($heikin_kion_list &lt;= $kion)->nelem / $num_elem * 100;
    push(@sotai_freq_list, $sotai_freq);
}

my $pl = PDL::Graphics::PLplot->new(
    DEV   => 'xcairo',
    TITLE => '平均気温の累積相対度数グラフ',
    XLAB  => '平均気温(℃)',
    YLAB  => '累積相対度数(%)',
    XTICK => 1,
    NXSUB => 1,
    YTICK => 10,
    NYSUB => 1,
    COLOR => 'BLUE',
);

my $sotai_freq_list = pdl @sotai_freq_list;

$pl->xyplot($kion_list, $sotai_freq_list, BOX => [ 0, $kion_list->max, 0, 100 ]);
$pl->close;

sc4-2

2014/05/29(木)Perl Data Language 統計編 #02 「度数分布表と棒グラフ」

http://www.tokyo-tosho.co.jp/download/DL02122.zip

↑のデータを使って実際の問題も解いていきましょう。まずは第1章の練習問題の2)から。

度数分布表はPDLを使わずにテキストで出力しました。 CSVの読み込みは「PDL::IO::Misc」でできるのですが、CSV中の文字列が値ゼロになるので、文字列を含む場合はText::CSVあたりで読み込まざるをえないですね。(このへんはRに比べると少し不便)

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw/say/;
use utf8;
use open qw/:encoding(utf-8) :std/;
use Text::CSV;
use Text::UnicodeTable::Simple;
use PDL::Lite;
use PDL::Graphics::PLplot;
use DDP filters => { -external => [ 'PDL' ] };

my $infile = 'weather.csv';

my $csv = Text::CSV->new({
    auto_diag => 1,
    binary    => 1,
});

open(my $fh, '<:encoding(cp932)', $infile) or die $!;

my $kaze_cnt = 0;
my %kaze_direction_freq_of;

while ( my $row = $csv->getline($fh) )
{
    my ($hizuke, $kion, $shitsudo, $nissho, $kaze_direction) = @{ $row };

    next unless $hizuke =~ /^[0-9]+$/;

    $kaze_direction_freq_of{$kaze_direction}++;
    $kaze_cnt++ if defined $kaze_direction;
}

close($fh);

my $table = Text::UnicodeTable::Simple->new;
$table->set_header(qw/風向き 度数 相対度数/);

for my $direction (keys %kaze_direction_freq_of)
{
    my $freq = $kaze_direction_freq_of{$direction};
    $table->add_row( $direction, $freq, sprintf(&quot;%.3f&quot;, $freq / $kaze_cnt) );
}

say '度数分布表:';
say $table;
say '(相対度数は少数第三位まで表示)';

my $pl = PDL::Graphics::PLplot->new(
    DEV   => 'xcairo',
    XLAB  => '風向き',
    YLAB  => '度数',
    YTICK => 2,
    NYSUB => 2,
    COLOR => 'BLUE',
);

my @labels = keys %kaze_direction_freq_of;
my $values = pdl map { $kaze_direction_freq_of{$_} } @labels;

$pl->bargraph(@labels, $values, BOX => [ 0, scalar @labels, 0, $values->max + 1 ]);

$pl->close;
度数分布表:
.--------+------+----------.
| 風向き | 度数 | 相対度数 |
+--------+------+----------+
| 南東   |    1 |    0.032 |
| 西北西 |    2 |    0.065 |
| 東北東 |    2 |    0.065 |
| 南西   |    1 |    0.032 |
| 北西   |   10 |    0.323 |
| 北北西 |   15 |    0.484 |
'--------+------+----------'

(相対度数は少数第三位まで表示)

棒グラフ