File Coverage

blib/lib/Statistics/Forecast.pm
Criterion Covered Total %
statement 42 82 51.2
branch 7 16 43.7
condition 4 8 50.0
subroutine 4 5 80.0
pod 3 3 100.0
total 60 114 52.6


line stmt bran cond sub pod time code
1             package Statistics::Forecast;
2            
3             require 5.005_62;
4 1     1   26781 use strict;
  1         3  
  1         624  
5 1     1   49 use warnings;
  1         2  
  1         1570  
6            
7             our $VERSION = '0.3';
8            
9             =head1 NAME
10            
11             Statistics::Forecast - calculates a future value
12            
13             =head1 DESCRIPTION
14            
15             This is a dummy Oriented Object module that calculates a future value by using existing values. The new value is calculated by using linear regression.
16            
17             =head1 SYNOPSIS
18            
19             use Statistics::Forecast;
20            
21             Create forecast object
22            
23             my $FCAST = Statistics::Forecast->new("My Forecast Name");
24            
25             Add data
26            
27             $FCAST->{DataX} = \@Array_X;
28             $FCAST->{DataY} = \@Array_Y;
29             $FCAST->{NextX} = $NextX;
30            
31             Calculate the result
32            
33             $FCAST->calc;
34            
35             Get the result
36            
37             my $Result_Forecast = $FCAST->{ForecastY);
38            
39             =head1 INTERNALS
40            
41             The equation for Forecast is:
42            
43             a+bx, where 'x' is the predicted value and
44             _ _
45             a = y + bx
46            
47             b = sum((x+x)(y-y))/sum(x-x)**2
48            
49             =head1 METHODS
50            
51             =over
52            
53             =item F
54            
55             Receives a forecast name, only to remember
56             and returns the blessed data structure as
57             a Statistics::Forecast object.
58            
59             my $FCAST = Statistics::Forecast->new("My Forecast");
60            
61             =cut
62            
63             ################################################################
64            
65             sub new {
66 1     1 1 81 my $classname= shift(@_);
67 1   50     4 my $ForecastName = shift(@_) || "with no name";
68 1   50     7 my $DataX = shift(@_) || undef;
69 1   50     6 my $DataY = shift(@_) || undef;
70 1   50     14 my $NextX = shift(@_) || undef;
71 1         9 my $self = {
72             ForecastName => $ForecastName,
73             DataX => $DataX,
74             DataY => $DataY,
75             NextX => $NextX,
76            
77             # Initialializing Acumulative variables
78             SumX => 0,
79             SumY => 0,
80             SumXY => 0,
81             SumXX => 0
82             };
83            
84 1         2 bless $self;
85 1         3 return $self;
86            
87             }
88            
89             =item F
90            
91             Calculate and return the forecast value.
92            
93             $FCAST->calc;
94            
95             =cut
96            
97             ################################################################
98            
99             sub calc {
100 1     1 1 49 my $self = shift;
101            
102             # Verify if the inputed values are correct.
103 1 50       5 if (!$self->{DataY}) { die "Cannot run without Y values" };
  0         0  
104            
105             # if no X values were input, populate with 1, 2 ...
106 1 50       2 if ($#{$self->{DataX}} eq -1) {
  1         5  
107 0         0 for (my $X=1; $X <= $#{$self->{DataY}}+1; $X++) {
  0         0  
108 0         0 $self->{DataX}[$X-1] = $X;
109             }
110             }
111            
112 1 50       2 if (join("", @{$self->{DataX}}) =~ /[^0-9\-]/) { die "You tried to input an illegal value to 'X'." };
  1         9  
  0         0  
113 1 50       3 if (join("", @{$self->{DataY}}) =~ /[^0-9\-]/) { die "You tried to input an illegal value to 'Y'." };
  1         8  
  0         0  
114 1 50       5 if ($self->{NextX} =~ /[^0-9\-]/) { die "You tried to input an illegal value to predict." };
  0         0  
115            
116 1 50       2 if ($#{$self->{DataY}} != $#{$self->{DataX}}) { die "Cannot run with different number of 'X' values." };
  1         3  
  1         4  
  0         0  
117 1 50       4 if (!$self->{NextX}) { die "Cannot run with no data point which you want to predict a value." };
  0         0  
118            
119            
120             # Calculate the Sum of Y, X, X*Y and X**2 values.
121 1         2 for (my $X=0; $X <= $#{$self->{DataX}}; $X++) {
  5         14  
122 4         8 $self->{SumY} += $self->{DataY}[$X];
123 4         7 $self->{SumX} += $self->{DataX}[$X];
124 4         9 $self->{SumXY} += ($self->{DataX}[$X] * $self->{DataY}[$X]);
125 4         9 $self->{SumXX} += ($self->{DataX}[$X]**2);
126             }
127            
128 1         2 $self->{N} = $#{$self->{DataX}}+1; # Number of Elements
  1         11  
129 1         4 $self->{AvgX} = $self->{SumX} / $self->{N}; # X Average
130 1         3 $self->{AvgY} = $self->{SumY} / $self->{N}; # Y Average
131            
132 1         4 my $B1 = ($self->{N} * $self->{SumXY} - $self->{SumX} * $self->{SumY});
133 1         3 my $B2 = ($self->{N} * $self->{SumXX} - $self->{SumX}**2 );
134 1         2 my $B = $B1 / $B2;
135 1         3 my $A = $self->{AvgY} - $B*$self->{AvgX};
136            
137 1         5 $self->{ForecastY} = $A + $B*$self->{NextX}; # The forecast
138             }
139            
140             ################################################################
141            
142             =item F
143            
144             Prints data for debuging propose.
145            
146             $FCAST->dump;
147            
148             =item F
149            
150             Returns the sum of X values.
151            
152             my $SumOfX = $FCAST->{SumX};
153            
154             =item F
155            
156             Returns the sum of Y values.
157            
158             my $SumOfY = $FCAST->{SumY};
159            
160             =item F
161            
162             Returns the sum of X**2 values.
163            
164             my $SumOfXX = $FCAST->{SumXX};
165            
166             =item F
167            
168             Returns the sum of X * Y values.
169            
170             my $SumOfXY = $FCAST->{SumXY};
171            
172             =item F
173            
174             Returns the average of X values.
175            
176             my $AvgX = $FCAST->{AvgX};
177            
178             =item F
179            
180             Returns the average of Y values.
181            
182             my $AvgY = $FCAST->{AvgY};
183            
184             =item F
185            
186             Return the number of X values.
187            
188             my $N = $FCAST->{N};
189            
190             =back
191            
192             =cut
193            
194             ################################################################
195            
196             sub dump {
197            
198 0     0 1   my $self = shift;
199 0           print "\n\n";
200 0           print "###########################################\n";
201 0           print " This is a Forecast dump \n";
202 0           print "###########################################\n";
203 0           print "\n";
204 0 0         if ($self->{N}) {
205 0           print ". Forecast Name : ", $self->{ForecastName}, "\n";
206 0           print ". Number of elements: ", $self->{N}, "\n";
207 0           print ". --------------------------------------- \n";
208 0           print ". X Values\n\t", join("; ", @{$self->{DataX}}), "\n";
  0            
209 0           print ". Sum of X values : ", $self->{SumX}, "\n";
210 0           print ". --------------------------------------- \n";
211 0           print ". Y Values\n\t", join("; ", @{$self->{DataY}}), "\n";
  0            
212 0           print ". Sum of Y values : ", $self->{SumY}, "\n";
213 0           print ". --------------------------------------- \n";
214 0           print ". Sum of X*Y values : ", $self->{SumXY}, "\n";
215 0           print ". Sum of X**2 values: ", $self->{SumXX}, "\n";
216 0           print ". --------------------------------------- \n";
217 0           print ". Predict inputed : ", $self->{NextX}, "\n";
218 0           print ". Forecast value : ", $self->{ForecastY}, "\n";
219 0           print ". --------------------------------------- \n";
220 0           print ". Thanks for using Statistics::Forecast\n";
221 0           print ". contact: alexjfalcao\@hotmail.com\n\n";
222             } else {
223 0           print "Error: You have to use method \n";
224 0           print " before dump the values.\n";
225 0           print " Exiting with error code 255.\n";
226 0           print "\n";
227 0           exit (255);
228             }
229             }
230            
231             =head1 EXAMPLE
232            
233             use Statistics::Forecast;
234            
235             my @Y = (1,3,7,12);
236             my @X = (1,2,3,4);
237            
238             my $FCAST = Statistics::Forecast->new("My Forecast");
239            
240             $FCAST->{DataX} = \@X;
241             $FCAST->{DataY} = \@Y;
242             $FCAST->{NextX} = 8;
243             $FCAST->calc;
244            
245             print "The Forecast ", $FCAST->{ForecastName};
246             print " has the forecast value: ", $FCAST->{ForecastY}, "\n";
247            
248             =head1 AUTHOR
249            
250             This module was developed by Alex Falcao (alexjfalcao@hotmail.com)
251            
252             =head1 STATUS OF THE MODULE
253            
254             This is the first version and calculates forecast value.
255            
256             =head1 VERSION
257            
258             0.3
259            
260             =head1 COPYRIGHT
261            
262             This module is released for free public use under a GPL license.
263            
264             =cut
265            
266             1;