gấu trúc python: Loại bỏ trùng lặp theo cột A, giữ hàng có giá trị cao nhất trong cột B


161

Tôi có một khung dữ liệu với các giá trị lặp lại trong cột A. Tôi muốn loại bỏ các mục trùng lặp, giữ cho hàng có giá trị cao nhất trong cột B.

Vậy đây:

A B
1 10
1 20
2 30
2 40
3 10

Nên biến thành thế này:

A B
1 20
2 40
3 10

Wes đã thêm một số chức năng tốt đẹp để loại bỏ các bản sao: http://wesmckinney.com/blog/?p=340 . Nhưng AFAICT, nó được thiết kế cho các bản sao chính xác, vì vậy không đề cập đến các tiêu chí để chọn hàng nào được giữ.

Tôi đoán có lẽ có một cách dễ dàng để làm điều này --- có thể dễ như sắp xếp khung dữ liệu trước khi bỏ các bản sao --- nhưng tôi không biết logic bên trong của nhóm đủ tốt để tìm ra nó. Bất kỳ đề xuất?


1
Lưu ý rằng URL trong câu hỏi xuất hiện EOL.
DaveL17

Đối với một cách thành ngữ và hiệu suất, xem giải pháp này dưới đây .
Ted Petrou

Câu trả lời:


194

Điều này mất cuối cùng. Không phải là tối đa mặc dù:

In [10]: df.drop_duplicates(subset='A', keep="last")
Out[10]: 
   A   B
1  1  20
3  2  40
4  3  10

Bạn cũng có thể làm một cái gì đó như:

In [12]: df.groupby('A', group_keys=False).apply(lambda x: x.loc[x.B.idxmax()])
Out[12]: 
   A   B
A       
1  1  20
2  2  40
3  3  10

12
Lưu ý nhỏ: Các tham số colstake_lastđược khấu hao và đã được thay thế bởi subsetkeepcác tham số. pandas.pydata.org/pandas-docs/version/0.17.1/generated/ tôn
Jezzamon

như @Jezzamon nói,FutureWarning: the take_last=True keyword is deprecated, use keep='last' instead
tumultous_rooster

1
Có một lý do để không sử dụng df.sort_values(by=['B']).drop_duplicates(subset=['A'], keep='last')? Ý tôi là sort_values ​​này có vẻ an toàn với tôi nhưng tôi không biết nó có thực sự như vậy không.
Bàn Bobby nhỏ

4
Câu trả lời này đã lỗi thời. Xem câu trả lời của @Ted Petrou bên dưới.
cxrodgers

Nếu bạn muốn sử dụng mã này nhưng với trường hợp có nhiều hơn một cột trong group_by, bạn có thể thêm .reset_index(drop=True) df.groupby(['A','C'], group_keys=False).apply(lambda x: x.ix[x.B.idxmax()]).reset_index(drop=True)Điều này sẽ đặt lại chỉ mục vì giá trị mặc định của nó sẽ là Multindex được tính từ 'A''C'
Hamri đã nói

79

Câu trả lời hàng đầu là làm quá nhiều việc và có vẻ rất chậm đối với các tập dữ liệu lớn hơn. applylà chậm và nên tránh nếu có thể. ixkhông được chấp nhận và nên tránh là tốt.

df.sort_values('B', ascending=False).drop_duplicates('A').sort_index()

   A   B
1  1  20
3  2  40
4  3  10

Hoặc đơn giản là nhóm theo tất cả các cột khác và lấy tối đa cột bạn cần. df.groupby('A', as_index=False).max()


1
Đây thực sự là một cách tiếp cận cleaver. Tôi đã tự hỏi nếu nó có thể được khái quát bằng cách sử dụng một số lambachức năng trong khi thả. Ví dụ: làm thế nào tôi có thể thả chỉ các giá trị nhỏ hơn giá trị trung bình của các giá trị trùng lặp đó.
Dexter

15

Giải pháp đơn giản nhất:

Để loại bỏ trùng lặp dựa trên một cột:

df = df.drop_duplicates('column_name', keep='last')

Để loại bỏ trùng lặp dựa trên nhiều cột:

df = df.drop_duplicates(['col_name1','col_name2','col_name3'], keep='last')

1
Giải pháp tốt nhất. Cảm ơn.
Flavio

Vui mừng được giúp đỡ. @Flavio
Gil Baggio

Khung dữ liệu của tôi có 10 cột và tôi đã sử dụng mã này để xóa các bản sao khỏi ba cột. Tuy nhiên, nó đã xóa các hàng từ phần còn lại của các cột. Có cách nào để xóa các bản sao chỉ cho 4 cột cuối cùng không?
Sofia

2
Nhưng OP muốn giữ giá trị cao nhất trong cột B. Điều này có thể hoạt động nếu bạn sắp xếp trước. Nhưng về cơ bản, đó là câu trả lời của Ted Petrou.
Teepeemm

7

Thử cái này:

df.groupby(['A']).max()

1
Bạn có biết thành ngữ tốt nhất để giới thiệu lại cái này để trông giống như DataFrame ban đầu không? Tôi đã cố gắng để tìm ra điều đó khi bạn ninja tôi. : ^)
DSM

