annotate PGAP-1.2.1/Statistics/LineFit.pm @ 0:83e62a1aeeeb draft

Uploaded
author dereeper
date Thu, 24 Jun 2021 13:51:52 +0000
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
1 package Statistics::LineFit;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
2 use strict;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
3 use Carp qw(carp);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
4 BEGIN {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
5 use Exporter ();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
6 use vars qw ($AUTHOR $VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
7 $AUTHOR = 'Richard Anderson <cpan(AT)richardanderson(DOT)org>';
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
8 @EXPORT = @EXPORT_OK = qw();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
9 %EXPORT_TAGS = ();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
10 @ISA = qw(Exporter);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
11 $VERSION = 0.06;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
12 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
13
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
14 sub new {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
15 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
16 # Purpose: Create a new Statistics::LineFit object
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
17 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
18 my ($caller, $validate, $hush) = @_;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
19 my $self = { doneRegress => 0,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
20 gotData => 0,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
21 hush => defined $hush ? $hush : 0,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
22 validate => defined $validate ? $validate : 0,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
23 };
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
24 bless $self, ref($caller) || $caller;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
25 return $self;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
26 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
27
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
28 sub coefficients {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
29 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
30 # Purpose: Return the slope and intercept from least squares line fit
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
31 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
32 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
33 unless (defined $self->{intercept} and defined $self->{slope}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
34 $self->regress() or return;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
35 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
36 return ($self->{intercept}, $self->{slope});
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
37 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
38
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
39 sub computeSums {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
40 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
41 # Purpose: Compute sum of x, y, x**2, y**2 and x*y (private method)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
42 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
43 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
44 my ($sumX, $sumY, $sumXX, $sumYY, $sumXY) = (0, 0, 0, 0, 0);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
45 if (defined $self->{weight}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
46 for (my $i = 0; $i < $self->{numXY}; ++$i) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
47 $sumX += $self->{weight}[$i] * $self->{x}[$i];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
48 $sumY += $self->{weight}[$i] * $self->{y}[$i];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
49 $sumXX += $self->{weight}[$i] * $self->{x}[$i] ** 2;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
50 $sumYY += $self->{weight}[$i] * $self->{y}[$i] ** 2;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
51 $sumXY += $self->{weight}[$i] * $self->{x}[$i]
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
52 * $self->{y}[$i];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
53 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
54 } else {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
55 for (my $i = 0; $i < $self->{numXY}; ++$i) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
56 $sumX += $self->{x}[$i];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
57 $sumY += $self->{y}[$i];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
58 $sumXX += $self->{x}[$i] ** 2;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
59 $sumYY += $self->{y}[$i] ** 2;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
60 $sumXY += $self->{x}[$i] * $self->{y}[$i];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
61 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
62 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
63 return ($sumX, $sumY, $sumXX, $sumYY, $sumXY);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
64 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
65
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
66 sub durbinWatson {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
67 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
68 # Purpose: Return the Durbin-Watson statistic
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
69 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
70 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
71 unless (defined $self->{durbinWatson}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
72 $self->regress() or return;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
73 my $sumErrDiff = 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
74 my $errorTMinus1 = $self->{y}[0] - ($self->{intercept} + $self->{slope}
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
75 * $self->{x}[0]);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
76 for (my $i = 1; $i < $self->{numXY}; ++$i) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
77 my $error = $self->{y}[$i] - ($self->{intercept} + $self->{slope}
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
78 * $self->{x}[$i]);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
79 $sumErrDiff += ($error - $errorTMinus1) ** 2;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
80 $errorTMinus1 = $error;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
81 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
82 $self->{durbinWatson} = $self->sumSqErrors() > 0 ?
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
83 $sumErrDiff / $self->sumSqErrors() : 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
84 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
85 return $self->{durbinWatson};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
86 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
87
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
88 sub meanSqError {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
89 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
90 # Purpose: Return the mean squared error
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
91 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
92 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
93 unless (defined $self->{meanSqError}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
94 $self->regress() or return;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
95 $self->{meanSqError} = $self->sumSqErrors() / $self->{numXY};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
96 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
97 return $self->{meanSqError};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
98 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
99
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
100 sub predictedYs {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
101 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
102 # Purpose: Return the predicted y values
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
103 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
104 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
105 unless (defined $self->{predictedYs}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
106 $self->regress() or return;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
107 $self->{predictedYs} = [];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
108 for (my $i = 0; $i < $self->{numXY}; ++$i) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
109 $self->{predictedYs}[$i] = $self->{intercept}
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
110 + $self->{slope} * $self->{x}[$i];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
111 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
112 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
113 return @{$self->{predictedYs}};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
114 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
115
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
116 sub regress {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
117 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
118 # Purpose: Do weighted or unweighted least squares 2-D line fit (if needed)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
119 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
120 # Description:
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
121 # The equations below apply to both the weighted and unweighted fit: the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
122 # weights are normalized in setWeights(), so the sum of the weights is
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
123 # equal to numXY.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
124 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
125 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
126 return $self->{regressOK} if $self->{doneRegress};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
127 unless ($self->{gotData}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
128 carp "No valid data input - can't do regression" unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
129 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
130 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
131 my ($sumX, $sumY, $sumYY, $sumXY);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
132 ($sumX, $sumY, $self->{sumXX}, $sumYY, $sumXY) = $self->computeSums();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
133 $self->{sumSqDevX} = $self->{sumXX} - $sumX ** 2 / $self->{numXY};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
134 if ($self->{sumSqDevX} != 0) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
135 $self->{sumSqDevY} = $sumYY - $sumY ** 2 / $self->{numXY};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
136 $self->{sumSqDevXY} = $sumXY - $sumX * $sumY / $self->{numXY};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
137 $self->{slope} = $self->{sumSqDevXY} / $self->{sumSqDevX};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
138 $self->{intercept} = ($sumY - $self->{slope} * $sumX) / $self->{numXY};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
139 $self->{regressOK} = 1;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
140 } else {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
141 carp "Can't fit line when x values are all equal" unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
142 $self->{sumXX} = $self->{sumSqDevX} = undef;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
143 $self->{regressOK} = 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
144 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
145 $self->{doneRegress} = 1;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
146 return $self->{regressOK};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
147 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
148
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
149 sub residuals {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
150 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
151 # Purpose: Return the predicted Y values minus the observed Y values
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
152 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
153 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
154 unless (defined $self->{residuals}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
155 $self->regress() or return;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
156 $self->{residuals} = [];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
157 for (my $i = 0; $i < $self->{numXY}; ++$i) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
158 $self->{residuals}[$i] = $self->{y}[$i] - ($self->{intercept}
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
159 + $self->{slope} * $self->{x}[$i]);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
160 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
161 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
162 return @{$self->{residuals}};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
163 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
164
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
165 sub rSquared {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
166 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
167 # Purpose: Return the correlation coefficient
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
168 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
169 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
170 unless (defined $self->{rSquared}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
171 $self->regress() or return;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
172 my $denom = $self->{sumSqDevX} * $self->{sumSqDevY};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
173 $self->{rSquared} = $denom != 0 ? $self->{sumSqDevXY} ** 2 / $denom : 1;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
174 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
175 return $self->{rSquared};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
176 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
177
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
178 sub setData {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
179 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
180 # Purpose: Initialize (x,y) values and optional weights
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
181 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
182 my ($self, $x, $y, $weights) = @_;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
183 $self->{doneRegress} = 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
184 $self->{x} = $self->{y} = $self->{numXY} = $self->{weight}
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
185 = $self->{intercept} = $self->{slope} = $self->{rSquared}
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
186 = $self->{sigma} = $self->{durbinWatson} = $self->{meanSqError}
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
187 = $self->{sumSqErrors} = $self->{tStatInt} = $self->{tStatSlope}
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
188 = $self->{predictedYs} = $self->{residuals} = $self->{sumXX}
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
189 = $self->{sumSqDevX} = $self->{sumSqDevY} = $self->{sumSqDevXY}
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
190 = undef;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
191 if (@$x < 2) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
192 carp "Must input more than one data point!" unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
193 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
194 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
195 $self->{numXY} = @$x;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
196 if (ref $x->[0]) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
197 $self->setWeights($y) or return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
198 $self->{x} = [ ];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
199 $self->{y} = [ ];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
200 foreach my $xy (@$x) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
201 push @{$self->{x}}, $xy->[0];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
202 push @{$self->{y}}, $xy->[1];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
203 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
204 } else {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
205 if (@$x != @$y) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
206 carp "Length of x and y arrays must be equal!" unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
207 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
208 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
209 $self->setWeights($weights) or return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
210 $self->{x} = [ @$x ];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
211 $self->{y} = [ @$y ];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
212 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
213 if ($self->{validate}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
214 unless ($self->validData()) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
215 $self->{x} = $self->{y} = $self->{weights} = $self->{numXY} = undef;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
216 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
217 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
218 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
219 $self->{gotData} = 1;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
220 return 1;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
221 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
222
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
223 sub setWeights {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
224 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
225 # Purpose: Normalize and initialize line fit weighting factors (private method)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
226 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
227 my ($self, $weights) = @_;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
228 return 1 unless defined $weights;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
229 if (@$weights != $self->{numXY}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
230 carp "Length of weight array must equal length of data array!"
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
231 unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
232 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
233 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
234 if ($self->{validate}) { $self->validWeights($weights) or return 0 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
235 my $sumW = my $numNonZero = 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
236 foreach my $weight (@$weights) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
237 if ($weight < 0) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
238 carp "Weights must be non-negative numbers!" unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
239 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
240 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
241 $sumW += $weight;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
242 if ($weight != 0) { ++$numNonZero }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
243 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
244 if ($numNonZero < 2) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
245 carp "At least two weights must be nonzero!" unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
246 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
247 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
248 my $factor = @$weights / $sumW;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
249 foreach my $weight (@$weights) { $weight *= $factor }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
250 $self->{weight} = [ @$weights ];
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
251 return 1;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
252 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
253
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
254 sub sigma {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
255 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
256 # Purpose: Return the estimated homoscedastic standard deviation of the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
257 # error term
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
258 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
259 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
260 unless (defined $self->{sigma}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
261 $self->regress() or return;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
262 $self->{sigma} = $self->{numXY} > 2 ?
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
263 sqrt($self->sumSqErrors() / ($self->{numXY} - 2)) : 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
264 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
265 return $self->{sigma};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
266 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
267
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
268 sub sumSqErrors {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
269 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
270 # Purpose: Return the sum of the squared errors (private method)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
271 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
272 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
273 unless (defined $self->{sumSqErrors}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
274 $self->regress() or return;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
275 $self->{sumSqErrors} = $self->{sumSqDevY} - $self->{sumSqDevX}
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
276 * $self->{slope} ** 2;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
277 if ($self->{sumSqErrors} < 0) { $self->{sumSqErrors} = 0 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
278 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
279 return $self->{sumSqErrors};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
280 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
281
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
282 sub tStatistics {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
283 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
284 # Purpose: Return the T statistics
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
285 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
286 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
287 unless (defined $self->{tStatInt} and defined $self->{tStatSlope}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
288 $self->regress() or return;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
289 my $biasEstimateInt = $self->sigma() * sqrt($self->{sumXX}
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
290 / ($self->{sumSqDevX} * $self->{numXY}));
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
291 $self->{tStatInt} = $biasEstimateInt != 0 ?
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
292 $self->{intercept} / $biasEstimateInt : 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
293 my $biasEstimateSlope = $self->sigma() / sqrt($self->{sumSqDevX});
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
294 $self->{tStatSlope} = $biasEstimateSlope != 0 ?
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
295 $self->{slope} / $biasEstimateSlope : 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
296 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
297 return ($self->{tStatInt}, $self->{tStatSlope});
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
298 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
299
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
300 sub validData {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
301 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
302 # Purpose: Verify that the input x-y data are numeric (private method)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
303 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
304 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
305 for (my $i = 0; $i < $self->{numXY}; ++$i) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
306 if (not defined $self->{x}[$i]) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
307 carp "Input x[$i] is not defined" unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
308 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
309 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
310 if ($self->{x}[$i] !~
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
311 /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
312 {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
313 carp "Input x[$i] is not a number: $self->{x}[$i]"
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
314 unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
315 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
316 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
317 if (not defined $self->{y}[$i]) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
318 carp "Input y[$i] is not defined" unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
319 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
320 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
321 if ($self->{y}[$i] !~
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
322 /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
323 {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
324 carp "Input y[$i] is not a number: $self->{y}[$i]"
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
325 unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
326 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
327 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
328 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
329 return 1;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
330 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
331
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
332 sub validWeights {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
333 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
334 # Purpose: Verify that the input weights are numeric (private method)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
335 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
336 my ($self, $weights) = @_;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
337 for (my $i = 0; $i < @$weights; ++$i) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
338 if (not defined $weights->[$i]) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
339 carp "Input weights[$i] is not defined" unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
340 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
341 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
342 if ($weights->[$i]
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
343 !~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
344 {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
345 carp "Input weights[$i] is not a number: $weights->[$i]"
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
346 unless $self->{hush};
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
347 return 0;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
348 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
349 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
350 return 1;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
351 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
352
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
353 sub varianceOfEstimates {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
354 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
355 # Purpose: Return the variances in the estimates of the intercept and slope
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
356 #
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
357 my $self = shift;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
358 unless (defined $self->{intercept} and defined $self->{slope}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
359 $self->regress() or return;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
360 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
361 my @predictedYs = $self->predictedYs();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
362 my ($s, $sx, $sxx) = (0, 0, 0);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
363 if (defined $self->{weight}) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
364 for (my $i = 0; $i < $self->{numXY}; ++$i) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
365 my $variance = ($predictedYs[$i] - $self->{y}[$i]) ** 2;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
366 next if 0 == $variance;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
367 $s += 1.0 / $variance;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
368 $sx += $self->{weight}[$i] * $self->{x}[$i] / $variance;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
369 $sxx += $self->{weight}[$i] * $self->{x}[$i] ** 2 / $variance;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
370 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
371 } else {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
372 for (my $i = 0; $i < $self->{numXY}; ++$i) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
373 my $variance = ($predictedYs[$i] - $self->{y}[$i]) ** 2;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
374 next if 0 == $variance;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
375 $s += 1.0 / $variance;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
376 $sx += $self->{x}[$i] / $variance;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
377 $sxx += $self->{x}[$i] ** 2 / $variance;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
378 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
379 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
380 my $denominator = ($s * $sxx - $sx ** 2);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
381 if (0 == $denominator) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
382 return;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
383 } else {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
384 return ($sxx / $denominator, $s / $denominator);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
385 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
386 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
387
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
388 1;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
389
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
390 __END__
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
391
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
392 =head1 NAME
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
393
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
394 Statistics::LineFit - Least squares line fit, weighted or unweighted
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
395
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
396 =head1 SYNOPSIS
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
397
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
398 use Statistics::LineFit;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
399 $lineFit = Statistics::LineFit->new();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
400 $lineFit->setData (\@xValues, \@yValues) or die "Invalid data";
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
401 ($intercept, $slope) = $lineFit->coefficients();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
402 defined $intercept or die "Can't fit line if x values are all equal";
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
403 $rSquared = $lineFit->rSquared();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
404 $meanSquaredError = $lineFit->meanSqError();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
405 $durbinWatson = $lineFit->durbinWatson();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
406 $sigma = $lineFit->sigma();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
407 ($tStatIntercept, $tStatSlope) = $lineFit->tStatistics();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
408 @predictedYs = $lineFit->predictedYs();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
409 @residuals = $lineFit->residuals();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
410 (varianceIntercept, $varianceSlope) = $lineFit->varianceOfEstimates();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
411
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
412 =head1 DESCRIPTION
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
413
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
414 The Statistics::LineFit module does weighted or unweighted least-squares
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
415 line fitting to two-dimensional data (y = a + b * x). (This is also called
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
416 linear regression.) In addition to the slope and y-intercept, the module
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
417 can return the square of the correlation coefficient (R squared), the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
418 Durbin-Watson statistic, the mean squared error, sigma, the t statistics,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
419 the variance of the estimates of the slope and y-intercept,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
420 the predicted y values and the residuals of the y values. (See the METHODS
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
421 section for a description of these statistics.)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
422
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
423 The module accepts input data in separate x and y arrays or a single
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
424 2-D array (an array of arrayrefs). The optional weights are input in a
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
425 separate array. The module can optionally verify that the input data and
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
426 weights are valid numbers. If weights are input, the line fit minimizes
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
427 the weighted sum of the squared errors and the following statistics are
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
428 weighted: the correlation coefficient, the Durbin-Watson statistic, the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
429 mean squared error, sigma and the t statistics.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
430
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
431 The module is state-oriented and caches its results. Once you call the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
432 setData() method, you can call the other methods in any order or call a
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
433 method several times without invoking redundant calculations. After calling
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
434 setData(), you can modify the input data or weights without affecting the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
435 module's results.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
436
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
437 The decision to use or not use weighting could be made using your a
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
438 priori knowledge of the data or using supplemental data. If the data is
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
439 sparse or contains non-random noise, weighting can degrade the solution.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
440 Weighting is a good option if some points are suspect or less relevant (e.g.,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
441 older terms in a time series, points that are known to have more noise).
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
442
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
443 =head1 ALGORITHM
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
444
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
445 The least-square line is the line that minimizes the sum of the squares
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
446 of the y residuals:
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
447
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
448 Minimize SUM((y[i] - (a + b * x[i])) ** 2)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
449
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
450 Setting the parial derivatives of a and b to zero yields a solution that
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
451 can be expressed in terms of the means, variances and covariances of x and y:
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
452
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
453 b = SUM((x[i] - meanX) * (y[i] - meanY)) / SUM((x[i] - meanX) ** 2)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
454
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
455 a = meanY - b * meanX
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
456
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
457 Note that a and b are undefined if all the x values are the same.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
458
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
459 If you use weights, each term in the above sums is multiplied by the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
460 value of the weight for that index. The program normalizes the weights
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
461 (after copying the input values) so that the sum of the weights equals
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
462 the number of points. This minimizes the differences between the weighted
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
463 and unweighted equations.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
464
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
465 Statistics::LineFit uses equations that are mathematically equivalent to
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
466 the above equations and computationally more efficient. The module runs
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
467 in O(N) (linear time).
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
468
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
469 =head1 LIMITATIONS
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
470
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
471 The regression fails if the input x values are all equal or the only unequal
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
472 x values have zero weights. This is an inherent limit to fitting a line of
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
473 the form y = a + b * x. In this case, the module issues an error message
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
474 and methods that return statistical values will return undefined values.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
475 You can also use the return value of the regress() method to check the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
476 status of the regression.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
477
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
478 As the sum of the squared deviations of the x values approaches zero,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
479 the module's results becomes sensitive to the precision of floating point
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
480 operations on the host system.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
481
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
482 If the x values are not all the same and the apparent "best fit" line is
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
483 vertical, the module will fit a horizontal line. For example, an input of
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
484 (1, 1), (1, 7), (2, 3), (2, 5) returns a slope of zero, an intercept of 4
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
485 and an R squared of zero. This is correct behavior because this line is the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
486 best least-squares fit to the data for the given parameterization
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
487 (y = a + b * x).
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
488
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
489 On a 32-bit system the results are accurate to about 11 significant digits,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
490 depending on the input data. Many of the installation tests will fail
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
491 on a system with word lengths of 16 bits or fewer. (You might want to
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
492 upgrade your old 80286 IBM PC.)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
493
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
494 =head1 EXAMPLES
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
495
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
496 =head2 Alternate calling sequence:
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
497
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
498 use Statistics::LineFit;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
499 $lineFit = Statistics::LineFit->new();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
500 $lineFit->setData(\@x, \@y) or die "Invalid regression data\n";
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
501 if (defined $lineFit->rSquared()
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
502 and $lineFit->rSquared() > $threshold)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
503 {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
504 ($intercept, $slope) = $lineFit->coefficients();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
505 print "Slope: $slope Y-intercept: $intercept\n";
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
506 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
507
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
508 =head2 Multiple calls with same object, validate input, suppress error messages:
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
509
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
510 use Statistics::LineFit;
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
511 $lineFit = Statistics::LineFit->new(1, 1);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
512 while (1) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
513 @xy = read2Dxy(); # User-supplied subroutine
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
514 $lineFit->setData(\@xy);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
515 ($intercept, $slope) = $lineFit->coefficients();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
516 if (defined $intercept) {
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
517 print "Slope: $slope Y-intercept: $intercept\n";
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
518 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
519 }
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
520
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
521 =head1 METHODS
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
522
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
523 The module is state-oriented and caches its results. Once you call the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
524 setData() method, you can call the other methods in any order or call
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
525 a method several times without invoking redundant calculations.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
526
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
527 The regression fails if the x values are all the same. In this case,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
528 the module issues an error message and methods that return statistical
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
529 values will return undefined values. You can also use the return value
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
530 of the regress() method to check the status of the regression.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
531
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
532 =head2 new() - create a new Statistics::LineFit object
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
533
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
534 $lineFit = Statistics::LineFit->new();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
535 $lineFit = Statistics::LineFit->new($validate);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
536 $lineFit = Statistics::LineFit->new($validate, $hush);
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
537
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
538 $validate = 1 -> Verify input data is numeric (slower execution)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
539 0 -> Don't verify input data (default, faster execution)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
540 $hush = 1 -> Suppress error messages
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
541 = 0 -> Enable error messages (default)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
542
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
543 =head2 coefficients() - Return the slope and y intercept
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
544
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
545 ($intercept, $slope) = $lineFit->coefficients();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
546
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
547 The returned list is undefined if the regression fails.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
548
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
549 =head2 durbinWatson() - Return the Durbin-Watson statistic
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
550
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
551 $durbinWatson = $lineFit->durbinWatson();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
552
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
553 The Durbin-Watson test is a test for first-order autocorrelation in
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
554 the residuals of a time series regression. The Durbin-Watson statistic
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
555 has a range of 0 to 4; a value of 2 indicates there is no
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
556 autocorrelation.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
557
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
558 The return value is undefined if the regression fails. If weights are
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
559 input, the return value is the weighted Durbin-Watson statistic.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
560
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
561 =head2 meanSqError() - Return the mean squared error
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
562
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
563 $meanSquaredError = $lineFit->meanSqError();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
564
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
565 The return value is undefined if the regression fails. If weights are
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
566 input, the return value is the weighted mean squared error.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
567
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
568 =head2 predictedYs() - Return the predicted y values
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
569
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
570 @predictedYs = $lineFit->predictedYs();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
571
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
572 The returned list is undefined if the regression fails.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
573
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
574 =head2 regress() - Do the least squares line fit (if not already done)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
575
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
576 $lineFit->regress() or die "Regression failed"
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
577
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
578 You don't need to call this method because it is invoked by the other
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
579 methods as needed. After you call setData(), you can call regress()
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
580 at any time to get the status of the regression for the current data.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
581
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
582 =head2 residuals() - Return predicted y values minus input y values
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
583
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
584 @residuals = $lineFit->residuals();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
585
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
586 The returned list is undefined if the regression fails.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
587
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
588 =head2 rSquared() - Return the square of the correlation coefficient
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
589
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
590 $rSquared = $lineFit->rSquared();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
591
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
592 R squared, also called the square of the Pearson product-moment correlation
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
593 coefficient, is a measure of goodness-of-fit. It is the fraction of the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
594 variation in Y that can be attributed to the variation in X. A perfect fit
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
595 will have an R squared of 1; fitting a line to the vertices of a
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
596 regular polygon will yield an R squared of zero. Graphical displays of data
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
597 with an R squared of less than about 0.1 do not show a visible linear trend.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
598
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
599 The return value is undefined if the regression fails. If weights are
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
600 input, the return value is the weighted correlation coefficient.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
601
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
602 =head2 setData() - Initialize (x,y) values and optional weights
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
603
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
604 $lineFit->setData(\@x, \@y) or die "Invalid regression data";
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
605 $lineFit->setData(\@x, \@y, \@weights) or die "Invalid regression data";
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
606 $lineFit->setData(\@xy) or die "Invalid regression data";
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
607 $lineFit->setData(\@xy, \@weights) or die "Invalid regression data";
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
608
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
609 @xy is an array of arrayrefs; x values are $xy[$i][0], y values are
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
610 $xy[$i][1]. (The module does not access any indices greater than $xy[$i][1],
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
611 so the arrayrefs can point to arrays that are longer than two elements.)
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
612 The method identifies the difference between the first and fourth calling
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
613 signatures by examining the first argument.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
614
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
615 The optional weights array must be the same length as the data array(s).
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
616 The weights must be non-negative numbers; at least two of the weights
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
617 must be nonzero. Only the relative size of the weights is significant:
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
618 the program normalizes the weights (after copying the input values) so
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
619 that the sum of the weights equals the number of points. If you want to
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
620 do multiple line fits using the same weights, the weights must be passed
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
621 to each call to setData().
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
622
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
623 The method will return zero if the array lengths don't match, there are
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
624 less than two data points, any weights are negative or less than two of
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
625 the weights are nonzero. If the new() method was called with validate = 1,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
626 the method will also verify that the data and weights are valid numbers.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
627 Once you successfully call setData(), the next call to any method other than
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
628 new() or setData() invokes the regression. You can modify the input data
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
629 or weights after calling setData() without affecting the module's results.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
630
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
631 =head2 sigma() - Return the standard error of the estimate
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
632
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
633 $sigma = $lineFit->sigma();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
634
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
635 Sigma is an estimate of the homoscedastic standard deviation of the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
636 error. Sigma is also known as the standard error of the estimate.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
637
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
638 The return value is undefined if the regression fails. If weights are
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
639 input, the return value is the weighted standard error.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
640
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
641 =head2 tStatistics() - Return the t statistics
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
642
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
643 (tStatIntercept, $tStatSlope) = $lineFit->tStatistics();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
644
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
645 The t statistic, also called the t ratio or Wald statistic, is used to
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
646 accept or reject a hypothesis using a table of cutoff values computed from
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
647 the t distribution. The t-statistic suggests that the estimated value is
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
648 (reasonable, too small, too large) when the t-statistic is (close to zero,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
649 large and positive, large and negative).
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
650
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
651 The returned list is undefined if the regression fails. If weights
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
652 are input, the returned values are the weighted t statistics.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
653
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
654 =head2 varianceOfEstimates() - Return variances of estimates of intercept, slope
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
655
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
656 (varianceIntercept, $varianceSlope) = $lineFit->varianceOfEstimates();
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
657
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
658 Assuming the data are noisy or inaccurate, the intercept and slope returned
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
659 by the coefficients() method are only estimates of the true intercept and
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
660 slope. The varianceofEstimate() method returns the variances of the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
661 estimates of the intercept and slope, respectively. See Numerical Recipes
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
662 in C, section 15.2 (Fitting Data to a Straight Line), equation 15.2.9.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
663
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
664 The returned list is undefined if the regression fails. If weights
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
665 are input, the returned values are the weighted variances.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
666
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
667 =head1 SEE ALSO
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
668
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
669 Mendenhall, W., and Sincich, T.L., 2003, A Second Course in Statistics:
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
670 Regression Analysis, 6th ed., Prentice Hall.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
671 Press, W. H., Flannery, B. P., Teukolsky, S. A., Vetterling, W. T., 1992,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
672 Numerical Recipes in C : The Art of Scientific Computing, 2nd ed.,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
673 Cambridge University Press.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
674 The man page for perl(1).
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
675 The CPAN modules Statistics::OLS, Statistics::GaussHelmert and
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
676 Statistics::Regression.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
677
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
678 Statistics::LineFit is simpler to use than Statistics::GaussHelmert or
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
679 Statistics::Regression. Statistics::LineFit was inspired by and borrows some
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
680 ideas from the venerable Statistics::OLS module.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
681
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
682 The significant differences
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
683 between Statistics::LineFit and Statistics::OLS (version 0.07) are:
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
684
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
685 =over 4
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
686
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
687 =item B<Statistics::LineFit is more robust.>
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
688
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
689 Statistics::OLS returns incorrect results for certain input datasets.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
690 Statistics::OLS does not deep copy its input arrays, which can lead
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
691 to subtle bugs. The Statistics::OLS installation test has only one
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
692 test and does not verify that the regression returns correct results.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
693 In contrast, Statistics::LineFit has over 200 installation tests that use
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
694 various datasets/calling sequences to verify the accuracy of the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
695 regression to within 1.0e-10.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
696
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
697 =item B<Statistics::LineFit is faster.>
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
698
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
699 For a sequence of calls to new(), setData(\@x, \@y) and regress(),
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
700 Statistics::LineFit is faster than Statistics::OLS by factors of 2.0, 1.6
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
701 and 2.4 for array lengths of 5, 100 and 10000, respectively.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
702
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
703 =item B<Statistics::LineFit can do weighted or unweighted regression.>
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
704
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
705 Statistics::OLS lacks this option.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
706
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
707 =item B<Statistics::LineFit has a better interface.>
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
708
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
709 Once you call the Statistics::LineFit::setData() method, you can call the
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
710 other methods in any order and call methods multiple times without invoking
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
711 redundant calculations. Statistics::LineFit lets you enable or disable
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
712 data verification or error messages.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
713
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
714 =item B<Statistics::LineFit has better code and documentation.>
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
715
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
716 The code in Statistics::LineFit is more readable, more object oriented and
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
717 more compliant with Perl coding standards than the code in Statistics::OLS.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
718 The documentation for Statistics::LineFit is more detailed and complete.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
719
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
720 =back
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
721
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
722 =head1 AUTHOR
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
723
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
724 Richard Anderson, cpan(AT)richardanderson(DOT)org,
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
725 http://www.richardanderson.org
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
726
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
727 =head1 LICENSE
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
728
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
729 This program is free software; you can redistribute it and/or modify it under
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
730 the same terms as Perl itself.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
731
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
732 The full text of the license can be found in the LICENSE file included in
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
733 the distribution and available in the CPAN listing for Statistics::LineFit
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
734 (see www.cpan.org or search.cpan.org).
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
735
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
736 =head1 DISCLAIMER
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
737
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
738 To the maximum extent permitted by applicable law, the author of this
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
739 module disclaims all warranties, either express or implied, including
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
740 but not limited to implied warranties of merchantability and fitness for
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
741 a particular purpose, with regard to the software and the accompanying
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
742 documentation.
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
743
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
744 =cut
83e62a1aeeeb Uploaded
dereeper
parents:
diff changeset
745