Удаление дубликатов только внутри групп

Я хочу удалить дубликаты только в определенных подмножествах из фрейма данных. Под каждой "спецификацией" в столбце "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 и удалите дубликаты.

Другие вопросы по тегам