在statsmodels中捕获高多重共线性

29 投票
2 回答
32324 浏览
提问于 2025-04-19 22:22

假设我在statsmodels中建立了一个模型。

mod = smf.ols('dependent ~ first_category + second_category + other', data=df).fit()

当我运行 mod.summary() 时,可能会看到以下内容:

Warnings:
[1] The condition number is large, 1.59e+05. This might indicate that there are
strong multicollinearity or other numerical problems.

有时候,警告信息会有所不同(比如,基于设计矩阵的特征值)。我该如何在一个变量中捕捉到高多重共线性的情况?这个警告信息是否存储在模型对象的某个地方?

另外,我在哪里可以找到 summary() 中各个字段的描述呢?

2 个回答

5

根据一个关于R语言的类似问题,有一些其他的选项可能对大家有帮助。我在寻找一个能反映多重共线性(也就是变量之间的相关性)的单一数字,这些选项包括相关矩阵的行列式和条件数。

根据R语言的一个回答,相关矩阵的行列式会“从0(完美共线性)到1(没有共线性)”变化。我觉得这个范围很有用。

行列式的示例翻译:

import numpy as np
import pandas as pd

# Create a sample random dataframe
np.random.seed(321)
x1 = np.random.rand(100)
x2 = np.random.rand(100)
x3 = np.random.rand(100)
df = pd.DataFrame({'x1': x1, 'x2': x2, 'x3': x3})

# Now create a dataframe with multicollinearity
multicollinear_df = df.copy()
multicollinear_df['x3'] = multicollinear_df['x1'] + multicollinear_df['x2']

# Compute both correlation matrices
corr = np.corrcoef(df, rowvar=0)
multicollinear_corr = np.corrcoef(multicollinear_df, rowvar=0)

# Compare the determinants
print np.linalg.det(corr) . # 0.988532159861
print np.linalg.det(multicollinear_corr) . # 2.97779797328e-16

同样,协方差矩阵的条件数在完美线性依赖时会接近无穷大。

print np.linalg.cond(corr) . # 1.23116253259
print np.linalg.cond(multicollinear_corr) . # 6.19985218873e+15
57

你可以通过检查相关矩阵特征值来发现高多重共线性。如果特征值非常小,就说明数据之间存在共线性,而对应的特征向量则显示了哪些变量是共线的。

如果数据中没有共线性,你会发现所有的特征值都不会接近零:

>>> xs = np.random.randn(100, 5)      # independent variables
>>> corr = np.corrcoef(xs, rowvar=0)  # correlation matrix
>>> w, v = np.linalg.eig(corr)        # eigen values & eigen vectors
>>> w
array([ 1.256 ,  1.1937,  0.7273,  0.9516,  0.8714])

但是,如果比如说x[4] - 2 * x[0] - 3 * x[2] = 0,那么

>>> noise = np.random.randn(100)                      # white noise
>>> xs[:,4] = 2 * xs[:,0] + 3 * xs[:,2] + .5 * noise  # collinearity
>>> corr = np.corrcoef(xs, rowvar=0)
>>> w, v = np.linalg.eig(corr)
>>> w
array([ 0.0083,  1.9569,  1.1687,  0.8681,  0.9981])

其中一个特征值(这里是第一个特征值)就会接近零。对应的特征向量是:

>>> v[:,0]
array([-0.4077,  0.0059, -0.5886,  0.0018,  0.6981])

忽略几乎为零的系数,上面的意思基本上是说x[0]x[2]x[4]是共线的(这也是预期的结果)。如果你对xs的值进行标准化,并乘以这个特征向量,结果会接近零,并且方差很小:

>>> std_xs = (xs - xs.mean(axis=0)) / xs.std(axis=0)  # standardized values
>>> ys = std_xs.dot(v[:,0])
>>> ys.mean(), ys.var()
(0, 0.0083)

注意,ys.var()基本上就是那个接近零的特征值。

所以,要捕捉到高多重共线性,就要查看相关矩阵的特征值。

撰写回答