python pandas : 열 A에서 중복을 제거하고 열 B에서 가장 높은 값을 유지


162

열 A에 반복 값이있는 데이터 프레임이 있습니다. 열 B를 가장 높은 값으로 유지하면서 중복을 삭제하고 싶습니다.

그래서 이거:

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

이것으로 바꿔야합니다 :

A B
1 20
2 40
3 10

Wes는 중복을 제거하는 몇 가지 훌륭한 기능을 추가했습니다. http://wesmckinney.com/blog/?p=340 . 그러나 AFAICT는 정확한 복제를 위해 설계되었으므로 유지할 행을 선택하는 기준에 대한 언급은 없습니다.

중복을 삭제하기 전에 데이터 프레임을 정렬하는 것만큼이나 쉬운 방법이있을 것입니다.하지만 그룹 별 내부 논리를 잘 알지 못합니다. 어떤 제안?


1
질문의 URL이 EOL로 나타납니다.
DaveL17

관용적이고 성능이 좋은 방법은 아래이 솔루션을 참조하십시오 .
Ted Petrou

답변:


194

마지막이 걸립니다. 그러나 최대 값은 아닙니다.

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

다음과 같은 작업을 수행 할 수도 있습니다.

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
작은 참고 : colstake_last매개 변수는 감가 상각하고 의해 대체되었습니다 subsetkeep매개 변수를 설정합니다. pandas.pydata.org/pandas-docs/version/0.17.1/generated/…
Jezzamon

@Jezzamon이 말했듯이FutureWarning: the take_last=True keyword is deprecated, use keep='last' instead
tumultous_rooster

1
사용하지 않는 이유가 df.sort_values(by=['B']).drop_duplicates(subset=['A'], keep='last')있습니까? 나는이 sort_values가 안전 해 보이지만 실제로 그것이 사실인지 전혀 모른다.
Little Bobby Tables

4
이 답변은 이제 더 이상 사용되지 않습니다. 아래의 @Ted Petrou의 답변을 참조하십시오.
cxrodgers

당신은 하나 개 이상의 컬럼의 경우이 코드 만 사용하려는 경우 group_by, 당신은 추가 할 수 있습니다 .reset_index(drop=True) df.groupby(['A','C'], group_keys=False).apply(lambda x: x.ix[x.B.idxmax()]).reset_index(drop=True)이것은 Multindex이 될 것입니다 기본 값으로 인덱스를 재설정에서 compsed 'A''C'
함리 말했다

79

가장 큰 대답은 너무 많은 작업을 수행하고 있으며 더 큰 데이터 세트에 대해서는 매우 느리게 보입니다. apply느리고 가능한 경우 피해야합니다. ix더 이상 사용되지 않으며 피해야합니다.

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

   A   B
1  1  20
3  2  40
4  3  10

또는 다른 모든 열을 기준으로 그룹화하고 필요한 열을 최대한 활용하십시오. df.groupby('A', as_index=False).max()


1
이것은 실제로 식칼 접근 방식입니다. lamba떨어 뜨리는 동안 일부 기능을 사용하여 일반화 할 수 있는지 궁금합니다 . 예를 들어 중복 값의 평균보다 작은 값만 삭제하는 방법은 무엇입니까?
Dexter

16

가장 간단한 해결책 :

한 열을 기준으로 중복을 삭제하려면

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

여러 열을 기준으로 중복을 삭제하려면

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

1
최고의 솔루션. 감사.
Flavio

기쁘다. @Flavio
길 바기오

내 데이터 프레임에는 10 개의 열이 있으며이 코드를 사용하여 3 개의 열에서 중복 항목을 삭제했습니다. 그러나 나머지 열에서 행을 삭제했습니다. 마지막 4 개의 열에 대해서만 중복을 삭제하는 방법이 있습니까?
Sofia