4
Khéo léo. Điều gì xảy ra nếu khung dữ liệu chứa nhiều cột hơn (ví dụ C, D, E)? Max dường như không hoạt động trong trường hợp đó, bởi vì chúng ta cần xác định rằng B là cột duy nhất cần được tối đa hóa.
Abe

1
@DSM Kiểm tra liên kết trong câu hỏi ban đầu. Có một số mã để giới thiệu lại khung dữ liệu được nhóm.
Abe

5

Tôi sẽ sắp xếp khung dữ liệu trước với Cột B giảm dần, sau đó thả các bản sao cho Cột A và giữ trước

df = df.sort_values(by='B', ascending=False)
df = df.drop_duplicates(subset='A', keep="first")

không có bất kỳ nhóm



1

Tôi nghĩ rằng trong trường hợp của bạn, bạn không thực sự cần một nhóm. Tôi sẽ sắp xếp theo thứ tự giảm dần thứ tự cột B của bạn, sau đó thả các bản sao vào cột A và nếu bạn muốn, bạn cũng có thể có một chỉ mục mới đẹp và sạch như thế:

df.sort_values('B', ascending=False).drop_duplicates('A').sort_index().reset_index(drop=True)

Làm thế nào là khác bất kỳ bài viết khác?
DJK

1

Đây là một biến thể tôi phải giải quyết đó là giá trị chia sẻ: với mỗi chuỗi duy nhất trong columnAtôi muốn tìm chuỗi liên kết phổ biến nhất trong đó columnB.

df.groupby('columnA').agg({'columnB': lambda x: x.mode().any()}).reset_index()

Chọn .any()một nếu có một ràng buộc cho chế độ. (Lưu ý rằng việc sử dụng .any()trên Sê-ri ints sẽ trả về giá trị boolean thay vì chọn một trong số chúng.)

Đối với câu hỏi ban đầu, cách tiếp cận tương ứng đơn giản hóa thành

df.groupby('columnA').columnB.agg('max').reset_index().


0

Khi đã có bài đăng trả lời câu hỏi, tôi đã thực hiện một thay đổi nhỏ bằng cách thêm tên cột mà hàm max () được áp dụng để dễ đọc mã hơn.

df.groupby('A', as_index=False)['B'].max()

Vui lòng cung cấp thêm một chút bối cảnh cho câu trả lời của bạn, giải thích cách chúng hoạt động và lý do tại sao chúng vượt trội hoặc bổ sung cho câu trả lời đã có sẵn cho một câu hỏi. Nếu họ không cung cấp giá trị gia tăng, xin vui lòng không đăng câu trả lời bổ sung cho các câu hỏi cũ. Cuối cùng, vui lòng định dạng mã của bạn dưới dạng khối mã bằng cách thụt lề.
WhoIsJack

0

Cách dễ nhất để làm điều này:

# First you need to sort this DF as Column A as ascending and column B as descending 
# Then you can drop the duplicate values in A column 
# Optional - you can reset the index and get the nice data frame again
# I'm going to show you all in one step. 

d = {'A': [1,1,2,3,1,2,3,1], 'B': [30, 40,50,42,38,30,25,32]}
df = pd.DataFrame(data=d)
df

    A   B
0   1   30
1   1   40
2   2   50
3   3   42
4   1   38
5   2   30
6   3   25
7   1   32


df = df.sort_values(['A','B'], ascending =[True,False]).drop_duplicates(['A']).reset_index(drop=True)

df

    A   B
0   1   40
1   2   50
2   3   42

-1

cái này cũng hoạt động:

a=pd.DataFrame({'A':a.groupby('A')['B'].max().index,'B':a.groupby('A')       ['B'].max().values})

Mặc dù đoạn mã này có thể giải quyết câu hỏi, bao gồm một lời giải thích thực sự giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn. Xin vui lòng cố gắng không làm đông mã của bạn với các bình luận giải thích, điều này làm giảm khả năng đọc của cả mã và các giải thích!
Martin Tournoij

-8

Tôi sẽ không cung cấp cho bạn toàn bộ câu trả lời (Tôi không nghĩ rằng bạn đang tìm kiếm phân tích cú pháp và viết thành một phần tệp), nhưng một gợi ý quan trọng nên đủ: sử dụng set()chức năng của python , và sau đó sorted()hoặc .sort()kết hợp với .reverse():

>>> a=sorted(set([10,60,30,10,50,20,60,50,60,10,30]))
>>> a
[10, 20, 30, 50, 60]
>>> a.reverse()
>>> a
[60, 50, 30, 20, 10]

8
Có thể tôi đã sai về điều này, nhưng việc lấy lại một DataFrame của gấu trúc như một bộ, sau đó chuyển đổi nó trở lại có vẻ như là một cách rất không hiệu quả để giải quyết vấn đề này. Tôi đang thực hiện phân tích nhật ký, vì vậy tôi sẽ áp dụng điều này cho một số tập dữ liệu rất lớn.
Abe

Xin lỗi, tôi không biết quá nhiều về kịch bản cụ thể này, vì vậy có thể câu trả lời chung chung của tôi sẽ không quá hiệu quả cho vấn đề của bạn.
Abhranil Das
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.