Ответ 1
Это еще одно возможное решение. Я считаю, что это самый быстрый.
df.loc[df.groupby('obj_id').data_date.idxmax(),:]
У меня есть следующий фреймворк:
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'
.
Я взломал решение, но он чувствует себя грязным. Мне было интересно, есть ли у кого-то лучший способ. Я уверен, что мне не хватает простого способа сделать это через pandas.
Мой метод состоит в том, чтобы группировать, сортировать, извлекать и рекомбинировать следующим образом:
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'))
Это еще одно возможное решение. Я считаю, что это самый быстрый.
df.loc[df.groupby('obj_id').data_date.idxmax(),:]
Если число "obj_id" очень велико, вам нужно отсортировать весь фрейм данных, а затем отбросить дубликаты, чтобы получить последний элемент.
sorted = df.sort_index(by='data_date')
result = sorted.drop_duplicates('obj_id', keep='last').values
Это должно быть быстрее (извините, я не проверял это), потому что вам не нужно делать специальную функцию agg, которая работает медленно при большом количестве клавиш. Вы можете подумать, что хуже сортировать весь фрейм данных, но на практике в Python сортировки выполняются быстро, а собственные циклы - медленные.
Мне нравится ответ экипажа, возможно, это быстрее (извините, еще не проверял, но я не сортирую все):
df.groupby('obj_id').agg(lambda df: df.values[df['data_date'].values.argmax()])
он использует функцию numpys "argmax" для поиска rowindex, в котором отображается максимум.
метод aggregate() для объектов groupby можно использовать для создания нового DataFrame из объекта groupby за один шаг. (Я не знаю более чистого способа извлечь первую/последнюю строку 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
Обновление ответа thetainted1, так как некоторые функции теперь имеют будущие предупреждения, как указано в tommy.carstensen. Вот то, что сработало для меня:
sorted = df.sort_values(by='data_date')
result = sorted.drop_duplicates('obj_id', keep='last')
Я считаю, что нашел более подходящее решение, основанное на том, что было в этой теме. Тем не менее моя использует функцию 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