python panda: Hapus duplikat dengan kolom A, pertahankan baris dengan nilai tertinggi di kolom B


161

Saya memiliki kerangka data dengan nilai berulang di kolom A. Saya ingin menjatuhkan duplikat, menjaga baris dengan nilai tertinggi di kolom B.

Jadi ini:

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

Harus berubah menjadi ini:

A B
1 20
2 40
3 10

Wes telah menambahkan beberapa fungsionalitas yang bagus untuk menjatuhkan duplikat: http://wesmckinney.com/blog/?p=340 . Tapi AFAICT, ini dirancang untuk duplikat yang tepat, jadi tidak disebutkan kriteria untuk memilih baris mana yang disimpan.

Saya menduga mungkin ada cara mudah untuk melakukan ini --- mungkin semudah mengurutkan dataframe sebelum menjatuhkan duplikat --- tapi saya tidak tahu logika internal groupby cukup baik untuk mengetahuinya. Ada saran?


1
Perhatikan bahwa URL dalam pertanyaan muncul EOL.
DaveL17

Untuk cara idiomatis dan performan, lihat solusi ini di bawah .
Ted Petrou

Jawaban:


194

Ini yang terakhir. Tidak maksimal:

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

Anda juga dapat melakukan sesuatu seperti:

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
Catatan kecil: colsdan take_lastparameter disusutkan dan telah digantikan oleh subsetdan keepparameter. pandas.pydata.org/pandas-docs/version/0.17.1/generated/…
Jezzamon

seperti yang dikatakan @Jezzamon,FutureWarning: the take_last=True keyword is deprecated, use keep='last' instead
tumultous_rooster

1
Apakah ada alasan untuk tidak menggunakan df.sort_values(by=['B']).drop_duplicates(subset=['A'], keep='last')? Maksud saya sort_values ​​ini tampaknya aman bagi saya, tetapi saya tidak tahu apakah itu benar-benar aman.
Little Bobby Tables

4
Jawaban ini sekarang sudah usang. Lihat jawaban @Ted Petrou di bawah ini.
cxrodgers

Jika Anda ingin menggunakan kode ini tetapi dengan huruf lebih dari satu kolom di group_by, Anda dapat menambahkan .reset_index(drop=True) df.groupby(['A','C'], group_keys=False).apply(lambda x: x.ix[x.B.idxmax()]).reset_index(drop=True)Ini akan mengatur ulang indeks karena nilai defaultnya adalah Multindex yang berasal dari 'A'dan'C'
Hamri Said

79

Jawaban teratas adalah melakukan terlalu banyak pekerjaan dan terlihat sangat lambat untuk set data yang lebih besar. applylambat dan harus dihindari jika memungkinkan. ixsudah usang dan harus dihindari juga.

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

   A   B
1  1  20
3  2  40
4  3  10

Atau cukup kelompokkan dengan semua kolom lain dan ambil maks kolom yang Anda butuhkan. df.groupby('A', as_index=False).max()


1
Ini sebenarnya adalah pendekatan golok. Saya bertanya-tanya apakah itu dapat digeneralisasi dengan menggunakan beberapa lambafungsi saat menjatuhkan. Misalnya bagaimana saya bisa menjatuhkan hanya nilai yang lebih rendah dari rata-rata nilai duplikat tersebut
Dexter

15

Solusi paling sederhana:

Untuk menjatuhkan duplikat berdasarkan satu kolom:

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

Untuk menjatuhkan duplikat berdasarkan beberapa kolom:

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

1
Solusi terbaik. Terima kasih.
Flavio

Senang untuk membantu. @Flavio
Gil Baggio

Kerangka data saya memiliki 10 kolom, dan saya menggunakan kode ini untuk menghapus duplikat dari tiga kolom. Namun, itu menghapus baris dari sisa kolom. Apakah ada cara untuk menghapus duplikat hanya untuk 4 kolom terakhir?
Sofia

