Verwijder duplicaten van kolom A, waarbij de rij met de hoogste waarde in kolom B behouden blijft

Ik heb een dataframe met herhalingswaarden in kolom A. Ik wil duplicaten verwijderen en de rij met de hoogste waarde in kolom B behouden.

Dus dit:

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

Moet dit worden:

A B
1 20
2 40
3 10

Ik vermoed dat er waarschijnlijk een gemakkelijke manier is om dit te doen – misschien net zo eenvoudig als het DataFrame sorteren voordat duplicaten worden verwijderd – maar ik ken de interne logica van groupby niet goed genoeg om erachter te komen. Suggesties?


Antwoord 1, autoriteit 100%

Dit duurt de laatste. Maar niet het maximum:

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

Je kunt ook zoiets doen als:

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

Antwoord 2, autoriteit 45%

Het beste antwoord is te veel werk doen en lijkt erg traag te zijn voor grotere datasets. applyis traag en moet indien mogelijk worden vermeden. ixis verouderd en moet ook worden vermeden.

df.sort_values('B', ascending=False).drop_duplicates('A').sort_index()
   A   B
1  1  20
3  2  40
4  3  10

Of groepeer gewoon op alle andere kolommen en neem het maximum van de kolom die u nodig heeft. df.groupby('A', as_index=False).max()


Antwoord 3, autoriteit 13%

Eenvoudigste oplossing:

Duplicaten verwijderen op basis van één kolom:

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

Duplicaten verwijderen op basis van meerdere kolommen:

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

Antwoord 4, autoriteit 6%

Ik zou het dataframe eerst sorteren met kolom B aflopend, dan duplicaten voor kolom A neerzetten en eerst bewaren

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

zonder groupby


Antwoord 5, autoriteit 3%

Probeer dit:

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

Antwoord 6

Ik denk dat je in jouw geval niet echt een groupby nodig hebt. Ik zou sorteren in aflopende volgorde van je B-kolom, dan duplicaten neerzetten in kolom A en als je wilt kun je ook een nieuwe mooie en
schone index op die manier:

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

Antwoord 7

Ik ben hierheen gebracht via een link van een dubbele vraag.

Voor slechts twee kolommen, zou het niet eenvoudiger zijn om te doen:

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

En om een ​​volledige rij te behouden (wanneer er meer kolommen zijn, wat de “dubbele vraag” was die me hier bracht):

df.loc[df.groupby(...)[column].idxmax()]

Als we bijvoorbeeld de volledige rij willen behouden waar 'C'zijn maximum neemt, voor elke groep van ['A', 'B'], zouden we doen :

out = df.loc[df.groupby(['A', 'B')['C'].idxmax()]

Als er relatief weinig groepen zijn (dwz veel duplicaten), is dit sneller dan de drop_duplicates()oplossing(minder sorteren):

Instellen:

n = 1_000_000
df = pd.DataFrame({
    'A': np.random.randint(0, 20, n),
    'B': np.random.randint(0, 20, n),
    'C': np.random.uniform(size=n),
    'D': np.random.choice(list('abcdefghijklmnopqrstuvwxyz'), size=n),
})

(Toevoegen van sort_index()om een ​​gelijke oplossing te garanderen):

%timeit df.loc[df.groupby(['A', 'B'])['C'].idxmax()].sort_index()
# 101 ms ± 98.7 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit df.sort_values(['C', 'A', 'B'], ascending=False).drop_duplicates(['A', 'B']).sort_index()
# 667 ms ± 784 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

Antwoord 8

Je kunt dit ook proberen

df.drop_duplicates(subset='A', keep='last')

Ik verwees dit naar https://pandas .pydata.org/pandas-docs/stable/generated/pandas.DataFrame.drop_duplicates.html


Antwoord 9

Hier is een variatie die ik moest oplossen en die het delen waard is: voor elke unieke string in columnAwilde ik de meest voorkomende bijbehorende string in columnBvinden.

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

De .any()kiest er een als de modus gelijk is. (Merk op dat het gebruik van .any()op een reeks ints een boolean retourneert in plaats van er een te kiezen.)

Voor de oorspronkelijke vraag vereenvoudigt de corresponderende benadering om

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


Antwoord 10

Gemakkelijkste manier om dit te doen:

# 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

Antwoord 11

Toen reeds gegeven berichten de vraag beantwoorden, heb ik een kleine wijziging aangebracht door de kolomnaam toe te voegen waarop de max()-functie wordt toegepast voor een betere leesbaarheid van de code.

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

Antwoord 12

dit werkt ook:

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

Antwoord 13

Ik ga je niet het hele antwoord geven (ik denk toch niet dat je op zoek bent naar het parseren en schrijven naar het bestandgedeelte), maar een cruciale hint zou voldoende moeten zijn: gebruik de set()functie, en dan sorted()of .sort()gekoppeld aan .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]

Other episodes