python中groupby⽤法_关于groupby:PythonPandas如何将
gro。。。
我在IPython中有以下数据框,其中每⼀⾏都是⼀只股票:
In [261]: bdata
Out[261]:
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操作,该操作计算" yearmonth"列中每个⽇期的所有内容的上限加权平均回报。
这按预期⼯作:
In [262]: upby("yearmonth").apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())
Out[262]:
yearmonth
201204 -0.109444
201205 -0.290546
但是,然后我想将这些值"⼴播"回原始数据帧中的索引,并将它们保存为⽇期匹配的常量列。
In [263]: dateGrps = upby("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/ in ()
----> 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对象级别添加列那样直观。
我会举⼀个例⼦。
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.upby('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
虽然我仍在探索将apply连接起来的所有令⼈难以置信的聪明⽅法,但这是在groupby操作之后在⽗级中添加新列的另⼀种⽅法。
In [236]: df
Out[236]:
yearmonth return
0 201202 0.922132
1 20120
2 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 20120
2 0.220270 1.371258
2 201202 0.228856 1.371258
3 201203 0.277170 1.024516
4 201203 0.747347 1.024516
我可以建议使⽤transform⽅法(⽽不是合计)吗?如果您在原始⽰例中使⽤它,它应该做您想要的(⼴播)。
我的理解是,转换产⽣的对象看起来像它传递的对象。因此,如果转换DataFrame,则不只是返回⼀列,⽽是返回DataFrame。⽽就我⽽⾔,我想将新结果附加到原始数据框。还是在说我应该编写⼀个单独的函数,该函数采⽤⼀个数据帧,计算新列,然后追加新列,然后使⽤该函数进⾏转换?
我同意,变换是更好的选择,df [A-month-sum] = df.groupby(month)[A] .transform(sum)
但是为什么会更好呢?⼀样吗,不是吗?它更快吗?
groupby是什么函数恕我直⾔,transform看起来更⼲净。 我没有EMS数据来确认这⼀点,但这可能有⽤(尽管可能必须修改lambda函数):
bdata[mkt_return] = upby("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: ((an()) - x.col_2.std()))将引发错误,抱怨没有属性XXX
通常,使⽤groupby()时,如果使⽤.transform()函数,pandas将返回与原始表相同长度的表。当您使⽤.sum()或.first()之类的其他函数时,pandas将返回⼀个表格,其中每⼀⾏都是⼀组。
我不确定应⽤程序如何⼯作,但通过转换实现复杂的lambda函数可能会⾮常棘⼿,因此我发现最有帮助的策略是创建所需的变量,将其放在原始数据集中,然后在此处进⾏操作。
如果我了解您要正确执⾏的操作(如果我弄错了,我深表歉意),那么您可以计算每个组的总市值:
bdata['group_MarketCap'] = upby('yearmonth')['MarketCap'].transform('sum')
这将在原始数据中添加⼀列" group_MarketCap",其中将包含每个组的市值之和。然后,您可以直接计算加权值:
bdata['weighted_P'] = bdata['PriceReturn'] * (bdata['MarketCap']/bdata['group_MarketCap'])
最后,您将使⽤相同的变换函数计算每个组的加权平均值:
bdata['MarketReturn'] = upby('yearmonth')['weighted_P'].transform('sum')
我倾向于以此⽅式构建变量。有时您可以将所有内容放到⼀个命令中,但这并不总是与groupby()⼀起使⽤,因为⼤多数情况下,熊猫需要实例化新对象才能在整个数据集范围内对其进⾏操作(即,您不能如果尚不存在,则将两列加在⼀起)。
希望这可以帮助 :)
这样⾏吗?
capWeighting = lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum()
bdata["MarketReturn"] = upby("yearmonth").transform(capWeighting)
我为此使⽤reindex_like:
summedbdata = upby("yearmonth").apply(lambda x:
(x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())
summedbdata.set_index('yearmonth').reindex_like(bdata.set_index('yearmonth').sort_index(), method='ffill')
这只是⽤NaN填充整个数组。看我的中间⽰例,其中的⾏是" In [262]"和" Out [262]"。我希望该操作的输出可以直接分配回bdata中的⼀列,以使该⼩输出(两个⽇期值)的索引被⼴播回它们在bdata中的位置(此信息必须位于groupby对象,只是不清楚如何使⽤它,⽽⽆需求助于组⾃⾝,这是我要避免的具体操作。
⽤summedbdata表⽰您的ln262。然后根据原始DataFrame重新索引此结果,并在⽰例中将其索引与2个值匹配。我提供的填充⽅法确定如何填充其余的列(默认情况下为NaN)。
我觉得你很困惑。仅涉及⼀列。对于某些索引(那些具有与⽇期#1相同的⽇期),该列将获得⼀个常数。对于其他索引(⽇期等于⽇期#2的索引),它们将获得其他常数值。还有其他"列"要填充。我测试了这种⽅法,但它不能像您所说的那样起作⽤。它不会重新索引按⽇期索引的内容并将其转换为按标
识符索引的内容,这是我的⽰例所需要的。⽇期索引来⾃标识符具有该⽇期的位置,因此groupby应该知道如何进⾏反向映射。
抱歉,我的意思是⾏⽽不是列...此外,您的bdata必须⽤yearmonth编制索引并⽤sortlevel(0)进⾏排序才能正常⼯作。
是的,但是我不希望bdata按yearmonth索引。那就是问题的很⼤⼀部分。 bdata中有很多很多重复的yearmonths,这就是我⾸先创建groupby组的⽅式! bdata⽆法按yearmonth进⾏索引,但是对于yearmonthgroupby组的每个结果,对于原始数组中具有相同yearmonth的所有事物,可以将其作为常量值平凡地传播回去。 。
我现在更好了。更新了我的答案。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论