2
그러나 OP는 B 열에서 가장 높은 값을 유지하려고합니다. 먼저 정렬하면 효과가있을 수 있습니다. 그러나 그것은 기본적으로 Ted Petrou의 대답입니다.
Teepeemm

7

이 시도:

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

1
원본 DataFrame처럼 보이도록 다시 인덱싱하는 가장 좋은 관용구를 알고 있습니까? 당신이 닌자 일 때 알아 냈어요. : ^)
DSM

4
산뜻한. 데이터 프레임에 더 많은 열 (예 : C, D, E)이 포함되어 있으면 어떻게됩니까? 이 경우 Max가 작동하지 않는 것 같습니다. B가 최대화해야하는 유일한 열임을 지정해야하기 때문입니다.
Abe

1
@DSM 원래 질문의 링크를 확인하십시오. 그룹화 된 데이터 프레임을 재 인덱싱하는 코드가 있습니다.
아베

5

먼저 B 열을 내림차순으로 데이터 프레임을 정렬 한 다음 A 열에 대해 중복을 삭제하고 먼저 유지하십시오.

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

어떤 그룹없이



1

나는 당신의 경우에 당신은 정말로 그룹별로 필요하지 않다고 생각합니다. 나는 B 열을 내림차순으로 정렬 한 다음 A 열에서 중복을 삭제하고 원하는 경우 다음과 같이 새롭고 깔끔한 인덱스를 가질 수 있습니다.

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

이것은 다른 게시물과 어떻게 다릅니 까?
DJK

1

공유 할 가치가있는 변형이 있습니다. 각 고유 한 문자열에 대해 columnA에서 가장 일반적인 관련 문자열을 찾고 싶었습니다 columnB.

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

.any()모드의 넥타이가 있다면 하나를 선택합니다. ( .any()시리즈의int s 하면 부울 중 하나를 선택하지 않고 부울이 반환됩니다.

원래 질문의 경우 해당 접근법이 단순화됩니다.

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


0

이미 주어진 게시물이 질문에 대답했을 때 더 나은 코드 가독성을 위해 max () 함수가 적용되는 열 이름을 추가하여 약간 변경했습니다.

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

답변의 맥락과 답변의 작동 방식 및 질문에 이미 사용 가능한 답변보다 우수하거나 보완적인 이유를 설명하십시오. 추가 가치를 제공하지 않으면 이전 질문에 대한 추가 답변을 게시하지 마십시오. 마지막으로 코드를 들여 써서 코드 블록으로 포맷 하십시오.
WhoIsJack 2016 년

0

가장 쉬운 방법은 :

# 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

이것은 또한 작동합니다 :

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

이 코드 스 니펫은 문제를 해결할 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 실제로 도움이됩니다. 앞으로 독자들에게 질문에 대한 답변을 제공하므로 해당 사람들이 코드 제안의 이유를 모를 수도 있습니다. 설명 주석으로 코드를 복잡하게 만들지 마십시오. 이렇게하면 코드와 설명의 가독성이 떨어집니다!
Martin Tournoij

-8

나는 당신에게 전체적인 대답을주지 않을 것입니다 (어쨌든 파일 부분을 파싱하고 쓰는 것을 생각하지 않는다고 생각합니다).하지만 중요한 힌트로 충분해야합니다 : 파이썬 set()기능을 사용 하고 다음 sorted().sort()결합하십시오 .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
어쩌면 나는 이것에 잘못되었지만 팬더 DataFrame을 세트로 다시 캐스팅 한 다음 다시 변환하면이 문제를 해결하는 매우 비효율적 인 방법처럼 보입니다. 로그 분석을 수행하고 있으므로이를 매우 큰 데이터 세트에 적용 할 것입니다.
Abe

죄송합니다.이 특정 시나리오에 대해 너무 많이 알지 못하므로 일반적인 대답이 귀하의 문제에 비해 너무 효율적이지 않을 수 있습니다.
Abhranil Das
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.