如何使用groupby避免python中的循环
Posted
技术标签:
【中文标题】如何使用groupby避免python中的循环【英文标题】:how to use groupby to avoid loop in python 【发布时间】:2013-12-05 03:58:42 【问题描述】:数据中有几列,三列分别命名为“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=1
、enddate=2013.5.1
和titlelevel=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)
循环确实需要一些时间来删除冗余行。有更快的方法吗?
【问题讨论】:
如果你能在代码中给出一些测试数据,你会更容易回答你的问题。话虽如此,groupby 非常好用。只需记住在将数据列表传递给函数之前对其进行排序 不仅仅是熊猫。我只是想找到一种方法来加速代码,而不使用 for 循环和 if else。测试数据在“说”下面。在candidate_id=1,enddate=2013.5.1,我想删除TitleLevel较低的行。 @user3013706,是的,但是用pandas
标记非常有帮助,因为熟悉它的人会看到你的问题
@user3013706 当你使用pandas时,可以根据pandas api给你建议,而不仅仅是使用一般的python内置
这段代码的目的是建立一个统计模型。所以我使用熊猫读入 csv 文件。好的,我会把“熊猫”放在标签里:)
【参考方案1】:
假设数据按开始日期排序(至少在每个组内),您可以使用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
【讨论】:
排序需要时间,所以我没有按开始日期对数据进行排序。我想要做的是将具有最高 TitleLevel 的数据保留在相同的候选 ID 和相同的结束日期中。你有什么想法可以做到这一点,但没有对开始日期进行排序?谢谢!【参考方案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_id
和 enddate
的行分组,max()
计算每个组内的最大 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
如果必须保留行顺序,您可以获得具有最大值的行的索引,而无需排序:
>>> 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
【讨论】:
但是如果我还想保持“enddate”的原始顺序。您的代码似乎对候选 ID 中的结束日期进行了排序。还有一些其他的列,我只是提取这些例如.. @user3013706 您可以使用 sort=False 参数和 ix/idxmax 而不是 max。查看更新的代码 就我而言,我认为 groupby(['candidate_id','enddate'],sort=False)['TitleLevel'].agg(lambda x:x.max()) 是正确的, bc 它不需要最大化它的索引。但是,使用代码后,其他列(除了candidate_id、enddate、TitleLevel)都不见了。以上是关于如何使用groupby避免python中的循环的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 .join() 避免在循环中连接字符串? - Python
如何在python中的groupby中为lambda函数设置名称标题[重复]