如何使用groupby来避免python中的循环

时间:2013-11-20 22:12:42

标签: python loops pandas

数据中有几列,其中三列名为“candidate_id”,“enddate”,“TitleLevel”。

在同一个id中,如果enddate相同,我将删除较低级别的记录。

例如,给定:

candidate_id   startdate     enddate   TitleLevel
    1          2012.1.1      2013.5.1     2
    1          2011.1.1      2013.5.1     4
    1          2008.12.1     2010.1.1     3
    2          2010.10.1     2012.12.1    2

我想要的是:

candidate_id   startdate     enddate   TitleLevel
    1          2011.1.1      2013.5.1     4
    1          2008.12.1     2010.1.1     3
    2          2010.10.1     2012.12.1    2

我将删除candidate_id=1enddate=2013.5.1titlelevel=2

我想出了一个循环。

for i in range(nrow-2,-1, -1):
    if (JobData['enddate'][i] == JobData['enddate'][i+1] 
           and JobData['candidate_id'][i] == JobData['candidate_id'][i+1] 
           and pd.notnull(JobData['enddate'][i]):
        if JobData['TitleLevel'][i] > JobData['TitleLevel'][i+1]:
            JobData= JobData.drop(i+1)
        else:
            JobData= JobData.drop(i) 

循环确实需要一些时间来删除冗余行。有更快的方法吗?

2 个答案:

答案 0 :(得分:2)

如果数据结构与您描述的完全一致,则可以使用groupby / max

>>> df
   candidate_id    enddate  TitleLevel
0             1   2013.5.1           2
1             1   2013.5.1           4
2             1   2010.1.1           3
3             2  2012.12.1           2
>>> df.groupby(['candidate_id','enddate']).max().reset_index()
   candidate_id    enddate  TitleLevel
0             1   2010.1.1           3
1             1   2013.5.1           4
2             2  2012.12.1           2

此处groupby将行分为candidate_idenddatemax()评估每个组中的最大TitleLevel。结果与删除所有其他值的行相同。

如果您有更多列,

>>> df
   candidate_id    enddate  TitleLevel other_column
0             1   2013.5.1           2          foo
1             1   2013.5.1           4          bar
2             1   2010.1.1           3       foobar
3             2  2012.12.1           2       barfoo

您可以获取具有最大值的行的idex,如果必须保留行顺序,则不进行排序:

>>> idx = df.groupby(['candidate_id','enddate'], sort=False)['TitleLevel'].agg(lambda x: x.idxmax())

并使用ix过滤所需的行:

>>> df.ix[idx]
   candidate_id    enddate  TitleLevel other_column
1             1   2013.5.1           4          bar
2             1   2010.1.1           3       foobar
3             2  2012.12.1           2       barfoo

答案 1 :(得分:1)

假设数据按startdate排序(至少在每个组中),您可以使用groupby last

In [11]: df.groupby(['candidate_id', 'enddate'], as_index=False).last()
Out[11]: 
   candidate_id    enddate  startdate  TitleLevel
0             1   2010.1.1  2008.12.1           3
1             1   2013.5.1   2011.1.1           4
2             2  2012.12.1  2010.10.1           2