在pandas中使用groupby循环多个变量组合

2 投票
1 回答
2545 浏览
提问于 2025-04-17 23:05

我有一些数据,比如:

df = pandas.DataFrame({"X1":[1,2,5]*4, "X2":[1,2,10]*4, 
                       "Y":[2,4,6]*4, "group":["A","B"]*6})

我想为每个组和每个相关变量组合创建一个线性回归斜率系数的表格,类似于:

group  x   y  coef
A      X1  Y  0.97
A      X2  Y  0.85
B      X1  Y  0.73
B      X2  Y  0.81

我试着这样做:

def OLS_slope_coef(df, xcol=0, ycol=1):
  x = df.ix[:,xcol]
  y = df.ix[:,ycol]
  slope, intercept, r, p, stderr = scipy.stats.linregress(x, y)
  return(slope)


s_df = pandas.DataFrame()
for x in ['X1', 'X2']:
    for y in ['Y']:
        s_df.ix[(x, y), 'coef'] = df.groupby('group').apply(OLS_slope_coef, x, y)

但是出现了一个错误:ValueError: Incompatible indexer with Series

有没有什么办法可以做到这一点?我不在乎groupxy这些变量是索引还是数据框的列(反正我会用.reset_index()来重置索引)。

1 个回答

0

问题在于,.apply 返回的是一个包含两个元素的序列(因为有两个组),这两个元素的索引分别是 'A' 和 'B',所以这和 .ix[(x,y), 'coef'] 不兼容。你可以选择这样做:

s_df = pd.DataFrame(index=['A', 'B'])
for x in ['X1', 'X2']:
    for y in ['Y']:
        s_df.loc[:, x + '-coef'] = df.groupby('group').apply(OLS_slope_coef, x, y)

这样会得到:

   X1-coef  X2-coef
A     0.92     0.37
B     0.92     0.37

[2 rows x 2 columns]

或者,在被应用的函数内部进行循环,并返回一个数据框:

import pandas as pd
def ols(df, xcols):
    from itertools import chain
    from scipy.stats import linregress
    fitcols = ['slope', 'intercept', 'rval', 'pval', 'stderr']
    cols = pd.MultiIndex.from_tuples([(var, k) for var in xcols for k in fitcols])
    fit = [linregress(df[xcol], df.Y) for xcol in xcols]
    return pd.DataFrame([list(chain(*fit))], columns=cols)

fit = df.groupby('group').apply(ols, xcols=['X1', 'X2'])
fit.reset_index(level=1, drop=True, inplace=True)

这样会得到:

          X1                                    X2                               
       slope  intercept  rval  pval  stderr  slope  intercept  rval  pval  stderr
group                                                                            
A       0.92       1.54  0.96     0    0.13   0.37        2.4  0.91  0.01    0.08
B       0.92       1.54  0.96     0    0.13   0.37        2.4  0.91  0.01    0.08

[2 rows x 10 columns]

撰写回答