2
Tetapi OP ingin mempertahankan nilai tertinggi di kolom B. Ini mungkin berhasil jika Anda mengurutkannya terlebih dahulu. Tapi pada dasarnya itulah jawaban Ted Petrou.
Teepeemm

7

Coba ini:

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

1
D'Anda tahu idiom terbaik untuk mengindeks ulang ini agar terlihat seperti DataFrame asli? Saya sedang berusaha mencari tahu ketika Anda ninja saya. : ^)
DSM

4
Rapi. Bagaimana jika kerangka data berisi lebih banyak kolom (misalnya C, D, E)? Max tampaknya tidak berfungsi dalam kasus itu, karena kita perlu menentukan bahwa B adalah satu-satunya kolom yang perlu dimaksimalkan.
Abe

1
@ DSM Periksa tautan di pertanyaan awal. Ada beberapa kode untuk mengindeks ulang kerangka data yang dikelompokkan.
Abe

5

Saya akan mengurutkan dataframe pertama dengan Kolom B turun, kemudian drop duplikat untuk Kolom A dan pertahankan terlebih dahulu

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

tanpa groupby



1

Saya pikir dalam kasus Anda, Anda tidak benar-benar membutuhkan grup. Saya akan menyortir dengan urutan menurun kolom B Anda, kemudian drop duplikat di kolom A dan jika Anda mau, Anda juga dapat memiliki indeks bagus dan bersih baru seperti itu:

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

bagaimana ini berbeda dari posting lain?
DJK

1

Berikut variasi yang harus saya pecahkan yang layak dibagikan: untuk setiap string unik di columnAsaya ingin menemukan string terkait yang paling umum columnB.

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

The .any()mengambil satu jika ada dasi untuk mode. (Perhatikan bahwa menggunakan .any()pada Seri ints mengembalikan boolean daripada memilih salah satunya.)

Untuk pertanyaan awal, pendekatan yang sesuai disederhanakan

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


0

Ketika sudah diberikan tulisan, jawab pertanyaan itu, saya membuat perubahan kecil dengan menambahkan nama kolom tempat fungsi max () diterapkan untuk keterbacaan kode yang lebih baik.

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

Tolong beri sedikit lebih banyak konteks untuk jawaban Anda, menjelaskan bagaimana mereka bekerja dan mengapa mereka lebih unggul atau melengkapi jawaban yang sudah tersedia untuk pertanyaan. Jika mereka tidak memberikan nilai tambah, harap jangan mengirim jawaban tambahan pada pertanyaan lama. Terakhir, harap format kode Anda sebagai blok kode dengan memberi indentasi.
WhoIsJack

0

Cara termudah untuk melakukan ini:

# 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

ini juga berfungsi:

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

Sementara potongan kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan sangat membantu untuk meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, dan orang-orang itu mungkin tidak tahu alasan untuk saran kode Anda. Tolong juga cobalah untuk tidak membuat kerumunan kode Anda dengan komentar penjelasan, ini mengurangi keterbacaan kode dan penjelasan!
Martin Tournoij

-8

Saya tidak akan memberikan Anda seluruh jawaban (saya tidak berpikir Anda sedang mencari bagian parsing dan menulis untuk mengajukan), tetapi petunjuk penting harus mencukupi: gunakan set()fungsi python , lalu sorted()atau .sort()ditambah dengan .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
Mungkin saya salah dalam hal ini, tetapi menyusun kembali panda DataFrame sebagai satu set, lalu mengubahnya kembali sepertinya cara yang sangat tidak efisien untuk menyelesaikan masalah ini. Saya sedang melakukan analisis log, jadi saya akan menerapkan ini pada beberapa set data yang sangat besar.
Abe

Maaf, saya tidak tahu terlalu banyak tentang skenario khusus ini, jadi mungkin jawaban generik saya tidak akan menjadi terlalu efisien untuk masalah Anda.
Abhranil Das
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.