1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
use crateOlsFit;
/// Variance Inflation Factor for each predictor.
///
/// `VIFⱼ = 1 / (1 − R²ⱼ)`, where `R²ⱼ` is the coefficient of determination from
/// regressing predictor `j` on **all the other predictors** (reusing the fit's
/// own OLS machinery — the diagnostic is computed with the same tool it
/// diagnoses).
///
/// # Return layout
///
/// The returned vector is aligned to the design-matrix columns: entry `j` is the
/// VIF of column `j`. The **intercept column's entry is [`f64::NAN`]** — VIF is
/// undefined for the constant term — so callers can index straight back into the
/// design without an off-by-one. A perfectly collinear predictor yields
/// [`f64::INFINITY`] rather than a silent `NaN`.
///
/// VIF assumes the model contains an intercept (the standard definition); on an
/// intercept-free fit the auxiliary regressions are still computed but the
/// values follow the through-the-origin convention.
///
/// # Example
///
/// ```
/// use ndarray::array;
/// use regression_diagnostics::{OlsFit, multicollinearity::vif};
///
/// // x2 is nearly 2*x1: strong collinearity, so both get a large VIF.
/// let x = array![
/// [1.0, 1.0, 2.01],
/// [1.0, 2.0, 3.99],
/// [1.0, 3.0, 6.02],
/// [1.0, 4.0, 7.98],
/// [1.0, 5.0, 10.01],
/// ];
/// let y = array![1.0, 2.1, 2.9, 4.2, 5.0];
/// let fit = OlsFit::new(x, y).unwrap();
/// let v = vif(&fit);
/// assert!(v[0].is_nan()); // intercept
/// assert!(v[1] > 5.0 && v[2] > 5.0);
/// ```