2016-06-12 2 views
1

Я хотел бы сделать следующее:Удаление дублирующихся строк, но сохранить те, с определенным значением в одной колонке (панды питон)

Если две строки имеют точно такое же значение, в 3-х столбцов («ID»,» символ "и" дата ") и имеют либо« X », либо« T »в одном столбце (« сообщение »), затем удалите обе эти строки. Однако, если две строки имеют одинаковое значение в одних и тех же 3 столбцах, но значение, отличное от «X» или «T» в другом столбце, затем оставить без изменений.

Вот пример моего фрейма данных:

df = pd.DataFrame({"ID":["AA-1", "AA-1", "C-0" ,"BB-2", "BB-2"], "symbol":["A","A","C","B","B"], "date":["06/24/2014","06/24/2014","06/20/2013","06/25/2014","06/25/2015"], "message": ["T","X","T","",""] }) 

Обратите внимание, что первые две строки имеют одинаковые значения значений для столбцов «ID», «символ», и «дата», и «Т "и" X "в столбце" message ". Я хотел бы удалить эти две строки.

Однако последние две строки имеют одинаковое значение в столбцах «ID», «символ» и «дата», но пустое (отличное от «X» или «T») в столбце «сообщение».

Я заинтересован в применении функции к большому набору данных с несколькими миллионами строк. До сих пор, что я пытался поглощает всю мою память,

спасибо, и я признателен за любую помощь,

+0

Просто поясните - хотите ли вы сохранить повторяющиеся строки в случае, если их больше 2? – Stefan

+0

Я должен, вероятно, сделать это более ясным в своем вопросе. Мои данные попадают парами.Для каждой строки «Х» существует (или, по крайней мере, должна быть) ровно одна строка «Т» с другими столбцами, равными, за исключением столбца «сообщение». В этом случае, по крайней мере, если данные были собраны правильно, должны быть только пары совпадающих наблюдений. – dleal

ответ

0

Это может работать для вас:

vals = ['X', 'T'] 
pd.concat([df[~df.message.isin(vals)], df[df.message.isin(vals)].loc[~df.duplicated(subset=['ID', 'date', 'symbol'], keep=False), :]]) 

    ID  date message symbol 
3 BB-2 06/25/2014    B 
4 BB-2 06/25/2015    B 
2 C-0 06/20/2013  T  C 

Это достаточно быстро:

%%timeit 
pd.concat([df[~df.message.isin(['X', 'T'])], df[df.message.isin(['X', 'T'])].loc[~df.duplicated(subset=['ID', 'date', 'symbol'], keep=False), :]]) 
100 loops, best of 3: 1.99 ms per loop 

%%timeit 
df.groupby(['ID','date','symbol']).filter(lambda x: ~x.message.isin(['T','X']).all()) 
100 loops, best of 3: 2.71 ms per loop 

Альтернативой давал ошибки индексирования.

+0

Существует проблема с 'Если две строки имеют точно такое же значение в ...' - ваш фильтр решения дублирует строки, а не только длиной 2. – jezrael

+0

Правильно, я просто следовал инструкции заголовка. Давайте посмотрим, что требуется. Мой ответ не поможет, если OP хочет сохранить дублированные строки, если их больше 2. – Stefan

+0

Функция concat выполняется значительно быстрее, чем группа в этом случае – dleal

0

Я думаю, что вы можете использовать groupby с filter - условия - не 2 строк с повторяющимися значениями и столбца message в группах isin не значения T или X:

import pandas as pd 

df = pd.DataFrame({"ID":["AA-1", "AA-1", "C-0" ,"BB-2", "BB-2"], 
        "symbol":["A","A","C","B","B"], 
        "date":["06/24/2014","06/24/2014","06/20/2013","06/25/2015","06/25/2015"], 
        "message": ["T","X","T","",""] }) 
print (df) 
    ID  date message symbol 
0 AA-1 06/24/2014  T  A 
1 AA-1 06/24/2014  X  A 
2 C-0 06/20/2013  T  C 
3 BB-2 06/25/2015    B 
4 BB-2 06/25/2015    B 

df1 = df.groupby(['ID','date','symbol']).filter(lambda x: ~((len(x) == 2) & 
                  (x.message.isin(['T','X']).all()))) 
print (df1) 
    ID  date message symbol 
2 C-0 06/20/2013  T  C 
3 BB-2 06/25/2015    B 
4 BB-2 06/25/2015    B 

Filtration in docs.

EDIT по comment:

import pandas as pd 

df = pd.DataFrame({"ID":["AA-1", "AA-1", "C-0", "C-0","BB-2", "BB-2"], 
        "symbol":["A","A","C","C", "B","B"], 
        "date":["06/24/2014","06/24/2014","06/20/2013","06/20/2013","06/25/2015","06/25/2015"], 
        "message": ["T","X","X","X","",""] }) 
print (df) 
    ID  date message symbol 
0 AA-1 06/24/2014  T  A 
1 AA-1 06/24/2014  X  A 
2 C-0 06/20/2013  X  C 
3 C-0 06/20/2013  X  C 
4 BB-2 06/25/2015    B 
5 BB-2 06/25/2015    B 

Если необходимо удалить значения с X или T в каждой группе - это означает, что удалить двойной X или двойной T тоже и каждый len каждой группы всегда 2:

df1 = df.groupby(['ID','date','symbol']).filter(lambda x: ~x.message.isin(['T','X']).all()) 
print (df1) 
    ID  date message symbol 
4 BB-2 06/25/2015    B 
5 BB-2 06/25/2015    B 

Если вам нужно удалить только группы, в которых значения T и X, вы должны нажать может сначала sort_values по message, а затем filter, проверив, имеет ли первое значение T и второе X в каждой группе. ('T' является первым и X является вторым, так как сортировка):

df2 = df.sort_values('message') 
     .groupby(['ID','date','symbol'], sort=False) 
     .filter(lambda x: ((x.message.iloc[0] != 'T') | (x.message.iloc[1] != 'X'))) 
print (df2) 
    ID  date message symbol 
4 BB-2 06/25/2015    B 
5 BB-2 06/25/2015    B 
2 C-0 06/20/2013  X  C 
3 C-0 06/20/2013  X  C 
Смежные вопросы