python pandaları: Yinelenenleri A sütunlarına göre kaldırarak B sütununda en yüksek değere sahip satırı koruyun


162

A sütununda tekrar değerleri olan bir veri çerçevesi var. B sütununda en yüksek değere sahip satırı tutarak yinelenenleri bırakmak istiyorum.

Yani bu:

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

Buna dönüşmeli:

A B
1 20
2 40
3 10

Wes, kopyaları bırakmak için bazı güzel işlevler ekledi: http://wesmckinney.com/blog/?p=340 . Ancak AFAICT, kesin kopyalar için tasarlanmıştır, bu nedenle hangi satırların tutulacağını seçmek için kriterlerden bahsedilmez.

Muhtemelen bunu yapmanın kolay bir yolu var --- belki yinelenenleri bırakmadan önce veri çerçevesini sıralamak kadar kolay - ama bunu anlamak için yeterince groupby'nin iç mantığını bilmiyorum. Baska öneri?


1
Sorudaki URL'nin EOL görüntülendiğini unutmayın.
DaveL17

Deyimsel ve performanssal bir yol için, aşağıdaki bu çözüme bakın .
Ted Petrou

Yanıtlar:


194

Bu sonuncusu alır. Yine de maksimum değil:

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

Ayrıca şöyle bir şey yapabilirsiniz:

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
Küçük not: colsve take_lastparametreleri amortismana tabi tutuldu ve yerine subsetve keepparametreleri getirildi . pandas.pydata.org/pandas-docs/version/0.17.1/generated/…
Jezzamon

@Jezzamon diyor ki,FutureWarning: the take_last=True keyword is deprecated, use keep='last' instead
tumultous_rooster

1
Kullanmamanın bir nedeni var mı df.sort_values(by=['B']).drop_duplicates(subset=['A'], keep='last')? Demek istediğim bu sort_values ​​benim için güvenli görünüyor ama aslında olup olmadığı hakkında hiçbir fikrim yok.
Küçük Bobby Masaları

4
Bu cevap şimdi kullanılmıyor. Aşağıdaki @Ted Petrou'nun cevabına bakınız.
cxrodgers

Bu kodu kullanmak istiyorsanız, ancak içinde birden fazla sütun olması durumunda group_by, ekleyebilirsiniz. .reset_index(drop=True) df.groupby(['A','C'], group_keys=False).apply(lambda x: x.ix[x.B.idxmax()]).reset_index(drop=True)Bu, varsayılan değeri bir Multindex tarafından oluşturulacak şekilde dizini sıfırlar 'A've'C'
Hamri Said

79

En iyi cevap çok fazla iş yapmak ve daha büyük veri kümeleri için çok yavaş görünüyor. applyyavaştır ve mümkünse kaçınılmalıdır. ixkullanımdan kaldırılmıştır ve bunlardan da kaçınılmalıdır.

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

   A   B
1  1  20
3  2  40
4  3  10

Veya diğer tüm sütunlara göre gruplandırın ve ihtiyacınız olan sütunun maks. df.groupby('A', as_index=False).max()


1
Bu aslında anlaşılır bir yaklaşımdır. Düşerken bazı lambaişlevler kullanarak genelleştirilip genelleştirilemeyeceğini merak ediyordum . Örneğin, yalnızca bu yinelenen değerlerin ortalamasından daha az değerleri nasıl düşürebilirim.
Dexter

16

En basit çözüm:

Bir sütuna göre kopyaları bırakmak için:

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

Birden çok sütuna dayalı kopyaları bırakmak için:

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

1
En iyi çözüm. Teşekkürler.
Flavio

Yardımcı olduğuma sevindim. @Flavio
Gil Baggio

Veri çerçevemde 10 sütun var ve bu kodu üç sütundan kopyaları silmek için kullandım. Ancak, sütunların geri kalanından satırları sildi. Yinelenenleri yalnızca son 4 sütun için silmenin bir yolu var mı?
Sofya

2
Ancak OP, B sütununda en yüksek değeri korumak istiyor. Ama sonra temelde Ted Petrou'nun cevabı.
Teepeemm

7

Bunu dene:

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

1
Orijinal DataFrame gibi görünecek şekilde yeniden endekslemek için en iyi deyimi biliyor musunuz? Beni ninja ettiğinde bunu anlamaya çalışıyordum. : ^)
DSM

4
Temiz. Veri çerçevesi daha fazla sütun içeriyorsa (örn. C, D, E)? Max bu durumda çalışmıyor gibi görünüyor, çünkü B'nin maksimize edilmesi gereken tek sütun olduğunu belirtmemiz gerekiyor.
Abe

1
@DSM Orijinal sorudaki bağlantıyı kontrol edin. Gruplandırılmış veri çerçevesini yeniden endekslemek için bazı kodlar vardır.
Abe

5

Önce Sütun B azalan veri çerçevesini sıralar, sonra Sütun A için kopyaları bırakır ve önce tutarım

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

grupsuz



1

Bence senin durumunda gerçekten bir gruba ihtiyacın yok. B sütununu azalan sıraya göre sıralar, daha sonra A sütununa kopyaları bırakırsınız ve isterseniz böyle yeni ve güzel bir dizine sahip olabilirsiniz:

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

bu diğer yayınlardan nasıl farklı?
DJK

1

İşte paylaşmaya değer çözmek zorunda bir varyasyon: içinde her benzersiz dize columnAiçin en yaygın ilişkili dize bulmak istedim columnB.

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

.any()Modu için bir beraberliğin olanı seçer. ( .any()Bir Seri ints'de kullanmanın bunlardan birini seçmek yerine bir boole döndürdüğünü unutmayın .)

Orijinal soru için, karşılık gelen yaklaşım

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


0

Zaten verilen mesajlar soruyu cevapladığında, daha iyi kod okunabilirliği için max () işlevinin uygulandığı sütun adını ekleyerek küçük bir değişiklik yaptım.

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

Lütfen cevaplarınızla nasıl çalıştıklarını ve bir soru için halihazırda mevcut olan cevaplardan neden daha üstün veya tamamlayıcı olduklarını açıklayarak biraz daha bağlam verin. Eğer katma değer sağlamazlarsa, lütfen eski sorulara ek cevaplar vermekten kaçının. Son olarak, lütfen kodunuzu girintili olarak bir kod bloğu olarak biçimlendirin .
WhoIsJack

0

Bunu yapmanın en kolay yolu:

# 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

bu da işe yarar:

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

Bu kod snippet'i soruyu çözebilir, ancak bir açıklama da dahil olmak üzere , yayınınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın. Lütfen kodunuzu açıklayıcı yorumlarla doldurmamaya çalışın, bu hem kodun hem de açıklamaların okunabilirliğini azaltır!
Martin Tournoij

-8

Size tüm cevabı vermeyeceğim (yine de dosya parçasına ayrıştırma ve yazma aradığınızı düşünmüyorum), ancak önemli bir ipucu yeterli olmalıdır: python set()işlevini kullanın ve sonra sorted()veya ile .sort()birleştiğinde .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
Belki bu konuda yanılıyorum, ama bir panda DataFrame bir set olarak yeniden, sonra geri dönüştürmek bu sorunu çözmek için çok verimsiz bir yol gibi görünüyor. Günlük analizi yapıyorum, bu yüzden bunu çok büyük veri setlerine uygulayacağım.
Abe

Maalesef, bu özel senaryo hakkında fazla bir şey bilmiyorum, bu yüzden genel cevabım probleminiz için çok verimli olmayacak olabilir.
Abhranil Das
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.