Skip to content

Variance inflation factors #517

Description

@poroc300

I'd like to propose adding a function to calculate Variance Inflation Factors (VIFs) for assessing multicollinearity among predictor variables. While statsmodels provides this functionality, the current implementation requires unnecessary boilerplate (in my opinion) to extract VIF values across all predictors:

from statsmodels.stats.outliers_influence import variance_inflation_factor

vif_ratios = []
for idx in range(df_num.shape[1]):
   vif_ratios.append(variance_inflation_factor(arr, idx))

In my view, the main limitations of this approach are:

  1. Column name mapping - since most data analysis workflows use pandas DataFrames, additional code is needed to associate VIF values with their corresponding column names.
  2. Missing data - the function does not handle missing values natively and raises a MissingDataError if any are present.
  3. Categorical columns - categorical variables are not handled natively and must be excluded manually before calling the function.

I propose a wrapper function with the following behaviour:

  1. Accepts both pandas DataFrames and numpy arrays as input.
  2. Automatically removes rows containing missing values.
  3. Discards categorical columns when the input is a pandas DataFrame.
  4. Returns a pandas DataFrame with VIF values per column (when the input is a DataFrame), or a numpy array of VIF values in the original column order (when the input is an array).
  5. Optionally, accepts a threshold parameter to flag column names or indices where the VIF exceeds a user-defined value.

In my private repository, I've implemented previously a function that does some of the above (the below is just for demonstration, it would require to be expanded in terms of functionality):

def vif(df):
    """
    Compute Variance Inflation Factor (VIF) for each numeric variable. Low values
    indicate low multicollinearity.

    Parameters
    ----------
    df : DataFrame
        Input DataFrame containing the variables to assess. Non-numeric columns
        are ignored automatically and rows with any NaN values and constante values
        are dropped before computation.

    Returns
    -------
    DataFrame
        Single-row DataFrame with the VIF for each numerical variable.

    """
    # get numeric columns, remove columns with constant and nan values
    df_num = df.select_dtypes("number").copy()
    df_num = df_num.dropna(axis=0, how="any")
    df_num = df_num.loc[:, df_num.nunique() > 1]
    if df_num.empty:
        raise ValueError("preprocessing made the input DataFrame empty")

    # estimate VIF for each variable
    vif_ratios = []
    for idx in range(df_num.shape[1]):
        vif_ratios.append(variance_inflation_factor(arr, idx))

    # convert vif_ratios to DataFrame
    return pd.DataFrame([vif_ratios], columns=df_num.columns, index=["VIF"])

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions