Python Pandas 如何将 groupby 操作结果分配回父数据框中的列?

     2023-02-16     167

关键词:

【中文标题】Python Pandas 如何将 groupby 操作结果分配回父数据框中的列?【英文标题】:Python Pandas How to assign groupby operation results back to columns in parent dataframe? 【发布时间】:2012-08-25 09:45:42 【问题描述】:

我在 IPython 中有以下数据框,其中每一行都是一个股票:

In [261]: bdata
Out[261]:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 21210 entries, 0 to 21209
Data columns:
BloombergTicker      21206  non-null values
Company              21210  non-null values
Country              21210  non-null values
MarketCap            21210  non-null values
PriceReturn          21210  non-null values
SEDOL                21210  non-null values
yearmonth            21210  non-null values
dtypes: float64(2), int64(1), object(4)

我想应用一个 groupby 操作,计算“年月”列中每个日期的所有事物的上限加权平均回报。

这按预期工作:

In [262]: bdata.groupby("yearmonth").apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())
Out[262]:
yearmonth
201204      -0.109444
201205      -0.290546

但是我想将这些值“广播”回原始数据框中的索引,并将它们保存为日期匹配的常量列。

In [263]: dateGrps = bdata.groupby("yearmonth")

In [264]: dateGrps["MarketReturn"] = dateGrps.apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/mnt/bos-devrnd04/usr6/home/espears/ws/Research/Projects/python-util/src/util/<ipython-input-264-4a68c8782426> in <module>()
----> 1 dateGrps["MarketReturn"] = dateGrps.apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())

TypeError: 'DataFrameGroupBy' object does not support item assignment

我意识到这个幼稚的任务不应该奏效。但是,将 groupby 操作的结果分配到父数据帧上的新列中的“正确”Pandas 习语是什么?

最后,我想要一个名为“MarketReturn”的列,而不是所有与 groupby 操作的输出具有匹配日期的索引的重复常量值。

实现此目的的一个技巧如下:

marketRetsByDate  = dateGrps.apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())

bdata["MarketReturn"] = np.repeat(np.NaN, len(bdata))

for elem in marketRetsByDate.index.values:
    bdata["MarketReturn"][bdata["yearmonth"]==elem] = marketRetsByDate.ix[elem]

但这很慢,很糟糕,而且不符合 Python 风格。

【问题讨论】:

您正在分配回您的分组对象,而不是您的原始框架。 我知道这一点,我直接在错误下方这么说,我说:“我意识到这个幼稚的分配不应该起作用。但是分配 groupby 的结果的“正确”Pandas 成语是什么操作到父数据框上的新列?”在 LHS 上使用我的原始数据框进行分配也不起作用,甚至比在 GroupBy 对象级别添加列更不直观。 【参考方案1】:
In [97]: df = pandas.DataFrame('month': np.random.randint(0,11, 100), 'A': np.random.randn(100), 'B': np.random.randn(100))

In [98]: df.join(df.groupby('month')['A'].sum(), on='month', rsuffix='_r')
Out[98]:
           A         B  month       A_r
0  -0.040710  0.182269      0 -0.331816
1  -0.004867  0.642243      1  2.448232
2  -0.162191  0.442338      4  2.045909
3  -0.979875  1.367018      5 -2.736399
4  -1.126198  0.338946      5 -2.736399
5  -0.992209 -1.343258      1  2.448232
6  -1.450310  0.021290      0 -0.331816
7  -0.675345 -1.359915      9  2.722156

【讨论】:

这仍然需要我保存 groupby 计算,而不是直接在我执行 groupby 操作的行上的 LHS 上进行分配。 Apply 可能比我在问题底部的 hack 中的循环要好一些,但它们基本上是相同的想法。 加入可以做到这一点,但您需要重命名添加的列。在这种情况下,A_r 是 new_col。 底部的连接示例确实有效,但没有清晰呈现。如果您想删除答案的第一部分并使后一部分更清楚一些,我会在接受之外投票。 我删除了第一种方法。老实说,我觉得代码不言自明,如果您想添加一些解释或对文档的引用,请随时编辑。我不是很喜欢投票系统,只是在这里支持一下熊猫。 我花了很长时间寻找这个答案,有点死灵帖子,但谢谢! +1【参考方案2】:

虽然我仍在探索 apply 连接给出的片段的所有令人难以置信的智能方式,但这是在 groupby 操作之后在父级中添加新列的另一种方法。

In [236]: df
Out[236]: 
  yearmonth    return
0    201202  0.922132
1    201202  0.220270
2    201202  0.228856
3    201203  0.277170
4    201203  0.747347

In [237]: def add_mkt_return(grp):
   .....:     grp['mkt_return'] = grp['return'].sum()
   .....:     return grp
   .....: 

In [238]: df.groupby('yearmonth').apply(add_mkt_return)
Out[238]: 
  yearmonth    return  mkt_return
0    201202  0.922132    1.371258
1    201202  0.220270    1.371258
2    201202  0.228856    1.371258
3    201203  0.277170    1.024516
4    201203  0.747347    1.024516

【讨论】:

您也可以在不使用 lambda 定义函数的情况下执行此操作并分配:df.groupby('yearmonth').apply(lambda grp: grp.assign(mkt_return=grp['return'].sum()))【参考方案3】:

我可以建议transform 方法(而不是聚合)吗?如果您在原始示例中使用它,它应该做您想做的事情(广播)。

【讨论】:

我的理解是 transform 会产生一个看起来像它传递的对象。因此,如果您转换一个 DataFrame,您不仅会返回一列,还会返回一个 DataFrame。而在我的情况下,我想将新结果附加到原始数据框中。或者你是说我应该编写一个单独的函数来获取数据框,计算新列并附加新列,然后然后使用该函数进行转换? 我同意,transform是更好的选择,df['A-month-sum'] = df.groupby('month')['A'].transform(sum) 但是为什么会更好呢?它也一样,不是吗?它更快吗? 恕我直言,transform 看起来更干净。我没有 EMS 数据来确认这一点,但这可能有效(尽管可能需要修改 lambda 函数):bdata['mkt_return'] = bdata.groupby("yearmonth").transform(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum()) 如果我错了,请纠正我,transform 不允许在groupby 之后对多个列进行操作,例如df.groupby('col_3')[['col_1','col_2']].transform(lambda x: ((1-x.col_1.mean()) - x.col_2.std())) 将抛出一个错误,抱怨“没有属性 XXX”【参考方案4】:

作为使用 groupby() 时的一般规则,如果您使用 .transform() 函数,pandas 将返回一个与原始表格长度相同的表格。当您使用 .sum() 或 .first() 等其他函数时,pandas 将返回一个表,其中每一行都是一个组。

我不确定这如何与 apply 一起工作,但使用 transform 实现复杂的 lambda 函数可能相当棘手,因此我认为最有用的策略是创建我需要的变量,将它们放在原始数据集中,然后执行我的在那里进行操作。

如果我了解您首先要正确执行的操作,您可以计算每个组的总市值:

bdata['group_MarketCap'] = bdata.groupby('yearmonth')['MarketCap'].transform('sum')

这将在您的原始数据中添加一个名为“group_MarketCap”的列,其中包含每个组的市值总和。然后你可以直接计算加权值:

bdata['weighted_P'] = bdata['PriceReturn'] * (bdata['MarketCap']/bdata['group_MarketCap'])

最后,您将使用相同的变换函数计算每个组的加权平均值:

bdata['MarketReturn'] = bdata.groupby('yearmonth')['weighted_P'].transform('sum')

我倾向于以这种方式构建我的变量。有时您可以将所有内容放在一个命令中,但这并不总是与 groupby() 一起使用,因为大多数时候 pandas 需要实例化新对象才能在整个数据集范围内对其进行操作(即,您不能如果两列尚不存在,则将两列加在一起)。

希望这会有所帮助:)

【讨论】:

【参考方案5】:

我没有找到对原始数据框进行分配的方法。所以我只是存储来自组的结果并将它们连接起来。然后我们通过索引对连接的数据帧进行排序,得到原始顺序作为输入数据帧。这是一个示例代码:

In [10]: df = pd.DataFrame('month': np.random.randint(0,11, 100), 'A': np.random.randn(100), 'B': np.random.randn(100))

In [11]: df.head()
Out[11]:
   month         A         B
0      4 -0.029106 -0.904648
1      2 -2.724073  0.492751
2      7  0.732403  0.689530
3      2  0.487685 -1.017337
4      1  1.160858 -0.025232

In [12]: res = []

In [13]: for month, group in df.groupby('month'):
    ...:     new_df = pd.DataFrame(
    ...:         'A^2+B': group.A ** 2 + group.B,
    ...:         'A+B^2': group.A + group.B**2
    ...:     )
    ...:     res.append(new_df)
    ...:

In [14]: res = pd.concat(res).sort_index()

In [15]: res.head()
Out[15]:
      A^2+B     A+B^2
0 -0.903801  0.789282
1  7.913327 -2.481270
2  1.225944  1.207855
3 -0.779501  1.522660
4  1.322360  1.161495

此方法非常快速且可扩展。您可以在此处导出任何特征。

注意:如果数据框太大,concat可能会导致你的MMO错误。

【讨论】:

使用 pandas python 将 2 个 groupby 输出与 lambda 组合

】使用pandaspython将2个groupby输出与lambda组合【英文标题】:Combining2groupbyoutputswithlambdausingpandaspython【发布时间】:2020-04-1812:00:36【问题描述】:表(df):customer_idOrder_date12015-01-1612015-01-1922014-12-2122015-01-1012015-01-1032018-01-183 查看详情

如何使用 Groupby 将 Pandas TA 应用于数据框

】如何使用Groupby将PandasTA应用于数据框【英文标题】:HowtoapplyPandasTAtoaDataframewithGroupby【发布时间】:2022-01-2403:30:36【问题描述】:我有一个包含股票数据并按股票分组的数据框(例如,参见附图),索引是每只股票的每分钟数... 查看详情

Pandas - 将列名添加到 groupby 的结果 [重复]

】Pandas-将列名添加到groupby的结果[重复]【英文标题】:Pandas-AddColumnNametoResultsofgroupby[duplicate]【发布时间】:2018-12-1207:44:40【问题描述】:我想将列名添加到Python3.6中DataFrame上的groupby的结果中。我试过这段代码:importpandasaspdd=\'t... 查看详情

如何对不同长度的 Python Pandas groupby 对象进行切片?

