2012-03-24 51 views
15

Tôi có dataframe sau:gấu trúc - nhận được hầu hết giá trị gần đây của một cột cụ thể lập chỉ mục theo cột khác (nhận được giá trị tối đa của một cột cụ thể lập chỉ mục theo cột khác)

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 

Tôi muốn có được một tập hợp con của dữ liệu này để tôi chỉ có mới nhất (lớn nhất 'data_date') 'value' cho mỗi 'obj_id'.

Tôi đã tấn công cùng nhau một giải pháp, nhưng nó cảm thấy bẩn. Tôi đã tự hỏi nếu có ai có một cách tốt hơn. Tôi chắc rằng tôi phải thiếu một số cách dễ dàng để làm điều đó thông qua gấu trúc.

Phương pháp của tôi chủ yếu là nhóm, sắp xếp, lấy, và tái tổ hợp như sau:

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

Trả lời

2

Các aggregate() method trên các đối tượng groupby thể được sử dụng để tạo ra một DataFrame mới từ một đối tượng groupby trong một bước duy nhất. (Tôi không biết một cách sạch hơn để trích xuất các dòng/ngoái đầu tiên của một DataFrame mặc dù.)

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 

Bạn cũng có thể thực hiện tập hợp trên các cột riêng biệt, trong trường hợp này hàm tổng hợp hoạt động trên một đối tượng Dòng .

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

Tôi thích câu trả lời crewbum, có lẽ đây là nhanh hơn (xin lỗi, không được thử nghiệm này, nhưng tôi tránh sắp xếp tất cả mọi thứ):

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

nó sử dụng numpys "argmax" chức năng để tìm ra rowindex trong đó tối đa xuất hiện.

+0

tôi đã thử nghiệm tốc độ trên dataframe với 24735 hàng, chia thành 16 nhóm (btw: bộ dữ liệu từ planethunter.org) và có 12,5 ms (argmax) vs 17,5 ms (loại) như kết quả của% timeit. Vì vậy, cả hai giải pháp khá nhanh :-) và tập dữ liệu của tôi dường như quá nhỏ ;-) – Maximilian

8

Nếu số lượng "obj_id" s rất cao, bạn sẽ muốn sắp xếp toàn bộ khung dữ liệu và sau đó thả các bản sao để lấy phần tử cuối cùng.

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

Điều này sẽ nhanh hơn (xin lỗi tôi đã không kiểm tra) vì bạn không phải thực hiện chức năng tùy chỉnh, điều này rất chậm khi có nhiều khóa. Bạn có thể nghĩ rằng nó tồi tệ hơn để sắp xếp toàn bộ khung dữ liệu, nhưng trong thực tế trong các loại python là nhanh và vòng bản địa chậm.

+0

Điều này làm việc một sự quyến rũ, các câu trả lời khác tất cả đã có vấn đề đối với tôi, và điều này cũng nhanh hơn rất nhiều. –

+0

Đây là một đơn đặt hàng của cường độ nhanh hơn cho tôi hơn là câu trả lời của pdifranc. Câu hỏi này tồn tại trong nhiều vỏ bọc trên SO. Tôi sẽ chỉ cho họ tất cả câu trả lời này. Chỉ cần một lưu ý 'FutureWarning: từ khóa take_last = True bị từ chối, hãy sử dụng keep = 'last' thay thế'. –

0

Tôi tin rằng đã tìm thấy giải pháp thích hợp hơn dựa trên giải pháp trong chuỗi này. Tuy nhiên, tôi sử dụng hàm áp dụng của một khung dữ liệu thay vì tổng hợp. Nó cũng trả về một khung dữ liệu mới với các cột giống như cột gốc.

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()]) 

gốc

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 

dataframe trả lại:

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

Đây là một giải pháp khả thi. Tôi tin rằng đó là nhanh nhất.

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

Đây là một cách tiếp cận tốt đẹp đã làm việc cho tôi trong ngữ cảnh này và các ngữ cảnh khác. – alexbw

+0

Một giải pháp tổng thể tốt đẹp nhưng khá chậm so với một số phương pháp khác – josh

0

Cập nhật câu trả lời của thetainted1 vì một số chức năng có cảnh báo trong tương lai ngay bây giờ như tommy.carstensen đã chỉ ra.Đây là những gì làm việc cho tôi:

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

result = sorted.drop_duplicates('obj_id', keep='last') 
Các vấn đề liên quan