File Coverage

blib/lib/Statistics/Robust/Scale.pm
Criterion Covered Total %
statement 102 115 88.7
branch 12 18 66.6
condition n/a
subroutine 15 16 93.7
pod 8 8 100.0
total 137 157 87.2


line stmt bran cond sub pod time code
1             package Statistics::Robust::Scale;
2              
3 1     1   40068 use strict;
  1         3  
  1         38  
4 1     1   7 use warnings;
  1         2  
  1         134  
5 1     1   7 use Carp;
  1         3  
  1         71  
6              
7 1     1   1323 use POSIX qw(floor);
  1         8661  
  1         9  
8 1     1   3043 use Math::CDF qw(qnorm pbeta);
  1         5425  
  1         1529  
9 1     1   2457 use Math::Round qw(round_even);
  1         5052  
  1         100  
10 1     1   927 use Statistics::Robust::Location qw(median);
  1         5  
  1         211  
11              
12 1     1   8 use base qw(Statistics::Robust);
  1         2  
  1         1831  
13              
14             our @EXPORT = ();
15             our @EXPORT_OK = (qw(
16             variance
17             MAD
18             MADN
19             idealf
20             winvar
21             trimvar
22             msmedse
23             pbvar
24             ));
25             our %EXPORT_TAGS = ( all => \@EXPORT_OK );
26              
27             # We need to implement variance since Statistics::Basic
28             # currently is messing up the unbiased variance implementation.
29             sub
30             variance
31             {
32 2     2 1 3 my($x) = @_;
33              
34 2         4 my $length = scalar @$x;
35 2         10 my $sum = Statistics::Robust::_sum($x);
36 2         5 my $mean = $sum/$length;
37              
38 2         6 my $var = 0;
39 2         17 for(my $i=0;$i<@$x;$i++)
40             {
41 34         97 $var += ($mean-$x->[$i])**2;
42             }
43              
44 2         6 return $var/($length-1);
45             }
46              
47             # The Median Absolute Deviation
48             sub
49             MAD
50             {
51 2     2 1 16 my($x) = @_;
52              
53 2         3 my @ad = ();
54              
55 2         11 my($median) = Statistics::Robust::Location::median($x);
56              
57 2         5 foreach my $xi (@$x)
58             {
59 34         48 my($adi) = abs($xi - $median);
60 34         55 push(@ad,$adi);
61             }
62              
63 2         93 my($mad) = Statistics::Robust::Location::median(\@ad) + 0.0;
64              
65              
66 2         7 return $mad;
67             }
68              
69             # The rescaled Median Absolute Deviation
70             sub
71             MADN
72             {
73 1     1 1 837 my($x) = @_;
74            
75 1         3 my $mad = MAD($x);
76 1         70 $mad /= qnorm(0.75);
77              
78 1         5 return $mad;
79             }
80              
81             sub
82             idealf
83             {
84             #
85             # Compute the ideal fourths for data in x
86             # and return the lower and upper quartiles
87             #
88 1     1 1 520 my($x) = @_;
89              
90 1         3 my $n = scalar @$x;
91              
92 1         19 my $j = floor($n/4 + 5/12) - 1;
93 1         6 my @y = sort {$a <=> $b} @$x;
  51         64  
94 1         5 my $g = ($n/4) - $j + (5/12) - 1;
95 1         5 my $ql = (1-$g)*$y[$j] + $g*$y[$j+1];
96 1         3 my $k = $n - $j - 1;
97 1         4 my $qu = (1-$g)*$y[$k] + $g*$y[$k-1];
98              
99 1         4 return ($ql,$qu);
100             }
101              
102             sub
103             winvar
104             {
105 2     2 1 1336 my($x,$tr) = @_;
106              
107 2 100       10 if ( not defined $tr )
108             {
109 1         3 $tr = 0.2;
110             }
111 2         10 my @y = sort {$a <=> $b} @$x;
  102         117  
112              
113 2         8 my $n = scalar @$x;
114 2         11 my $ibot = floor($tr*$n);# + 1;
115 2         5 my $itop = $n - $ibot;# + 1;
116 2         4 my $xbot = $y[$ibot];
117 2         4 my $xtop = $y[$itop];
118 2         8 for(my $i=0;$i<$n;$i++)
119             {
120 34 100       76 if ( $y[$i] <= $xbot )
121             {
122 8         14 $y[$i] = $xbot;
123             }
124 34 100       102 if ( $y[$i] >= $xtop )
125             {
126 8         24 $y[$i] = $xtop;
127             }
128             }
129 2         10 my $winvar = variance(\@y);
130              
131 2         23 return $winvar;
132             }
133              
134             # The variance of the trimmed mean
135             sub
136             trimvar
137             {
138 1     1 1 635 my($x,$tr) = @_;
139              
140 1 50       6 if ( not defined $tr )
141             {
142 1         3 $tr = 0.2;
143             }
144              
145 1         14 my $n = scalar @$x;
146 1         5 my $winvar = winvar($x,$tr);
147 1         4 my $trimvar = $winvar/((1-2*$tr)**2*$n);
148              
149 1         3 return $trimvar;
150             }
151              
152             # Given an array, estimate the standard error of the sample median from pg. 65
153             # of Wilcox, "Introduction to Robust Estimation and Hypothesis Testing", 2005
154              
155             sub
156             msmedse
157             {
158 0     0 1 0 my($x) = @_;
159            
160 0         0 my @sorted = sort {$a <=> $b} @$x;
  0         0  
161 0         0 unshift @sorted, 0.0;
162 0         0 my $n = @sorted -1;
163 0         0 my $av = round_even(($n+1)/2.0 - 2.575829*sqrt($n/4.0));
164 0 0       0 if ( $av == 0 )
165             {
166 0         0 $av = 1.0;
167             }
168 0         0 my $top = ($n - $av + 1);
169 0         0 my $sqse = (($sorted[$top] - $sorted[$av])/(2*2.575829))**2;
170 0         0 $sqse = sqrt($sqse);
171              
172 0         0 return $sqse;
173             }
174              
175             # The percentage bend midvariance
176             sub
177             pbvar
178             {
179 1     1 1 444 my($x,$beta) = @_;
180              
181 1 50       5 if ( not defined $beta )
182             {
183 1         3 $beta = 0.2;
184             }
185 1         2 my $pbvar = 0;
186 1         2 my $n = scalar @$x;
187 1         6 my $median = Statistics::Robust::Location::median($x) + 0.0;
188              
189 1         3 my @w = ();
190 1         5 for(my $i=0;$i<@$x;$i++)
191             {
192 17         60 $w[$i] = ($x->[$i] - $median);
193             }
194              
195 1         4 my @sorted = sort {abs($a) <=> abs($b)} @w;
  51         59  
196 1         8 my $m = floor((1-$beta)*$n + 0.5);
197 1         3 my $omega = $sorted[$m];
198              
199 1 50       5 if ( $omega > 0 )
200             {
201 1         3 my @z=0;
202 1         3 my $np = 0;
203              
204 1         4 for(my $i=0;$i<@w;$i++)
205             {
206 17         25 my $y = $w[$i]/$omega;
207 17 100       40 if ( $y >= 1.0 )
    50          
208             {
209 4         6 $y = 1.0;
210             }
211             elsif ( $y <= -1 )
212             {
213 0         0 $y = -1.0;
214             }
215             else
216             {
217 13         18 $np++;
218             }
219 17         55 $z[$i] = $y**2;
220             }
221            
222 1         7 $pbvar = $n*$omega**2*Statistics::Robust::_sum(\@z)/($np**2);
223             }
224              
225 1         7 return $pbvar;
226             }
227              
228             1;
229              
230             =head1 NAME
231              
232             Statistics::Robust::Scale - Robust Measures of Scale
233              
234             =head1 SYNOPSIS
235              
236             my @x = (1,4,5,3,7,2,4);
237              
238             my($mad) = MAD(\@x);
239             my($madn) = MADN(\@x);
240             my($ql,qu) = idealf(\@x);
241             my($winvar) = winvar(\@x);
242              
243             =head1 FUNCTIONS
244              
245             =head2 MAD
246              
247             my($mad) = MAD(\@x);
248              
249             Return the non-normalized Median Absolute Deviation.
250              
251             =head2 MADN
252              
253             my($madn) = MADN(\@x);
254              
255             Return the Median Absolute Deviation normalized by the 0.75 quartile of the normal distribution.
256              
257             =head2 idealf
258              
259             my($ql,$qu) = idealf(\@x);
260              
261             Return the Ideal Fourths estimate of the lower and upper quartiles (in that order).
262              
263             =head2 winvar
264              
265             my($winvar) = winvar(\@x,$tr);
266              
267             Return the Winsorized variance. If the amount of trimming ($tr) is not specified, it defaults to 0.2.
268              
269             =head2 trimvar
270              
271             my($trimvar) = trimvar(\@x,$tr);
272              
273             Return the variance for the trimmed mean with $tr trimming. If the amount of trimming is not specified,
274             it defaults to 0.2.
275              
276             =head2 variance
277              
278             my($var) = variance(\@x);
279              
280             The unbiased sample variance.
281              
282             =head2 msmedse
283              
284             my($mse) = msmedse(\@x);
285              
286             An estimate of the standard error of the median.
287              
288             =head2 pbvar
289              
290             my($pb) = pbvar(\@x, $beta);
291              
292             The percentage-bend midvariance
293              
294             =head1 AUTHOR
295              
296             Walter Szeliga C<< >>
297              
298             =cut