@@ -13,6 +13,8 @@ use crate::imp_prelude::*;
1313use crate :: itertools:: enumerate;
1414use crate :: numeric_util;
1515
16+ use crate :: { FoldWhile , Zip } ;
17+
1618/// # Numerical Methods for Arrays
1719impl < A , S , D > ArrayBase < S , D >
1820where
@@ -111,6 +113,114 @@ where
111113 sum
112114 }
113115
116+ /// Return variance of elements in the array.
117+ ///
118+ /// The variance is computed using the [Welford one-pass
119+ /// algorithm](https://www.jstor.org/stable/1266577).
120+ ///
121+ /// The parameter `ddof` specifies the "delta degrees of freedom". For
122+ /// example, to calculate the population variance, use `ddof = 0`, or to
123+ /// calculate the sample variance, use `ddof = 1`.
124+ ///
125+ /// The variance is defined as:
126+ ///
127+ /// ```text
128+ /// 1 n
129+ /// variance = ―――――――― ∑ (xᵢ - x̅)²
130+ /// n - ddof i=1
131+ /// ```
132+ ///
133+ /// where
134+ ///
135+ /// ```text
136+ /// 1 n
137+ /// x̅ = ― ∑ xᵢ
138+ /// n i=1
139+ /// ```
140+ ///
141+ /// and `n` is the length of the array.
142+ ///
143+ /// **Panics** if `ddof` is less than zero or greater than `n`
144+ ///
145+ /// # Example
146+ ///
147+ /// ```
148+ /// use ndarray::array;
149+ /// use approx::assert_abs_diff_eq;
150+ ///
151+ /// let a = array![1., -4.32, 1.14, 0.32];
152+ /// let var = a.var(1.);
153+ /// assert_abs_diff_eq!(var, 6.7331, epsilon = 1e-4);
154+ /// ```
155+ pub fn var ( & self , ddof : A ) -> A
156+ where
157+ A : Float + FromPrimitive ,
158+ {
159+ let zero = A :: from_usize ( 0 ) . expect ( "Converting 0 to `A` must not fail." ) ;
160+ let n = A :: from_usize ( self . len ( ) ) . expect ( "Converting length to `A` must not fail." ) ;
161+ assert ! (
162+ !( ddof < zero || ddof > n) ,
163+ "`ddof` must not be less than zero or greater than the length of \
164+ the axis",
165+ ) ;
166+ let dof = n - ddof;
167+ let mut mean = A :: zero ( ) ;
168+ let mut sum_sq = A :: zero ( ) ;
169+ for ( i, & x) in self . into_iter ( ) . enumerate ( ) {
170+ let count = A :: from_usize ( i + 1 ) . expect ( "Converting index to `A` must not fail." ) ;
171+ let delta = x - mean;
172+ mean = mean + delta / count;
173+ sum_sq = ( x - mean) . mul_add ( delta, sum_sq) ;
174+ }
175+ sum_sq / dof
176+ }
177+
178+ /// Return standard deviation of elements in the array.
179+ ///
180+ /// The standard deviation is computed from the variance using
181+ /// the [Welford one-pass algorithm](https://www.jstor.org/stable/1266577).
182+ ///
183+ /// The parameter `ddof` specifies the "delta degrees of freedom". For
184+ /// example, to calculate the population standard deviation, use `ddof = 0`,
185+ /// or to calculate the sample standard deviation, use `ddof = 1`.
186+ ///
187+ /// The standard deviation is defined as:
188+ ///
189+ /// ```text
190+ /// ⎛ 1 n ⎞
191+ /// stddev = sqrt ⎜ ―――――――― ∑ (xᵢ - x̅)²⎟
192+ /// ⎝ n - ddof i=1 ⎠
193+ /// ```
194+ ///
195+ /// where
196+ ///
197+ /// ```text
198+ /// 1 n
199+ /// x̅ = ― ∑ xᵢ
200+ /// n i=1
201+ /// ```
202+ ///
203+ /// and `n` is the length of the array.
204+ ///
205+ /// **Panics** if `ddof` is less than zero or greater than `n`
206+ ///
207+ /// # Example
208+ ///
209+ /// ```
210+ /// use ndarray::array;
211+ /// use approx::assert_abs_diff_eq;
212+ ///
213+ /// let a = array![1., -4.32, 1.14, 0.32];
214+ /// let stddev = a.std(1.);
215+ /// assert_abs_diff_eq!(stddev, 2.59483, epsilon = 1e-4);
216+ /// ```
217+ pub fn std ( & self , ddof : A ) -> A
218+ where
219+ A : Float + FromPrimitive ,
220+ {
221+ self . var ( ddof) . sqrt ( )
222+ }
223+
114224 /// Return sum along `axis`.
115225 ///
116226 /// ```
0 commit comments