Python:如何按组运行多元单变量回归

Python:如何按组运行多元单变量回归,python,pandas,Python,Pandas,假设我有一个DataFrame,其中有一列y变量和多列x变量。我希望能够运行yvsx1,yvsx2,…,等等的多个单变量回归,并将预测存储回数据框。我还需要通过一个组变量来实现这一点 import statsmodels.api as sm import pandas as pd df = pd.DataFrame({ 'y': np.random.randn(20), 'x1': np.random.randn(20), 'x2': np.random.randn(20),

假设我有一个
DataFrame
,其中有一列
y
变量和多列
x
变量。我希望能够运行
y
vs
x1
y
vs
x2
,…,等等的多个单变量回归,并将预测存储回
数据框
。我还需要通过一个组变量来实现这一点

import statsmodels.api as sm
import pandas as pd

df = pd.DataFrame({
  'y': np.random.randn(20),
  'x1': np.random.randn(20), 
  'x2': np.random.randn(20),
  'grp': ['a', 'b'] * 10})

def ols_res(x, y):
    return sm.OLS(y, x).fit().predict()

df.groupby('grp').apply(ols_res) # This does not work

上面的代码显然不起作用。我不清楚如何在使
apply
遍历
x
列(
x1
x2
,…)的同时正确地将固定的
y
传递给函数。我怀疑可能有一个非常聪明的单线解决方案可以做到这一点。有什么想法吗?

传递给
apply
的函数必须将
pandas.DataFrame
作为第一个参数。您可以将其他关键字或位置参数传递给
apply
,这些参数将传递给applied函数。因此,您的示例只需稍加修改即可工作。将
ols\u res
更改为

def ols_res(df, xcols,  ycol):
    return sm.OLS(df[ycol], df[xcols]).fit().predict()
然后,您可以像这样使用
groupby
apply

df.groupby('grp').apply(ols_res, xcols=['x1', 'x2'], ycol='y')

编辑

上述代码不运行多个单变量回归。相反,它对每组进行一次多元回归。不过,只要(再)稍加修改,它就可以了

def ols_res(df, xcols,  ycol):
    return pd.DataFrame({xcol : sm.OLS(df[ycol], df[xcol]).fit().predict() for xcol in xcols})
编辑2

尽管上述解决方案可行,但我认为下面的方法更为简单

import statsmodels.api as sm
import pandas as pd
import numpy as np

df = pd.DataFrame({
  'y': np.random.randn(20),
  'x1': np.random.randn(20), 
  'x2': np.random.randn(20),
  'grp': ['a', 'b'] * 10})

def ols_res(x, y):
    return pd.Series(sm.OLS(y, x).fit().predict())

df.groupby('grp').apply(lambda x : x[['x1', 'x2']].apply(ols_res, y=x['y']))

出于某种原因,如果我像最初一样定义
ols_res()
,那么结果的
DataFrame
在索引中没有组标签。

事实上,我相信这会运行一个多元回归,而不是在列中循环并运行多个单变量回归。很抱歉,我本应该更仔细地阅读这个问题。请看我的编辑。
import statsmodels.api as sm
import pandas as pd
import numpy as np

df = pd.DataFrame({
  'y': np.random.randn(20),
  'x1': np.random.randn(20), 
  'x2': np.random.randn(20),
  'grp': ['a', 'b'] * 10})

def ols_res(x, y):
    return pd.Series(sm.OLS(y, x).fit().predict())

df.groupby('grp').apply(lambda x : x[['x1', 'x2']].apply(ols_res, y=x['y']))