将不同的功能应用于组对象中的不同项目:Python pandas
Posted
技术标签:
【中文标题】将不同的功能应用于组对象中的不同项目:Python pandas【英文标题】:Apply different functions to different items in group object: Python pandas 【发布时间】:2013-02-22 02:48:11 【问题描述】:假设我有一个如下的数据框:
In [1]: test_dup_df
Out[1]:
exe_price exe_vol flag
2008-03-13 14:41:07 84.5 200 yes
2008-03-13 14:41:37 85.0 10000 yes
2008-03-13 14:41:38 84.5 69700 yes
2008-03-13 14:41:39 84.5 1200 yes
2008-03-13 14:42:00 84.5 1000 yes
2008-03-13 14:42:08 84.5 300 yes
2008-03-13 14:42:10 84.5 88100 yes
2008-03-13 14:42:10 84.5 11900 yes
2008-03-13 14:42:15 84.5 5000 yes
2008-03-13 14:42:16 84.5 3200 yes
我想在时间14:42:10
对重复数据进行分组,并对exe_price
和exe_vol
应用不同的函数(例如,求和exe_vol
并计算exe_price
的体积加权平均值)。我知道我能做到
In [2]: grouped = test_dup_df.groupby(level=0)
对重复的索引进行分组,然后使用first()
或last()
函数获取第一行或最后一行,但这并不是我真正想要的。
有没有办法对不同列中的值进行分组,然后将不同的(由我编写的)函数应用于值?
【问题讨论】:
这不会给我两个单独的数据框吗?我想将它放在一个数据框中(类似于 grouped.first() 或 grouped.last() 的输出)。我可能错过了什么吗?? 【参考方案1】:应用你自己的函数:
In [12]: def func(x):
exe_price = (x['exe_price']*x['exe_vol']).sum() / x['exe_vol'].sum()
exe_vol = x['exe_vol'].sum()
flag = True
return Series([exe_price, exe_vol, flag], index=['exe_price', 'exe_vol', 'flag'])
In [13]: test_dup_df.groupby(test_dup_df.index).apply(func)
Out[13]:
exe_price exe_vol flag
date_time
2008-03-13 14:41:07 84.5 200 True
2008-03-13 14:41:37 85 10000 True
2008-03-13 14:41:38 84.5 69700 True
2008-03-13 14:41:39 84.5 1200 True
2008-03-13 14:42:00 84.5 1000 True
2008-03-13 14:42:08 84.5 300 True
2008-03-13 14:42:10 20.71 100000 True
2008-03-13 14:42:15 84.5 5000 True
2008-03-13 14:42:16 84.5 3200 True
【讨论】:
这太棒了!flag = True
的目的是什么?
该函数应该返回一个包含与原始列相同的所有列的系列。我不知道 flag 是什么意思,所以直接返回 True。【参考方案2】:
我喜欢@waitingkuo 的回答,因为它非常清晰易读。
无论如何我都会保留它,因为它看起来确实更快——至少在 Pandas 0.10.0 版中是这样。 may (hopefully) change in the future 的情况,因此请务必重新运行基准测试,尤其是在您使用不同版本的 Pandas 时。
import pandas as pd
import io
import timeit
data = '''\
date time exe_price exe_vol flag
2008-03-13 14:41:07 84.5 200 yes
2008-03-13 14:41:37 85.0 10000 yes
2008-03-13 14:41:38 84.5 69700 yes
2008-03-13 14:41:39 84.5 1200 yes
2008-03-13 14:42:00 84.5 1000 yes
2008-03-13 14:42:08 84.5 300 yes
2008-03-13 14:42:10 10 88100 yes
2008-03-13 14:42:10 100 11900 yes
2008-03-13 14:42:15 84.5 5000 yes
2008-03-13 14:42:16 84.5 3200 yes'''
df = pd.read_table(io.BytesIO(data), sep='\s+', parse_dates=[[0, 1]],
index_col=0)
def func(subf):
exe_vol = subf['exe_vol'].sum()
exe_price = ((subf['exe_price']*subf['exe_vol']).sum()
/ exe_vol)
flag = True
return pd.Series([exe_price, exe_vol, flag],
index=['exe_price', 'exe_vol', 'flag'])
# return exe_price
def using_apply():
return df.groupby(df.index).apply(func)
def using_helper_column():
df['weight'] = df['exe_price'] * df['exe_vol']
grouped = df.groupby(level=0, group_keys=True)
result = grouped.agg('weight': 'sum', 'exe_vol': 'sum')
result['exe_price'] = result['weight'] / result['exe_vol']
result['flag'] = True
result = result.drop(['weight'], axis=1)
return result
result = using_apply()
print(result)
result = using_helper_column()
print(result)
time_apply = timeit.timeit('m.using_apply()',
'import __main__ as m ',
number=1000)
time_helper = timeit.timeit('m.using_helper_column()',
'import __main__ as m ',
number=1000)
print('using_apply: t'.format(t = time_apply))
print('using_helper_column: t'.format(t = time_helper))
产量
exe_vol exe_price flag
date_time
2008-03-13 14:41:07 200 84.50 True
2008-03-13 14:41:37 10000 85.00 True
2008-03-13 14:41:38 69700 84.50 True
2008-03-13 14:41:39 1200 84.50 True
2008-03-13 14:42:00 1000 84.50 True
2008-03-13 14:42:08 300 84.50 True
2008-03-13 14:42:10 100000 20.71 True
2008-03-13 14:42:15 5000 84.50 True
2008-03-13 14:42:16 3200 84.50 True
timeit 基准为:
using_apply: 3.0081038475
using_helper_column: 1.35300707817
【讨论】:
非常感谢! PS:希望创建一个新的数据框不会占用太多内存,因为我有超过 200 万行... @kunitomo:看来我错了——waitingkuo 展示了一种在多列上聚合的方法。 这仍然是 pandas 0.18 和 python 3.4.5 的两倍。【参考方案3】:对pandas
不是很熟悉,但在纯 numpy 中你可以这样做:
tot_vol = np.sum(grouped['exe_vol'])
avg_price = np.average(grouped['exe_price'], weights=grouped['exe_vol'])
【讨论】:
感谢您的快速回复。我想知道,既然我的“分组”现在是一个熊猫 DataFrameGroupBy 对象,我真的不能直接应用你的功能吗? 也许你可以把它变成另一个数据框here 我明白了。非常感谢。以上是关于将不同的功能应用于组对象中的不同项目:Python pandas的主要内容,如果未能解决你的问题,请参考以下文章