OLS回归:Scikit与Statsmodels之间的区别?

31
简短版本: 我在处理一些数据时使用了scikit的LinearRegression,但我习惯于使用p值,所以将数据放入statsmodels的OLS中。虽然R^2大致相同,但变量系数差别很大。这让我感到担忧,因为最可能的问题是我犯了一个错误,现在我对两个输出都不太有信心(因为可能我已经错误地建立了一个模型,但不知道哪一个)。 更长版本: 因为我不知道问题出在哪里,也不确定应该包含哪些细节,包含所有信息可能太多了。我也不确定是否应该包含代码或数据。
我认为scikit的LR和statsmodels的OLS都应该在进行OLS,据我所知,OLS就是OLS,因此结果应该是相同的。
对于scikit的LR,无论我设置normalize=True还是False,结果(在统计上)都是相同的,这让我感到有些奇怪。
对于statsmodels OLS,我使用sklearn的StandardScaler来规范化数据。我添加了一列1,以包含截距(因为scikit的输出包括一个截距)。更多信息请参见:http://statsmodels.sourceforge.net/devel/examples/generated/example_ols.html (添加这一列并没有明显改变变量系数,而且截距非常接近零)。由于StandardScaler不喜欢我的整数不是浮点数,所以我尝试了这个:https://github.com/scikit-learn/scikit-learn/issues/1709。这样可以消除警告,但结果完全相同。
虽然我在sklearn方法中使用了5倍交叉验证(每次测试和训练数据的R ^ 2都是一致的),但对于statsmodels方法,我只是将所有数据都放在一起。
sklearn和statsmodels的R ^ 2分别约为0.41(这对社会科学来说很好)。这可能是一个好兆头,也可能只是巧合。
这份数据是关于魔兽世界中角色头像的观察数据(来源于 http://mmnet.iis.sinica.edu.tw/dl/wowah/),我对其进行了处理,使其变成了每周一次并添加了一些不同的特征。最初这是一项数据科学课程的项目。
自变量包括每周的观察次数(整数)、角色等级(整数)、是否在公会中(布尔值)、上线时间(平日白天、平日晚上、平日深夜、周末同样有三个布尔值)、角色职业的虚拟变量(当时魔兽世界只有8个职业,因此有7个虚拟变量,原始字符串分类变量被删除)以及其他变量。
因变量是每个角色在那周内获得的等级数(整数)。
有趣的是,在统计模型和sklearn中,某些类似变量的相对顺序是保持一致的。因此,“上线时间”的排名顺序是相同的,尽管载荷非常不同,而角色职业虚拟变量的排名顺序也是相同的,尽管载荷再次非常不同。
我认为这个问题类似于这个问题: Python statsmodels OLS和R的lm的区别 我对Python和统计学足够熟练,但不足以弄清楚这样的问题。我尝试阅读sklearn文档和statsmodels文档,但如果答案就在那里盯着我,我也不理解它。
我想知道:
1.哪个输出可能是准确的?(如果我错过了一个kwarg,那么它们两个都可能是准确的。) 2.如果我犯了一个错误,那么是什么错误,如何修复? 3.我是否可以在没有询问这里的情况下弄清楚这一点,如果可以,那么如何?
我知道这个问题有一些相当模糊的部分(没有代码,没有数据,没有输出),但我认为它更多地涉及两个软件包的一般过程。当然,一个似乎更注重统计学,而另一个似乎更注重机器学习,但它们都是OLS,所以我不明白为什么输出不同。

我甚至尝试了一些其他的OLS调用来进行三角剖分,其中一个R^2值明显较低,另一个循环了五分钟后我强制停止了它,还有一个崩溃了。

谢谢!


1
你能否在一个小输入上复制你的问题?如果可以,请在这里发布输入和代码。 - Akavall
3
只是一种可能性:你有检查过自变量矩阵的秩吗?它可能是奇异的。但如果没有更明确的示例,很难确定造成差异的原因。 - Josef
啊,好的——我明天会看看能否通过一些东西来改进这个问题(美国东部时间)。我担心我可能无法提出一个具体情况下的问题。 - Nat Poor
2
一种可能性是生成一些随机数据并使用它运行您的程序,看看是否得到相同的差异。这样您就可以看出问题是数据本身的问题还是statsmodels与scikit-learn的用法问题。 - Josef
哦,这也是个好主意!顺便说一下,我不确定“解释变量矩阵的等级”是什么意思。我的统计知识都有些陈旧生锈了,而且机器学习方面似乎使用不同的术语,方法也有所不同,所以有时我在术语上感到困惑。 - Nat Poor
@NatPoor:如果矩阵是奇异的,那就说明你的一些自变量存在相关性,这可能解释了为什么你得到了两组不同的系数。 - naught101
3个回答

42

看起来你没有在两个过程中都使用相同的回归自变量矩阵X(但请参见下文)。这里是一个示例,向你展示如何使用sklearn和statsmodels产生相同的结果所需的选项。

import numpy as np
import statsmodels.api as sm
from sklearn.linear_model import LinearRegression

# Generate artificial data (2 regressors + constant)
nobs = 100 
X = np.random.random((nobs, 2)) 
X = sm.add_constant(X)
beta = [1, .1, .5] 
e = np.random.random(nobs)
y = np.dot(X, beta) + e 

# Fit regression model
sm.OLS(y, X).fit().params
>> array([ 1.4507724 ,  0.08612654,  0.60129898])

LinearRegression(fit_intercept=False).fit(X, y).coef_
>> array([ 1.4507724 ,  0.08612654,  0.60129898])

正如评论者建议的那样,即使您为两个程序都提供了相同的X,X可能没有完整的列秩,它们可能会在幕后采取(不同的)操作以使OLS计算得以进行(即删除不同的列)。

我建议您使用pandaspatsy来处理这个问题:

import pandas as pd
from patsy import dmatrices

dat = pd.read_csv('wow.csv')
y, X = dmatrices('levels ~ week + character + guild', data=dat)

或者,作为替代方案,使用 statsmodels 公式接口:

import statsmodels.formula.api as smf
dat = pd.read_csv('wow.csv')
mod = smf.ols('levels ~ week + character + guild', data=dat).fit()

编辑:这个例子可能会有用:http://statsmodels.sourceforge.net/devel/example_formulas.html


1
太棒了,谢谢。让我……好的,我会发布我构建的函数,然后回来尝试应用这些想法。我确实理解“不要喂相同的矩阵”的含义,#胜利……我希望我在那个层面上没有搞砸,但当然也有可能。 - Nat Poor
实际上,在粘贴我的两个不同函数调用的75行代码之前,我会在这里尝试代码示例。如果答案已经在这里,我不想浪费人们的时间阅读代码。(当然,如果这段代码有效,并且我无法确定出错的地方,那么我可能最终会发布它,但是一步一步来。)今天应该能够处理它(也许稍后)。谢谢大家! - Nat Poor
1
好的!那段代码确实让我在两个库中对于同一数据得到了相同的结果!太棒了!然而,这些数字与我之前得到的完全不同 -- 幸好我在这里问了!现在我有了一个良好的起点和一些我认为可以信任的数字,我将努力弄清楚其中的问题。 (我有点失望,我竟然做了两个回归,但它们完全走样了...也许我应该坚持使用SPSS和R....绝不放弃!) - Nat Poor
1
总结:我使用标准化(StandardScaler)得到了SM,并且使用CV(和SS)得到了SK,结果大致相同。问题似乎是我必须将整数转换为numpy浮点数(此时我无法回忆起原因),这对SM和SK(没有CV)版本都有效(有效意味着它们给出了相同的结果,我有信心这些结果是准确的)。当我将CV添加到使用numpy浮点数的工作SK函数中时,R ^ 2降至-5000。因此,某些东西(?可能很明显?)在CV和np浮点数之间不起作用。我将np浮点数拿出来就可以了! - Nat Poor
1
嗨,我只是想在这里补充一下,在sklearn方面,它不使用OLS方法进行线性回归。由于sklearn来自数据挖掘/机器学习领域,他们喜欢使用最陡梯度下降算法。这是一种对初始条件等敏感的数值方法,而OLS是一种解析闭合形式方法,因此应该期望存在差异。因此,statsmodels来自经典统计领域,因此他们会使用OLS技术。因此,这两个不同库中的两个线性回归之间存在差异。 - Palu

1
如果您使用statsmodels,我强烈建议使用statsmodels公式接口。使用statsmodels公式接口进行OLS将得到与sklearn.linear_model.LinearRegression、R、SAS或Excel相同的结果。
smod = smf.ols(formula ='y~ x', data=df)
result = smod.fit()
print(result.summary())

当有疑问时,请尝试:

  1. 阅读源代码
  2. 尝试使用其他语言进行基准测试,或者
  3. 从头开始尝试OLS,这是基本线性代数。

1
statsmodelsscikit-learn 更加友好。我已经对后者所需的难以理解的输入和输出数组/矩阵格式(大多数情况下失败的)解密感到厌烦了。 - WestCoastProjects

-1

我想在这里补充一下,就sklearn而言,它在底层并不使用OLS方法进行线性回归。由于sklearn来自数据挖掘/机器学习领域,他们喜欢使用最速下降梯度算法。这是一种对初始条件等敏感的数值方法,而OLS则是一种解析闭合形式的方法,因此应该预期会有差异。因此,statsmodels来自经典统计学领域,因此他们会使用OLS技术。因此,这两个不同库中的两个线性回归之间存在差异。


3
这个答案是错误的。sklearn中的LinearRegression使用OLS方法。只需查看源代码:https://github.com/scikit-learn/scikit-learn/blob/1495f6924/sklearn/linear_model/base.py#L367 - Sarah
4
嗨,回到我回答过的地方,我联系了sklearn的人,他们告诉我他们没有OLS实现,只有SDG算法。但是我没有尝试查看git代码库。所以谢谢你发现这个Sarah。那么要么回复我的人不知道,要么他们最近实现了OLS。无论哪种方式,感谢你指出这一点,Sarah,非常感激。 - Palu
谢谢Palu的回复和美好的评论 :) - Sarah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接