2012-03-24 85 views
15

我有以下数据框:大熊猫 - 获得最近被另一列索引的特定列的值(获得由另一列索引的特定列的最大值)

obj_id data_date value 
0 4  2011-11-01 59500  
1 2  2011-10-01 35200 
2 4  2010-07-31 24860 
3 1  2009-07-28 15860 
4 2  2008-10-15 200200 

我想要得到的一个子集这个数据让我只有最近的(最大的'data_date''value'每个'obj_id'

我一起砍了一个解决方案,但感觉很脏。我想知道是否有人有更好的方法。我相信我一定会错过一些简单的方法来通过熊猫来做到这一点。

我的方法本质上是分组,排序,检索和重组如下:

row_arr = [] 
for grp, grp_df in df.groupby('obj_id'): 
    row_arr.append(dfg.sort('data_date', ascending = False)[:1].values[0]) 

df_new = DataFrame(row_arr, columns = ('obj_id', 'data_date', 'value')) 

回答

2

aggregate() method GROUPBY对象可用于在单个步骤中以创建从GROUPBY对象的新数据帧。 (我不知道的清洁方式,但提取数据帧的第一个/最后一行。)

In [12]: df.groupby('obj_id').agg(lambda df: df.sort('data_date')[-1:].values[0]) 
Out[12]: 
     data_date value 
obj_id     
1  2009-07-28 15860 
2  2011-10-01 35200 
4  2011-11-01 59500 

您也可以对各列的聚集,在这种情况下,聚合函数工作的系列对象。

In [25]: df.groupby('obj_id')['value'].agg({'diff': lambda s: s.max() - s.min()}) 
Out[25]: 
      diff 
obj_id   
1   0 
2  165000 
4  34640 
4

我喜欢crewbum的答案,或许这是更快(对不起,没有测试过,但我避免排序的所有内容):

df.groupby('obj_id').agg(lambda df: df.values[df['data_date'].values.argmax()]) 

它使用numpys“argmax”功能找到其中出现最大值的rowindex。

+0

我测试了速度上的数据帧有24735行,分为16组(顺便说一句:从planethunter.org数据集),并得到了12.5毫秒(argmax)VS 17.5毫秒(排序)为%timeit的结果。所以这两个解决方案都相当快:-)和我的数据集似乎太小了;-) – Maximilian 2012-10-25 08:34:39

8

如果“obj_id”的数量非常高,则需要对整个数据帧进行排序,然后删除重复项以获取最后一个元素。

sorted = df.sort_index(by='data_date') 
result = sorted.drop_duplicates('obj_id', take_last=True).values 

这应该是更快(抱歉,我没有测试),因为你没有做一个自定义的AGG功能,这是缓慢的,当有一个大的数字键。您可能认为对整个数据框进行排序会更糟糕,但实际上在python中排序很快并且本地循环很慢。

+0

这工作的魅力,其他答案都对我有问题,这也快了很多。 – 2014-09-18 01:58:29

+0

这比pdifranc的回答要快一个数量级以上。这个问题以各种形式存在于SO上。我会把他们都指向这个答案。只有一个音符'FutureWarning:take_last = True关键字已被弃用,请使用keep ='last'来代替'。 – 2017-03-26 02:21:14

0

我相信找到了一个更合适的解决方案,基于这个线程中的解决方案。 但是,我使用数据框的apply函数而不是聚合。 它还返回一个与原始列相同的新数据帧。

df = pd.DataFrame({ 
'CARD_NO': ['000', '001', '002', '002', '001', '111'], 
'DATE': ['2006-12-31 20:11:39','2006-12-27 20:11:53','2006-12-28 20:12:11','2006-12-28 20:12:13','2008-12-27 20:11:53','2006-12-30 20:11:39']}) 

print df 
df.groupby('CARD_NO').apply(lambda df:df['DATE'].values[df['DATE'].values.argmax()]) 

原始

CARD_NO     DATE 
0  000 2006-12-31 20:11:39 
1  001 2006-12-27 20:11:53 
2  002 2006-12-28 20:12:11 
3  002 2006-12-28 20:12:13 
4  001 2008-12-27 20:11:53 
5  111 2006-12-30 20:11:39 

返回数据帧:

CARD_NO 
000  2006-12-31 20:11:39 
001  2008-12-27 20:11:53 
002  2006-12-28 20:12:13 
111  2006-12-30 20:11:39 
12

这是另一种可能的解决方案。我相信这是最快的。

df.loc[df.groupby('obj_id').data_date.idxmax(),:] 
+2

这是一个很好的方法,在这个和其他环境中适用于我。 – alexbw 2015-11-22 16:20:28

+0

一个很好的通用解决方案,但与其他一些方法相比,速度很慢 – josh 2017-07-22 16:28:27

0

更新thetainted1的答案,因为一些功能现在有未来的警告,现在tommy.carstensen指出。下面是我工作:

sorted = df.sort_values(by='data_date') 

result = sorted.drop_duplicates('obj_id', keep='last') 
相关问题