当前位置: 首页 > 知识库问答 >
问题:

对组对象中的不同项应用不同的函数:Python

孙乐逸
2023-03-14

假设我有一个数据帧,如下所示:

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_priceexe_vol(例如,求和exe_vol和计算卷加权平均值exe_price)...我知道我能做到

In [2]: grouped = test_dup_df.groupby(level=0)

将重复索引分组,然后使用first()last()函数获取第一行或最后一行,但这并不是我真正想要的。

是否有方法对不同列中的值进行分组,然后应用不同的(由我编写的)函数?

共有3个答案

通迪
2023-03-14

不太熟悉熊猫,但在纯numpy中,您可以:

tot_vol = np.sum(grouped['exe_vol'])
avg_price = np.average(grouped['exe_price'], weights=grouped['exe_vol'])
华君浩
2023-03-14

我喜欢@waitingkuo的答案,因为它非常清晰易读。

不管怎样,我一直保留着这个,因为它看起来确实更快——至少在熊猫版本0.10.0中是这样。这种情况可能(希望)在未来发生变化,因此一定要重新运行基准测试,特别是如果您使用的是不同版本的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

具有时间基准:

using_apply: 3.0081038475
using_helper_column: 1.35300707817
段干玺
2023-03-14

应用您自己的功能

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
 类似资料:
  • 编辑:最后一个问题,如何通过值而不是引用来存储它?

  • 我想知道如何为不同对象的数组指定JSON模式。这个线程给了我一半的答案,但当我有每种类型的对象的多个实例时,它就失败了。 下面是一个基于这里给出的示例的示例XML,但是重复了“product”对象:- 下面的模式将只在每种类型都有单个实例时(例如,如果“product”只出现一次)验证上面的XML。 为了增加娱乐性,我不能使用像“anyof”这样的关键字,因为我要将这个模式嵌入到一个Swagger

  • 问题内容: 我正在练习继承。 我有两个相似的类,我想将其同化为一个数组,因此我想将Object类用作超类,因为所有内容都是Object的子类。 因此,例如,我将T类和CT类放入一个名为all的数组中,如下所示: 我跳过了声明,因为那不是我的问题。 当我希望使用循环在数组内调用函数时,我真正的问题就变成了: T和CT分别涉及的类都具有beingShot方法,该方法是公共的。 Eclipse建议将它们

  • 打印c时,c的值是初始化的值,x,y都是1。a变化了不影响c。 那么函数d在初始化时,x:b(),y:a为什么不初始化为x:1,y:1呢,就是这样

  • 问题内容: 我尝试过一些关于绑定和未绑定方法的代码。当我们调用它们时,我认为它们都会返回对象。但是,当我用于获取一些信息时,它返回的内容我并不理解。 IDE:Eclipse 插件:pydev 输出是… 为什么#1和#2返回相同的ID?他们不是不同的对象吗?如果我们分配和两个变量,#3,#4回报不同的ID。 我认为#3和#4表明它们不是同一对象,而是#1和#2 … 绑定方法的ID和未绑定方法的ID有

  • 我是新来的Clojure和玩它的乐趣。 我正在阅读一个CSV文件,并希望对每一列应用一个不同的函数。什么是一个优雅的(既简洁又可读)方法来做到这一点?我探讨了两种方法: null 对于每一行... ...我想对每个元素应用一个不同的函数,得到这样的结果: 我要使用的函数是: null 使用此方法,我首先将每一行转换为一个映射: 编辑:并且我想获取此地图: 转换器也存储在映射中: 最后我会把数据放入