Панды - напротив дубликатов капель, держите первым - PullRequest
2 голосов
/ 12 марта 2019

Я знаком с тем, как отбрасывать дублирующиеся строки, а затем использовать параметр first, last, none.Ничего сложного в этом нет, и есть множество примеров (например, здесь ).

Однако, я ищу способ найти дубликаты, но вместо удаления всех дубликатови сохраняя первое, если у меня есть дубликаты, оставьте все дубликаты, но отбросьте первое:

Так что вместо «отбросить дубликаты, оставьте первое», я хочу «сохранить, если дубликаты, сначала убрать»

Пример:

Учитывая этот кадр данных и просматривая дубликаты в столбце cost:

    ID name type cost
0    0    a   bb    1
1    1    a   cc    2 <--- there are duplicates, so drop this row
2  1_0    a   dd    2
3    2    a   ee    3 <--- there are duplicates, so drop this row
4  2_0    a   ff    3
5  2_1    a   gg    3
6  2_2    a   hh    3

Если в столбце cost есть дубликаты, просто отбросьте первое вхождение, но оставьте все остальное.

Таким образом, мой вывод будет:

    ID name type cost
0    0    a   bb    1
2  1_0    a   dd    2
4  2_0    a   ff    3
5  2_1    a   gg    3
6  2_2    a   hh    3

Вот пример кадра данных:

import pandas as pd

df = pd.DataFrame([
['0',   'a',    'bb',   '1'],
['1',   'a',    'cc',   '2'],
['1_0', 'a',    'dd',   '2'],
['2',   'a',    'ee',   '3'],
['2_0', 'a',    'ff',   '3'],
['2_1', 'a',    'gg',   '3'],
['2_2', 'a',    'hh',   '3']], columns = ['ID', 'name', 'type', 'cost'])

Ответы [ 3 ]

2 голосов
/ 12 марта 2019

Вы можете связать 2 маски, созданные DataFrame.duplicated с побитовым OR и фильтровать по boolean indexing:

df = df[df.duplicated('cost') | ~df.duplicated('cost', keep=False)]
print (df)
    ID name type cost
0    0    a   bb    1
2  1_0    a   dd    2
4  2_0    a   ff    3
5  2_1    a   gg    3
6  2_2    a   hh    3

Detail

print (df.assign(mask1=df.duplicated('cost'), mask2=~df.duplicated('cost', keep=False)))
    ID name type cost  mask1  mask2
0    0    a   bb    1  False   True
1    1    a   cc    2  False  False
2  1_0    a   dd    2   True  False
3    2    a   ee    3  False  False
4  2_0    a   ff    3   True  False
5  2_1    a   gg    3   True  False
6  2_2    a   hh    3   True  False
1 голос
/ 12 марта 2019

Вы можете использовать groupby и передать лямбда-функцию, чтобы получить записи после первого дублирования, если дублирование существует:

>>> df.groupby('cost').apply(lambda group: group.iloc[1:] if len(group) > 1 else group).reset_index(drop=True)
    ID  cost name type
0    0     1    a   bb
1  1_0     2    a   dd
2  2_0     3    a   ff
3  2_1     3    a   gg
4  2_2     3    a   hh
1 голос
/ 12 марта 2019

Вы можете сделать следующее с оператором XOR (^), который ищет оба условия как True.Так как мы используем оператор NOT (~).Он ищет противоположность, например: оба False:

df[~(df.cost.duplicated(keep=False) ^ df.cost.duplicated())]

Выход

    ID name type cost
0    0    a   bb    1
2  1_0    a   dd    2
4  2_0    a   ff    3
5  2_1    a   gg    3
6  2_2    a   hh    3
...