Удаление дубликатов только внутри групп
Я хочу удалить дубликаты только в определенных подмножествах из фрейма данных. Под каждой "спецификацией" в столбце "A" я хочу отбросить дубликаты, но хочу сохранить дубликаты во всем фрейме данных (возможно иметь несколько строк под первой "спецификацией", которые совпадают со строками под вторая "спекуляция", но под "спекуляция" до следующей "спекуляции" хочу отбросить дубликаты)
Это фрейм данных
Д.Ф.
A B C
spec first second
test text1 text2
act text12 text13
act text14 text15
test text32 text33
act text34 text35
test text85 text86
act text87 text88
test text1 text2
act text12 text13
act text14 text15
test text85 text86
act text87 text88
spec third fourth
test text1 text2
act text12 text13
act text14 text15
test text85 text86
act text87 text88
test text1 text2
act text12 text13
act text14 text15
test text85 text86
act text87 text88
и вот чего я хочу:
Д.Ф.
A B C
spec first second
test text1 text2
act text12 text13
act text14 text15
test text32 text33
act text34 text35
test text85 text86
act text87 text88
spec third fourth
test text1 text2
act text12 text13
act text14 text15
test text85 text86
act text87 text88
Я мог бы разделить фрейм данных на "маленькие" фреймы данных, а затем создать дубликаты для удаления цикла для каждого из "маленьких" фреймов данных и, наконец, объединить их, но мне интересно, есть ли какое-либо другое решение.
Я попробовал также и получилось:
dfList = df.index[df["A"] == "spec"].tolist()
dfList = np.asarray(dfList)
for dfL in dfList:
idx = np.where(dfList == dfL)
if idx[0][0]!=(len(dfList)-1):
df.loc[dfList[idx[0][0]]:dfList[idx[0][0]+1]-1]
= df.loc[dfList[idx[0][0]]:dfList[idx[0][0]+1]-1].drop_duplicates()
else:
df.loc[dfList[idx[0][0]]:] = df.loc[dfList[idx[0][0]]:].drop_duplicates()
РЕДАКТИРОВАТЬ: я должен добавить это до конца:
df.dropna (how = 'all', inplace = True)
Но мне просто интересно, есть ли другое решение.
3 ответа
Использование groupby
+ duplicated
:
df[~df.groupby(df.A.eq('spec').cumsum()).apply(lambda x: x.duplicated()).values]
A B C
0 spec first second
1 test text1 text2
2 act text12 text13
3 act text14 text15
4 test text32 text33
5 act text34 text35
6 test text85 text86
7 act text87 text88
13 spec third fourth
14 test text1 text2
15 act text12 text13
16 act text14 text15
17 test text85 text86
18 act text87 text88
подробности
Мы находим все строки в определенной записи "spec", используя cumsum
, Метки группы:
df.A.eq('spec').cumsum()
0 1
1 1
2 1
3 1
4 1
5 1
6 1
7 1
8 1
9 1
10 1
11 1
12 1
13 2
14 2
15 2
16 2
17 2
18 2
19 2
20 2
21 2
22 2
23 2
Name: A, dtype: int64
Затем в этой серии выполняется группировка, и для каждой группы вычисляются дубликаты:
df.groupby(df.A.eq('spec').cumsum()).apply(lambda x: x.duplicated()).values
array([False, False, False, False, False, False, False, False, True,
True, True, True, True, False, False, False, False, False,
False, True, True, True, True, True])
Исходя из этого, все, что осталось, - это сохранить те строки, которые соответствуют "False" (то есть не дублированы).
Это должно работать:
df2 = df.drop_duplicates(subset=['A', 'B','C'])
Другое возможное решение может быть... Вы можете иметь счетчик и создать новый столбец из столбца A со значением счетчика, всякий раз, когда вы сталкиваетесь со спецификацией в значении столбца, вы увеличиваете значение счетчика.
counter = 0
def counter_fun(val):
if val == 'spec': counter+=1
return counter
df['new_col'] = df.A.apply(counter_fun)
Затем сгруппируйте на new_col и удалите дубликаты.