】如何对不同长度的PythonPandasgroupby对象进行切片?【英文标题】:HowtoslicePythonPandasgroupbyobjectswithvariouslengths?【发布时间】:2021-12-0219:37:15【问题描述】:创建数据框:df=pd.DataFrame(\'Set\':[1,1,1,2,2,2,2,2],\'Value\':[1,2,3,1,2,3,4,5])DataFrame... 查看详情

Pandas Python Groupby 累积和反向

】PandasPythonGroupby累积和反向【英文标题】:PandasPythonGroupbyCummulativeSumReverse【发布时间】:2018-02-2810:10:15【问题描述】:我找到了Pandasgroupbycumulativesum,发现它非常有用。但是,我想确定如何计算反向累积和。该链接建议以下内... 查看详情

如何访问python groupby对象值

】如何访问pythongroupby对象值【英文标题】:Howtoaccesspythongroupbyobjectsvalues【发布时间】:2017-12-0214:37:17【问题描述】:我使用groupby()函数对pandas数据框进行多列分组。df_tr_mod=df_tr.groupby([\'Col1\',\'Col2\']).aCol.agg([\'count\'])现在我想访... 查看详情

Python、Pandas:GroupBy 属性文档

】Python、Pandas:GroupBy属性文档【英文标题】:Python,Pandas:GroupByattributesdocumentation【发布时间】:2017-06-0108:35:54【问题描述】:在Groupby文档中,在页面的该级别:http://pandas.pydata.org/pandas-docs/stable/groupby.html#groupby-object-attributes如果... 查看详情

Python Pandas DF Pivot 和 Groupby

】PythonPandasDFPivot和Groupby【英文标题】:PythonPandasDFPivotandGroupby【发布时间】:2020-12-1808:28:57【问题描述】:每次text_y列中的值发生变化时,我需要遍历我的数据框行并将单列bounding_box_y旋转为8列。原始数据框所需的数据帧任何... 查看详情

如何将pandas dataframe进行groupby操作后得到的数据结构转换为dataframe?

】如何将pandasdataframe进行groupby操作后得到的数据结构转换为dataframe?【英文标题】:Howtoconvertthedatastructureobtainedafterperformingagroupbyoperationonapandasdataframeintoadataframe?【发布时间】:2019-01-2103:17:31【问题描述】:假设我有来自示例her... 查看详情

Python Pandas GroupBy 获取组列表

】PythonPandasGroupBy获取组列表【英文标题】:PythonPandasGroupBygetlistofgroups【发布时间】:2015-05-0420:32:16【问题描述】:我有一行代码:g=x.groupby(\'Color\')颜色有红色、蓝色、绿色、黄色、紫色、橙色和黑色。如何返回此列表?对于类... 查看详情

如何使用 groupby 调整 pandas 中的小计列?

】如何使用groupby调整pandas中的小计列?【英文标题】:howtoadjustsubtotalcolumnsinpandasusinggrouby?【发布时间】:2021-04-2608:32:51【问题描述】:我正在使用数据框连接将数据框导出到Excel。但是,在加入数据框之后,使用groupby计算小计... 查看详情

Python pandas groupby 方法无法正常工作

】Pythonpandasgroupby方法无法正常工作【英文标题】:Pythonpandasgroupbymethodnotworkingproperly【发布时间】:2014-04-2602:34:48【问题描述】:我有一个文本文件,每一行都有数据,每一行都有一个时间戳。所以我将数据读取到这样的数据框... 查看详情

Python pandas计算groupby后的份额

】Pythonpandas计算groupby后的份额【英文标题】:Pythonpandascalculateshareofaftergroupby【发布时间】:2021-07-2522:53:57【问题描述】:我想按邮政编码对以下类型的数据集进行分组,并计算每种运输方式在每个邮政编码中所占的已完成订单... 查看详情

python[groupby]示例groupby#pandas#secret(代码片段)

查看详情

Xlwings python pandas dataframe groupby返回重复数据

】Xlwingspythonpandasdataframegroupby返回重复数据【英文标题】:Xlwingspythonpandasdataframegroupbyreturningduplicatedata【发布时间】:2020-03-3017:59:56【问题描述】:我想对第0列和第1列进行分组。我为“x”使用了一个命名范围,我们将其称为x。... 查看详情

绘制 Pandas DataSeries.GroupBy

】绘制PandasDataSeries.GroupBy【英文标题】:PlottingaPandasDataSeries.GroupBy【发布时间】:2013-04-2821:00:19【问题描述】:我是python和pandas的新手,并且有以下DataFrame。如何绘制DataFrame,其中每个ModelID是一个单独的图,saledate是x轴,MeanToDa... 查看详情

绘制 Pandas DataSeries.GroupBy

】绘制PandasDataSeries.GroupBy【英文标题】:PlottingaPandasDataSeries.GroupBy【发布时间】:2013-04-2821:00:19【问题描述】:我是python和pandas的新手,并且有以下DataFrame。如何绘制DataFrame,其中每个ModelID是一个单独的图,saledate是x轴,MeanToDa... 查看详情

在 Pandas 中使用 groupby 函数时如何解决“keyerror”?

】在Pandas中使用groupby函数时如何解决“keyerror”?【英文标题】:howdoiresolve"keyerror"whileusinggroupbyfunctioninPandas?【发布时间】:2020-04-0708:41:27【问题描述】:我正在尝试将我的数据集与“驱动轮”、“车身样式”和“价格... 查看详情