Skip to main content

rhai_sci/
statistics.rs

1use rhai::plugin::*;
2
3fn extremum_index<T: PartialOrd>(
4    values: &[T],
5    direction: std::cmp::Ordering,
6) -> Result<rhai::Dynamic, Box<rhai::EvalAltResult>> {
7    let mut best = 0;
8    for (index, value) in values.iter().enumerate() {
9        let ordering = value.partial_cmp(&values[best]).ok_or_else(|| {
10            rhai::EvalAltResult::ErrorArithmetic(
11                "Cannot compare NaN values".into(),
12                rhai::Position::NONE,
13            )
14        })?;
15        if ordering == direction {
16            best = index;
17        }
18    }
19    Ok(rhai::Dynamic::from_int(best as rhai::INT))
20}
21
22#[export_module]
23pub mod stats {
24    use super::extremum_index;
25    #[cfg(feature = "nalgebra")]
26    use crate::matrix::RhaiMatrix;
27    use crate::{
28        array_to_vec_float, array_to_vec_int, if_list_convert_to_vec_float_and_do,
29        if_list_do_int_or_do_float,
30    };
31    #[cfg(feature = "nalgebra")]
32    use rhai::Map;
33    use rhai::{Array, Dynamic, EvalAltResult, Position, FLOAT, INT};
34
35    #[cfg(feature = "nalgebra")]
36    use std::collections::BTreeMap;
37    use std::collections::HashMap;
38
39    /// Return the highest value from a pair of numbers. Fails if the numbers are anything other
40    /// than INT or FLOAT.
41    /// ```typescript
42    /// let the_higher_number = max(2, 3);
43    /// assert_eq(the_higher_number, 3);
44    /// ```
45    /// ```typescript
46    /// let the_higher_number = max(2.0, 3.0);
47    /// assert_eq(the_higher_number, 3.0);
48    /// ```
49    #[rhai_fn(name = "max", return_raw)]
50    pub fn gen_max(a: Dynamic, b: Dynamic) -> Result<Dynamic, Box<EvalAltResult>> {
51        array_max(&mut vec![a, b])
52    }
53
54    /// Return the highest value from an array. Fails if the input is not an array, or if
55    /// it is an array with elements other than INT or FLOAT.
56    /// ```typescript
57    /// let the_highest_number = max([2, 3, 4, 5]);
58    /// assert_eq(the_highest_number, 5);
59    /// ```
60    /// ```typescript
61    /// let the_highest_number = max([2, 3.0, 4.12, 5]);
62    /// assert_eq(the_highest_number, 5.0);
63    /// ```
64    #[rhai_fn(name = "max", return_raw)]
65    pub fn array_max(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
66        if_list_do_int_or_do_float(
67            arr,
68            |arr: &mut Array| {
69                let mut y = array_to_vec_int(arr);
70                y.sort();
71                Ok(Dynamic::from(y[y.len() - 1]))
72            },
73            |arr: &mut Array| {
74                let mut y = array_to_vec_float(arr);
75                y.sort_by(|a, b| a.partial_cmp(b).unwrap());
76                Ok(Dynamic::from(y[y.len() - 1]))
77            },
78        )
79    }
80
81    /// Return the lowest value from a pair of numbers. Fails if the numbers are anything other
82    /// than INT or FLOAT.
83    ///
84    /// ```typescript
85    /// let the_lower_number = min(2, 3);
86    /// assert_eq(the_lower_number, 2);
87    /// ```
88    /// ```typescript
89    /// let the_lower_number = min(2.0, 3.0);
90    /// assert_eq(the_lower_number, 2.0);
91    /// ```
92    #[rhai_fn(name = "min", return_raw)]
93    pub fn gen_min(a: Dynamic, b: Dynamic) -> Result<Dynamic, Box<EvalAltResult>> {
94        array_min(&mut vec![a, b])
95    }
96
97    /// Return the lowest value from an array. Fails if the input is not an array, or if
98    /// it is an array with elements other than INT or FLOAT.
99    ///
100    /// ```typescript
101    /// let the_lowest_number = min([2, 3, 4, 5]);
102    /// assert_eq(the_lowest_number, 2);
103    /// ```
104    /// ```typescript
105    /// let the_lowest_number = min([2, 3.0, 4.12, 5]);
106    /// assert_eq(the_lowest_number, 2.0);
107    /// ```
108    #[rhai_fn(name = "min", return_raw, pure)]
109    pub fn array_min(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
110        if_list_do_int_or_do_float(
111            arr,
112            |arr: &mut Array| {
113                let mut y = array_to_vec_int(arr);
114                y.sort();
115                Ok(Dynamic::from(y[0]))
116            },
117            |arr: &mut Array| {
118                let mut y = array_to_vec_float(arr);
119                y.sort_by(|a, b| a.partial_cmp(b).unwrap());
120                Ok(Dynamic::from(y[0]))
121            },
122        )
123    }
124
125    /// Return the highest value from an array. Fails if the input is not an array, or if
126    /// it is an array with elements other than INT or FLOAT.
127    /// ```typescript
128    /// let high_and_low = bounds([2, 3, 4, 5]);
129    /// assert_eq(high_and_low, [2, 5]);
130    /// ```
131    #[rhai_fn(name = "bounds", return_raw)]
132    pub fn bounds(arr: &mut Array) -> Result<Array, Box<EvalAltResult>> {
133        match (array_min(arr), array_max(arr)) {
134            (Ok(low), Ok(high)) => Ok(vec![low, high]),
135            (Ok(_), Err(high)) => Err(high),
136            (Err(low), Ok(_)) => Err(low),
137            (Err(low), Err(_)) => Err(low),
138        }
139    }
140
141    /// Returns the `k` highest values from an array. Fails if the input is not an array, or if
142    /// it is an array with elements other than INT or FLOAT.
143    /// ```typescript
144    /// let data = [32, 15, -7, 10, 1000, 41, 42];
145    /// let mk = maxk(data, 3);
146    /// assert_eq(mk, [41, 42, 1000]);
147    /// ```
148    /// ```typescript
149    /// let data = [32, 15, -7.0, 10, 1000, 41.0, 42];
150    /// let mk = maxk(data, 3);
151    /// assert_eq(mk, [41.0, 42.0, 1000.0]);
152    /// ```
153    #[rhai_fn(name = "maxk", return_raw, pure)]
154    pub fn maxk(arr: &mut Array, k: INT) -> Result<Array, Box<EvalAltResult>> {
155        if_list_do_int_or_do_float(
156            arr,
157            |arr: &mut Array| {
158                let mut y = array_to_vec_int(arr);
159                y.sort();
160                let r = (y.len() - (k as usize))..(y.len());
161                let mut v = Array::new();
162                for idx in r {
163                    v.push(Dynamic::from(y[idx]));
164                }
165                Ok(v)
166            },
167            |arr: &mut Array| {
168                let mut y = array_to_vec_float(arr);
169                y.sort_by(|a, b| a.partial_cmp(b).unwrap());
170                let r = (y.len() - (k as usize))..(y.len());
171                let mut v = Array::new();
172                for idx in r {
173                    v.push(Dynamic::from(y[idx]));
174                }
175                Ok(v)
176            },
177        )
178    }
179
180    /// Return the `k` lowest values in an array. Fails if the input is not an array, or if
181    /// it is an array with elements other than INT or FLOAT.
182    /// ```typescript
183    /// let data = [32, 15, -7, 10, 1000, 41, 42];
184    /// let mk = mink(data, 3);
185    /// assert_eq(mk, [-7, 10, 15]);
186    /// ```
187    /// ```typescript
188    /// let data = [32, 15.1223232, -7, 10, 1000.00000, 41, 42];
189    /// let mk = mink(data, 3);
190    /// assert_eq(mk, [-7.0, 10.0, 15.1223232]);
191    /// ```
192    #[rhai_fn(name = "mink", return_raw, pure)]
193    pub fn mink(arr: &mut Array, k: INT) -> Result<Array, Box<EvalAltResult>> {
194        if_list_do_int_or_do_float(
195            arr,
196            |arr| {
197                let mut y = array_to_vec_int(arr);
198                y.sort();
199                let r = (0 as usize)..(k as usize);
200                let mut v = Array::new();
201                for idx in r {
202                    v.push(Dynamic::from(y[idx]));
203                }
204                Ok(v)
205            },
206            |arr| {
207                let mut y = array_to_vec_float(arr);
208                y.sort_by(|a, b| a.partial_cmp(b).unwrap());
209                let r = (0 as usize)..(k as usize);
210                let mut v = Array::new();
211                for idx in r {
212                    v.push(Dynamic::from(y[idx]));
213                }
214                Ok(v)
215            },
216        )
217    }
218
219    /// Sum an array. Fails if the input is not an array, or if
220    /// it is an array with elements other than INT or FLOAT.
221    /// ```typescript
222    /// let data = [1, 2, 3];
223    /// let m = sum(data);
224    /// assert_eq(m, 6);
225    /// ```
226    /// ```typescript
227    /// let data = [1, 2.0, 3];
228    /// let m = sum(data);
229    /// assert_eq(m, 6.0);
230    /// ```
231    #[rhai_fn(name = "sum", return_raw, pure)]
232    pub fn sum(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
233        if arr.is_empty() {
234            return Ok(Dynamic::from_int(0));
235        }
236        if_list_do_int_or_do_float(
237            arr,
238            |arr| {
239                let y = array_to_vec_int(arr);
240                Ok(Dynamic::from_int(y.iter().sum()))
241            },
242            |arr| {
243                let y = array_to_vec_float(arr);
244                Ok(Dynamic::from_float(y.iter().sum()))
245            },
246        )
247    }
248
249    /// Return the average of an array. Fails if the input is not an array, or if
250    /// it is an array with elements other than INT or FLOAT.
251    /// ```typescript
252    /// let data = [1, 2, 3];
253    /// let m = mean(data);
254    /// assert_eq(m, 2.0);
255    /// ```
256    #[rhai_fn(name = "mean", return_raw, pure)]
257    pub fn mean(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
258        if_list_do_int_or_do_float(
259            arr,
260            |arr: &mut Array| {
261                sum(arr)
262                    .map(|s| Dynamic::from_float(s.as_int().unwrap() as FLOAT / arr.len() as FLOAT))
263            },
264            |arr: &mut Array| {
265                sum(arr).map(|s| Dynamic::from_float(s.as_float().unwrap() / arr.len() as FLOAT))
266            },
267        )
268    }
269
270    /// Return the index of the largest array element. Fails if the input is not an array, or if
271    /// it is an array with elements other than INT or FLOAT.
272    /// ```typescript
273    /// let data = [1, 2, 3];
274    /// let m = argmax(data);
275    /// assert_eq(m, 2);
276    /// ```
277    #[rhai_fn(name = "argmax", return_raw, pure)]
278    pub fn argmax(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
279        if_list_do_int_or_do_float(
280            arr,
281            |values| extremum_index(&array_to_vec_int(values), std::cmp::Ordering::Greater),
282            |values| extremum_index(&array_to_vec_float(values), std::cmp::Ordering::Greater),
283        )
284    }
285
286    /// Return the index of the smallest array element. Fails if the input is not an array, or if
287    /// it is an array with elements other than INT or FLOAT.
288    /// ```typescript
289    /// let data = [1, 2, 3];
290    /// let m = argmin(data);
291    /// assert_eq(m, 0);
292    /// ```
293    #[rhai_fn(name = "argmin", return_raw, pure)]
294    pub fn argmin(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
295        if_list_do_int_or_do_float(
296            arr,
297            |values| extremum_index(&array_to_vec_int(values), std::cmp::Ordering::Less),
298            |values| extremum_index(&array_to_vec_float(values), std::cmp::Ordering::Less),
299        )
300    }
301
302    /// Compute the product of an array. Fails if the input is not an array, or if
303    /// it is an array with elements other than INT or FLOAT.
304    /// ```typescript
305    /// let data = [1, 2, 3];
306    /// let m = prod(data);
307    /// assert_eq(m, 6);
308    /// ```
309    /// ```typescript
310    /// let data = [3, 6, 10];
311    /// let m = prod(data);
312    /// assert_eq(m, 180);
313    /// ```
314    #[rhai_fn(name = "prod", return_raw, pure)]
315    pub fn prod(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
316        if arr.is_empty() {
317            return Ok(Dynamic::from_int(1));
318        }
319        if_list_do_int_or_do_float(
320            arr,
321            |arr| {
322                let mut p = 1 as INT;
323                for el in arr {
324                    p *= el.as_int().unwrap()
325                }
326                Ok(Dynamic::from_int(p))
327            },
328            |arr| {
329                let mut p = 1.0 as FLOAT;
330                for el in arr {
331                    p *= el.as_float().unwrap()
332                }
333                Ok(Dynamic::from_float(p))
334            },
335        )
336    }
337
338    /// Returns the variance of a 1-D array.
339    /// ```typescript
340    /// let data = [1, 2, 3];
341    /// let v = variance(data);
342    /// assert_eq(v, 1.0);
343    /// ```
344    #[rhai_fn(name = "variance", return_raw, pure)]
345    pub fn variance(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
346        let m = mean(arr).map(|med| med.as_float().unwrap())?;
347
348        if_list_convert_to_vec_float_and_do(arr, |x| {
349            let mut sum = 0.0 as FLOAT;
350
351            for v in &x {
352                sum += (v - m).powi(2)
353            }
354            let d = sum / (x.len() as FLOAT - 1.0);
355            Ok(Dynamic::from_float(d))
356        })
357    }
358
359    /// Returns the standard deviation of a 1-D array.
360    /// ```typescript
361    /// let data = [1, 2, 3];
362    /// let v = std(data);
363    /// assert_eq(v, 1.0);
364    /// ```
365    #[rhai_fn(name = "std", return_raw, pure)]
366    pub fn std(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
367        variance(arr).map(|v| Dynamic::from_float(v.as_float().unwrap().sqrt()))
368    }
369
370    /// Returns the variance of a 1-D array.
371    /// ```typescript
372    /// let data = [1, 2, 3, 4, 5];
373    /// let r = rms(data);
374    /// assert_eq(r, 3.3166247903554);
375    /// ```
376    #[rhai_fn(name = "rms", return_raw, pure)]
377    pub fn rms(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
378        if_list_convert_to_vec_float_and_do(arr, |arr| {
379            let mut sum = 0.0 as FLOAT;
380            for v in &arr {
381                sum += v.powi(2)
382            }
383            let d = sum / (arr.len() as FLOAT);
384            Ok(Dynamic::from_float(d.sqrt()))
385        })
386    }
387
388    /// Returns the variance of a 1-D array.
389    /// ```typescript
390    /// let data = [1, 1, 1, 1, 2, 5, 6, 7, 8];
391    /// let m = median(data);
392    /// assert_eq(m, 2.0);
393    /// ```
394    #[rhai_fn(name = "median", return_raw, pure)]
395    pub fn median(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
396        if_list_convert_to_vec_float_and_do(arr, |mut x| {
397            x.sort_by(|a, b| a.partial_cmp(b).unwrap());
398
399            let med = if x.len() % 2 == 1 {
400                x[(x.len() - 1) / 2]
401            } else {
402                (x[x.len() / 2] + x[x.len() / 2 - 1]) / 2.0
403            };
404
405            Ok(Dynamic::from_float(med))
406        })
407    }
408
409    /// Returns the median absolute deviation of a 1-D array.
410    /// ```typescript
411    /// let data = [1.0, 2.0, 3.0, 3.0, 4.0, 4.0, 4.0, 5.0, 5.5, 6.0, 6.0, 6.5, 7.0, 7.0, 7.5, 8.0, 9.0, 12.0, 52.0, 90.0];
412    /// let m = mad(data);
413    /// assert_eq(m, 2.0);
414    /// ```
415    #[rhai_fn(name = "mad", return_raw, pure)]
416    pub fn mad(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
417        let m = median(arr).map(|med| med.as_float().unwrap())?;
418
419        if_list_convert_to_vec_float_and_do(arr, |x| {
420            let mut dev = vec![];
421            for v in x {
422                dev.push(Dynamic::from_float((v - m).abs()));
423            }
424            median(&mut dev)
425        })
426    }
427
428    /// Returns a given percentile value for a 1-D array of data.
429    ///
430    /// The array must not be empty.
431    ///
432    /// If the percentile value is <= 0 or >= 100, returns the minimum and maximum values of the array respectively.
433    /// ```typescript
434    /// let data = [1, 2, 0, 3, 4];
435    /// let p = prctile(data, 0);
436    /// assert_eq(p, 0.0);
437    /// ```
438    /// ```typescript
439    /// let data = [1, 2, 0, 3, 4];
440    /// let p = prctile(data, 50);
441    /// assert_eq(p, 2.0);
442    /// ```
443    /// ```typescript
444    /// let data = [1, 2, 0, 3, 4];
445    /// let p = prctile(data, 100);
446    /// assert_eq(p, 4.0);
447    /// ```
448    #[rhai_fn(name = "prctile", return_raw, pure)]
449    pub fn prctile(arr: &mut Array, p: Dynamic) -> Result<FLOAT, Box<EvalAltResult>> {
450        if arr.is_empty() {
451            return Err(EvalAltResult::ErrorArithmetic(
452                "Array must not be empty".to_string(),
453                Position::NONE,
454            )
455            .into());
456        }
457        if !p.is_float() && !p.is_int() {
458            return Err(EvalAltResult::ErrorArithmetic(
459                "Percentile value must either be INT or FLOAT".to_string(),
460                Position::NONE,
461            )
462            .into());
463        }
464
465        if_list_convert_to_vec_float_and_do(arr, move |mut float_array| {
466            match float_array.len() {
467                0 => unreachable!(),
468                1 => return Ok(float_array[0]),
469                _ => (),
470            }
471
472            // Sort
473            float_array.sort_by(|a, b| a.partial_cmp(b).unwrap());
474
475            let sorted_array = float_array
476                .iter()
477                .map(|el| Dynamic::from_float(*el))
478                .collect::<Array>();
479
480            let mut x = crate::matrix_functions::linspace(
481                Dynamic::from_int(0),
482                Dynamic::from_int(100),
483                float_array.len() as INT,
484            )?;
485            crate::misc_functions::interp1(&mut x, sorted_array, p.clone())
486        })
487    }
488
489    /// Returns the inter-quartile range for a 1-D array.
490    /// ```typescript
491    /// let data = [1, 1, 1, 1, 1, 1, 1, 5, 6, 9, 9, 9, 9, 9, 9, 9, 9];
492    /// let inter_quartile_range = iqr(data);
493    /// assert_eq(inter_quartile_range, 8.0);
494    /// ```
495    #[rhai_fn(name = "iqr", return_raw, pure)]
496    pub fn iqr(arr: &mut Array) -> Result<FLOAT, Box<EvalAltResult>> {
497        match (
498            prctile(arr, Dynamic::from_int(25)),
499            prctile(arr, Dynamic::from_int(75)),
500        ) {
501            (Ok(low), Ok(high)) => Ok(high - low),
502            (Ok(_), Err(high)) => Err(high),
503            (Err(low), Ok(_)) => Err(low),
504            (Err(low), Err(_)) => Err(low),
505        }
506    }
507
508    /// Returns the mode of a 1-D array.
509    /// ```typescript
510    /// let data = [1, 2, 2, 2, 2, 3];
511    /// let m = mode(data);
512    /// assert_eq(m, 2);
513    /// ```
514    /// ```typescript
515    /// let data = [1.0, 2.0, 2.0, 2.0, 2.0, 3.0];
516    /// let m = mode(data);
517    /// assert_eq(m, 2.0);
518    /// ```
519    #[rhai_fn(name = "mode", return_raw, pure)]
520    pub fn mode(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
521        if_list_do_int_or_do_float(
522            arr,
523            |arr| {
524                let v = array_to_vec_int(arr);
525
526                let mut counts: HashMap<INT, usize> = HashMap::new();
527
528                Ok(Dynamic::from_int(
529                    v.iter()
530                        .copied()
531                        .max_by_key(|&n| {
532                            let count = counts.entry(n).or_insert(0);
533                            *count += 1;
534                            *count
535                        })
536                        .unwrap(),
537                ))
538            },
539            |arr| {
540                let v = array_to_vec_float(arr);
541
542                let mut counts: HashMap<String, usize> = HashMap::new();
543
544                Ok(Dynamic::from_float(
545                    v.iter()
546                        .copied()
547                        .max_by_key(|&n| {
548                            let count = counts.entry(format!("{:?}", n)).or_insert(0);
549                            *count += 1;
550                            *count
551                        })
552                        .unwrap(),
553                ))
554            },
555        )
556    }
557
558    /// Performs ordinary least squares regression with an automatically fitted intercept.
559    /// Rows of `x` are observations; columns are predictors. Do not add a column of ones.
560    /// `y` may be a list, row vector, or column vector with one value per observation.
561    /// `parameters`, `pvalues`, and `standard_errors` describe the predictor columns in order;
562    /// `intercept` is returned separately. Predict with intercept + X * parameters.
563    /// ```typescript
564    /// let x = col([0.0, 1.0, 2.0]);
565    /// let y = [[0.1],
566    ///          [0.8],
567    ///          [2.1]];
568    /// let b = regress(x, y);
569    /// assert_approx_eq(b.intercept, 0.0);
570    /// assert_approx_eq(b.parameters, [1.0]);
571    /// ```
572    #[cfg(feature = "nalgebra")]
573    #[rhai_fn(name = "regress", return_raw, pure)]
574    pub fn regress(x: &mut Array, y: Array) -> Result<Map, Box<EvalAltResult>> {
575        use linregress::{FormulaRegressionBuilder, RegressionDataBuilder};
576        crate::matrix_functions::mat_from_array(x.clone())?;
577        let mut response = crate::matrix::numeric_vector_data(&y)?;
578        if response.len() != x.len() {
579            return Err(EvalAltResult::ErrorArithmetic(
580                "regress expects one response per predictor row".into(),
581                Position::NONE,
582            )
583            .into());
584        }
585        let x_transposed = crate::matrix_functions::transpose(RhaiMatrix::from_array(x.clone()))?;
586        let x_arr = x_transposed.to_array();
587        let mut data: Vec<(String, Vec<f64>)> = vec![];
588        let mut vars = vec![];
589        for (iter, column) in x_arr.iter().enumerate() {
590            let var_name = format!("x_{iter}");
591            vars.push(var_name.clone());
592            data.push((
593                var_name,
594                array_to_vec_float(&mut column.clone().into_array().unwrap()),
595            ));
596        }
597        data.push(("y".to_string(), array_to_vec_float(&mut response)));
598
599        let regress_data = RegressionDataBuilder::new()
600            .build_from(data)
601            .map_err(|e| EvalAltResult::ErrorArithmetic(e.to_string(), Position::NONE))?;
602
603        let model = FormulaRegressionBuilder::new()
604            .data(&regress_data)
605            .data_columns("y", vars)
606            .fit()
607            .map_err(|e| EvalAltResult::ErrorArithmetic(e.to_string(), Position::NONE))?;
608
609        let parameters = Dynamic::from_array(
610            model
611                .iter_parameter_pairs()
612                .map(|x| Dynamic::from_float(x.1))
613                .collect::<Array>(),
614        );
615        let pvalues = Dynamic::from_array(
616            model
617                .iter_p_value_pairs()
618                .map(|x| Dynamic::from_float(x.1))
619                .collect::<Array>(),
620        );
621        let standard_errors = Dynamic::from_array(
622            model
623                .iter_se_pairs()
624                .map(|x| Dynamic::from_float(x.1))
625                .collect::<Array>(),
626        );
627
628        let mut result = BTreeMap::new();
629        result.insert(
630            "intercept".into(),
631            Dynamic::from_float(model.parameters()[0]),
632        );
633        let mut params = smartstring::SmartString::new();
634        params.push_str("parameters");
635        result.insert(params, parameters);
636        let mut pv = smartstring::SmartString::new();
637        pv.push_str("pvalues");
638        result.insert(pv, pvalues);
639        let mut se = smartstring::SmartString::new();
640        se.push_str("standard_errors");
641        result.insert(se, standard_errors);
642        Ok(result)
643    }
644}