BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlsta_linefit.h
Go to the documentation of this file.
1/// @file bdlsta_linefit.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlsta_linefit.h -*-C++-*-
8#ifndef INCLUDED_BDLSTA_LINEFIT
9#define INCLUDED_BDLSTA_LINEFIT
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14// BDE_VERIFY pragma: -LL01 // Link is just too long
15
16/// @defgroup bdlsta_linefit bdlsta_linefit
17/// @brief Online algorithm for computing the least squares regression line.
18/// @addtogroup bdl
19/// @{
20/// @addtogroup bdlsta
21/// @{
22/// @addtogroup bdlsta_linefit
23/// @{
24///
25/// <h1> Outline </h1>
26/// * <a href="#bdlsta_linefit-purpose"> Purpose</a>
27/// * <a href="#bdlsta_linefit-classes"> Classes </a>
28/// * <a href="#bdlsta_linefit-description"> Description </a>
29/// * <a href="#bdlsta_linefit-usage"> Usage </a>
30/// * <a href="#bdlsta_linefit-example-1-calculating-line-fit-variance-and-mean"> Example 1: Calculating line fit, variance, and mean </a>
31///
32/// # Purpose {#bdlsta_linefit-purpose}
33/// Online algorithm for computing the least squares regression line.
34///
35/// # Classes {#bdlsta_linefit-classes}
36///
37/// - bdlsta::LineFit: online calculation of least squares regression line
38///
39/// # Description {#bdlsta_linefit-description}
40/// This component provides a mechanism, `bdlsta::LineFit`, that
41/// provides online calculation of the least squares line fit. Online
42/// algorithms process the data in one pass, while maintaining accuracy. The
43/// online algorithm used is developed in the implementation notes (it is
44/// similar to the Welford online algorithm for computing variance). The
45/// formulae for line fit are taken from:
46/// https://en.wikipedia.org/wiki/Simple_linear_regression#Fitting_the_regression_line
47///
48/// Note that the behavior is undefined if there are less than 2 data points, or
49/// if all the X's (dependent variable) are the same.
50///
51/// ## Usage {#bdlsta_linefit-usage}
52///
53///
54/// This section illustrates intended use of this component.
55///
56/// ### Example 1: Calculating line fit, variance, and mean {#bdlsta_linefit-example-1-calculating-line-fit-variance-and-mean}
57///
58///
59/// This example shows how to accumulate a set of values, and calculate the
60/// line fit parameters, variance, and mean.
61///
62/// First, we create example input and instantiate the appropriate mechanism:
63/// @code
64/// double inputX[] = { 1.0, 2.0, 4.0, 5.0 };
65/// double inputY[] = { 1.0, 2.0, 4.0, 4.5 };
66/// bdlsta::LineFit lineFit;
67/// @endcode
68/// Then, we invoke the `add` routine to accumulate the data:
69/// @code
70/// for(int i = 0; i < 4; ++i) {
71/// lineFit.add(inputX[i], inputY[i]);
72/// }
73/// @endcode
74/// Finally, we assert that the alpha, beta, variance, and mean are what we
75/// expect:
76/// @code
77/// double alpha, beta;
78/// ASSERT(4 == lineFit.count());
79/// ASSERT(3.0 == lineFit.xMean());
80/// ASSERT(1e-3 > fabs(2.875 - lineFit.yMean()));
81/// ASSERT(1e-3 > fabs(3.33333 - lineFit.variance()));
82/// ASSERT(0 == lineFit.fitIfValid(&alpha, &beta));
83/// ASSERT(1e-3 > fabs(0.175 - alpha));
84/// ASSERT(1e-3 > fabs(0.9 - beta ));
85/// @endcode
86/// @}
87/** @} */
88/** @} */
89
90/** @addtogroup bdl
91 * @{
92 */
93/** @addtogroup bdlsta
94 * @{
95 */
96/** @addtogroup bdlsta_linefit
97 * @{
98 */
99
100// BDE_VERIFY pragma: +LL01
101
102#include <bdlscm_version.h>
103
104#include <bsl_cmath.h>
105
106#include <bsls_assert.h>
107#include <bsls_review.h>
108
109
110namespace bdlsta {
111
112 // =============
113 // class LineFit
114 // =============
115
116/// This class provides an efficient online algorithm for calculating linear
117/// square line fit. The class also calculates the mean for the X's and
118/// Y's, and variance for the X's. These are byproducts of calculating the
119/// line fit. The online algorithm is detailed in the implementation notes.
120///
121/// See @ref bdlsta_linefit
122class LineFit {
123 private:
124 // DATA
125 int d_count; // Number of data points.
126 double d_xMean; // Mean of X's.
127 double d_xSum; // Sum of X's.
128 double d_ySum; // Sum of Y's.
129 double d_M2; // 2nd moment
130 double d_xySum; // Sum of Xi*Yi
131
132 public:
133 // CONSTANTS
134 enum {
137 };
138
139 // CREATORS
140
141 /// Create an empty `LineFit` object.
142 LineFit();
143
144 // MANIPULATORS
145
146 /// Add the specified `(xValue, yValue)` point to the data set.
147 void add(double xValue, double yValue);
148
149 // ACCESSORS
150
151 /// Returns the number of elements in the data set.
152 int count() const;
153
154 /// Calculate line fit coefficients `Y = Alpha + Beta * X`, and populate
155 /// the specified `alpha` (intercept) and `beta` (slope).
156 ///
157 /// \pre The behavior is undefined if `2 > count` or all X's are identical.
158 void fit(double *alpha, double *beta) const;
159
160 /// Calculate line fit coefficients `Y = Alpha + Beta * X`, and populate
161 /// the specified `alpha` (intercept) and `beta` (slope). Return 0 on
162 /// success, and non-zero otherwise. The computations is unsuccessful
163 /// if `2 > count` or all X's are identical.
164 int fitIfValid(double *alpha, double *beta) const;
165
166 /// Return the variance of the data set X's.
167 ///
168 /// \pre The behavior is undefined unless `2 <= count`.
169 double variance() const;
170
171 /// Load into the specified `result`, the variance of the data set X's.
172 /// Return 0 on success, and a non-zero value otherwise. Specifically,
173 /// `e_INADEQUATE_DATA` is returned if `2 > count`.
174 int varianceIfValid(double *result) const;
175
176 /// Return the mean of the data set X's.
177 ///
178 /// \pre The behavior is undefined unless `1 <= count`.
179 double xMean() const;
180
181 /// Load into the specified `result`, the mean of the data set X's.
182 /// Return 0 on success, and a non-zero value otherwise. Specifically,
183 /// `e_INADEQUATE_DATA` is returned if `1 > count`.
184 int xMeanIfValid(double *result) const;
185
186 /// Return the mean of the data set Y's.
187 ///
188 /// \pre The behavior is undefined unless `1 <= count`.
189 double yMean() const;
190
191 /// Load into the specified `result`, the mean of the data set Y's.
192 /// Return 0 on success, and a non-zero value otherwise. Specifically,
193 /// `e_INADEQUATE_DATA` is returned if `1 > count`.
194 int yMeanIfValid(double *result) const;
195};
196
197// ============================================================================
198// INLINE DEFINITIONS
199// ============================================================================
200
201 // ---------------------
202 // class bdlsta::LineFit
203 // ---------------------
204
205// CREATORS
206inline
208: d_count(0)
209, d_xMean(0.0)
210, d_xSum(0.0)
211, d_ySum(0.0)
212, d_M2(0.0)
213, d_xySum(0.0)
214{
215}
216
217// MANIPULATORS
218inline
219void LineFit::add(double xValue, double yValue)
220{
221 const double delta = xValue - d_xMean;
222 ++d_count;
223 d_xSum += xValue;
224 d_ySum += yValue;
225 d_xMean = d_xSum / static_cast<double>(d_count);
226 const double delta2 = xValue - d_xMean;
227 d_M2 += delta * delta2;
228 d_xySum += xValue * yValue;
229}
230
231// ACCESSORS
232inline
233int LineFit::count() const
234{
235 return d_count;
236}
237
238inline
239void LineFit::fit(double *alpha, double *beta) const
240{
241 BSLS_ASSERT(2 <= d_count && 0.0 != d_M2);
242
243 const double n = static_cast<double>(d_count);
244 double tmpBeta = (d_xySum - d_xSum * d_ySum / n) / d_M2;
245 *beta = tmpBeta;
246 *alpha = (d_ySum - d_xSum * tmpBeta) / n;
247}
248
249inline
250int LineFit::fitIfValid(double *alpha, double *beta) const
251{
252 if (2 > d_count || 0.0 == d_M2) {
253 return e_INADEQUATE_DATA; // RETURN
254 }
255 const double n = static_cast<double>(d_count);
256 double tmpBeta = (d_xySum - d_xSum * d_ySum / n) / d_M2;
257 *beta = tmpBeta;
258 *alpha = (d_ySum - d_xSum * tmpBeta) / n;
259 return 0;
260}
261
262inline
263double LineFit::variance() const
264{
265 BSLS_ASSERT(2 <= d_count);
266
267 return d_M2 / (d_count - 1);
268}
269
270inline
271int LineFit::varianceIfValid(double *result) const
272{
273 if (2 > d_count) {
274 return e_INADEQUATE_DATA; // RETURN
275 }
276 *result = variance();
277 return 0;
278}
279
280inline
281double LineFit::xMean() const
282{
283 BSLS_ASSERT(1 <= d_count);
284
285 return d_xSum / static_cast<double>(d_count);
286}
287
288inline
289int LineFit::xMeanIfValid(double *result) const
290{
291 if (1 > d_count) {
292 return e_INADEQUATE_DATA; // RETURN
293 }
294 *result = xMean();
295 return 0;
296}
297
298inline
299double LineFit::yMean() const
300{
301 BSLS_ASSERT(1 <= d_count);
302
303 return d_ySum / static_cast<double>(d_count);
304}
305
306inline
307int LineFit::yMeanIfValid(double *result) const
308{
309 if (1 > d_count) {
310 return e_INADEQUATE_DATA; // RETURN
311 }
312 *result = yMean();
313 return 0;
314}
315
316} // close package namespace
317
318
319#endif
320
321// ----------------------------------------------------------------------------
322// Copyright 2017 Bloomberg Finance L.P.
323//
324// Licensed under the Apache License, Version 2.0 (the "License");
325// you may not use this file except in compliance with the License.
326// You may obtain a copy of the License at
327//
328// http://www.apache.org/licenses/LICENSE-2.0
329//
330// Unless required by applicable law or agreed to in writing, software
331// distributed under the License is distributed on an "AS IS" BASIS,
332// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
333// See the License for the specific language governing permissions and
334// limitations under the License.
335// ----------------------------- END-OF-FILE ----------------------------------
336
337/** @} */
338/** @} */
339/** @} */
Definition bdlsta_linefit.h:122
void fit(double *alpha, double *beta) const
Definition bdlsta_linefit.h:239
@ e_INADEQUATE_DATA
Definition bdlsta_linefit.h:136
@ e_SUCCESS
Definition bdlsta_linefit.h:135
double xMean() const
Definition bdlsta_linefit.h:281
int xMeanIfValid(double *result) const
Definition bdlsta_linefit.h:289
int yMeanIfValid(double *result) const
Definition bdlsta_linefit.h:307
double yMean() const
Definition bdlsta_linefit.h:299
void add(double xValue, double yValue)
Add the specified (xValue, yValue) point to the data set.
Definition bdlsta_linefit.h:219
double variance() const
Definition bdlsta_linefit.h:263
int count() const
Returns the number of elements in the data set.
Definition bdlsta_linefit.h:233
int fitIfValid(double *alpha, double *beta) const
Definition bdlsta_linefit.h:250
LineFit()
Create an empty LineFit object.
Definition bdlsta_linefit.h:207
int varianceIfValid(double *result) const
Definition bdlsta_linefit.h:271
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlsta_linefit.h:110