22

我有以下数据框:

   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'))
4

6 回答 6

17

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

sorted = df.sort_index(by='data_date')
result = sorted.drop_duplicates('obj_id', keep='last').values

这应该会更快(抱歉我没有测试它),因为你不必做自定义的 agg 函数,当有大量键时会很慢。您可能认为对整个数据帧进行排序会更糟糕,但实际上在 python 中排序速度很快,而本地循环很慢。

于 2014-01-08T21:35:50.247 回答
17

这是另一种可能的解决方案。不知道这是否是最快的(我怀疑..),因为我没有将它与其他方法进行基准测试。

df.loc[df.groupby('obj_id').data_date.idxmax(),:]
于 2014-04-08T14:58:02.850 回答
4

我喜欢crewbum的回答,可能这更快(抱歉,尚未对此进行测试,但我避免对所有内容进行排序):

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

它使用 numpys "argmax" 函数来查找出现最大值的行索引。

于 2012-10-23T11:16:32.897 回答
2

groupby 对象上的aggregate() 方法可用于在一个步骤中从 groupby 对象创建新的 DataFrame。(不过,我不知道有一种更简洁的方法来提取 DataFrame 的第一行/最后一行。)

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

您还可以对单个列执行聚合,在这种情况下,聚合函数适用于 Series 对象。

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
于 2012-03-25T01:46:55.683 回答
2

正如tommy.carstensen指出的那样,由于某些功能现在有未来的警告,因此更新了thetainted1的答案。这对我有用:

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

result = sorted.drop_duplicates('obj_id', keep='last')
于 2017-08-13T23:13:56.983 回答
0

我相信已经找到了基于此线程中的更合适的解决方案。但是我的使用数据框的应用功能而不是聚合。它还返回一个新的数据框,其列与原始数据框相同。

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
于 2014-03-04T20:01:20.500 回答