使用apply将panda的数据帧组迭代转换为groupby

时间:2014-10-08 23:48:39

标签: python pandas

我需要将数据帧拆分成组,对于那些具有奇数行的组,我需要拉入其列匹配某个条件的第一行,然后我需要汇回所有这些第一行(所以只有符合条件的奇数组中的第一个)。我可以在下面的循环(它工作)中执行它,但不能使用apply将其重新编写为groupby。你能帮忙吗?

grp_by_cols=['A','B']
new_df=pd.DataFrame(columns=grp_by_cols)
for name, group in txn.groupby(grp_by_cols):
if len(group) % 2 != 0:
    new_df=new_df.append(group[group['C']=='something')].head(1))

1 个答案:

答案 0 :(得分:2)

有趣的问题,我会通过编写一个函数然后通过申请来解决。

假设您有这样的数据(对问题很方便):

import pandas as pd
import random

DF = pd.DataFrame({
        'key'   : [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7],
        'data1' : ['A', 'B', 'C', 'A', 'B', 'B', 'B', 'C', 'A', 'B', 'A', 'B', 'C',
                 'A', 'B', 'B', 'B', 'C'],
        'data2' : [random.random() for x in xrange(18)]})

其中key是您要分组的列," data1'是您将用于测试条件的列。对于组1,3,5和7,该数据具有奇数个观察结果。<数据1'第一次观察时这些群体的价值是A' B' B' A'' B'例如,假设您希望获得一个新数据框,其中包含这些组中的第一个观察结果,但仅限于“数据1”和“数据”的位置。第一行中的值等于B.我们可以写一个像这样的通用函数:

def apply_func(df, col, condition):
    if len(df)%2 == 0:
        return None
    else:
        if df.irow(0)[col] == condition:
            return df.irow(0)
        else:
            return None

然后按如下方式在组上调用它:

DF.groupby('key').apply(apply_func, 'data1', 'B').dropna()

给出以下输出:

  data1     data2  key
2     B  0.980814    3
6     B  0.428402    7

如果我没弄错的话,那就是你想要生成的输出类型。

当然你实际上并不需要函数中的所有分支,我只是为了让它更清晰。编写函数最简洁的方法是:

def apply_func(df, col, condition):
    if len(df)%2 != 0 and df.irow(0)[col] == condition:
        return df.irow(0)

请注意,在调用传递要应用的函数时,传递的第一个参数是DataFrame本身,这是自动完成的。这就是为什么你不需要指定' df'传递函数以应用时的参数。事实上,如果你这样做,你会得到一个错误,说你已经传递了太多的论据。在我的视图中,在传递函数时,有点奇怪的是,参数是在逗号之后而不是在括号中提供的。我觉得这看起来令人困惑,但它就是它......