Как я могу получить все дубликаты во фрейме данных pandas, а также индекс строки, с которой он является копией?

#python #pandas #dataframe #duplicates

Вопрос:

У меня есть следующий список:

 data = [
  {"name":"John","subject":"Maths","marks":"99"},
  {"name":"John","subject":"English","marks":"95"},
  {"name":"John","subject":"Science","marks":"97"},
  {"name":"Robert","subject":"Maths","marks":"98"},
  {"name":"Robert","subject":"Maths","marks":"98"},
  {"name":"Robert","subject":"Science","marks":"89"},
  {"name":"Robert","subject":"English","marks":"92"},
  {"name":"Lucifer","subject":"Maths","marks":"98"},
  {"name":"Lucifer","subject":"Science","marks":"87"},
  {"name":"Lucifer","subject":"English","marks":"98"},
  {"name":"Lucifer","subject":"English","marks":"98"}
]
 

Я преобразовал его в фрейм данных pandas originalDF

originalDF = pd.DataFrame(data)

        name  subject marks
0      John    Maths    99
1      John  English    95
2      John  Science    97
3    Robert    Maths    98
4    Robert    Maths    98 (duplicate)
5    Robert  Science    89
6    Robert  English    92
7   Lucifer    Maths    98
8   Lucifer  Science    87
9   Lucifer  English    98
10  Lucifer  English    98 (duplicate)
 

Теперь я мог извлекать как уникальные строки, так и дублированные строки

 uniqueDF = originalDF.drop_duplicates()
duplicates = originalDF.duplicated()
duplicates = duplicates[duplicates == True]
duplicateDF = originalDF.loc[list(duplicates.index)]
 

Теперь у меня есть как уникальные строки uniqueDF , так и дублированные строки duplicateDF

 uniqueDF
      name  subject marks
0     John    Maths    99
1     John  English    95
2     John  Science    97
3   Robert    Maths    98
5   Robert  Science    89
6   Robert  English    92
7  Lucifer    Maths    98
8  Lucifer  Science    87
9  Lucifer  English    98

duplicateDF
       name  subject marks
4    Robert    Maths    98
10  Lucifer  English    98
 

Теперь я хочу добавить еще один столбец copyOf , в duplicateDF котором будет указан индекс его уникальной строки из unique DF. Я хочу, чтобы конечный результат был следующим:

        name  subject marks  copyof
4    Robert    Maths    98  3
10  Lucifer  English    98  9
 

Есть идеи, как это рассчитать? Заранее спасибо.

Ответ №1:

Вот решение для объединения всех дублированных значений индекса в новый столбец с join :

 c = originalDF.columns.tolist()
#filtered only duplciated rows
df = originalDF[originalDF.duplicated(keep=False)]

df = (df.rename(index=str)
        .reset_index()
        .groupby(c)
        .agg(copyof=('index',lambda x: ','.join(x[:-1])),
             orig=('index', 'last'))
        .reset_index()
        .set_index('orig'))

print (df)
         name  subject marks copyof
orig                               
10    Lucifer  English    98      9
4      Robert    Maths    98      3
 

Проверка на наличие нескольких значений:

 data = [
  {"name":"John","subject":"Maths","marks":"99"},
  {"name":"John","subject":"English","marks":"95"},
  {"name":"John","subject":"Science","marks":"97"},
  {"name":"Robert","subject":"Maths","marks":"98"},
  {"name":"Robert","subject":"Maths","marks":"98"},
  {"name":"Robert","subject":"Maths","marks":"98"},
  {"name":"Robert","subject":"Science","marks":"89"},
  {"name":"Robert","subject":"English","marks":"92"},
  {"name":"Lucifer","subject":"Maths","marks":"98"},
  {"name":"Lucifer","subject":"Science","marks":"87"},
  {"name":"Lucifer","subject":"English","marks":"98"},
  {"name":"Lucifer","subject":"English","marks":"98"}
]

originalDF = pd.DataFrame(data)
print (originalDF)
 

 c = originalDF.columns.tolist()
df = originalDF[originalDF.duplicated(keep=False)]

df = (df.rename(index=str)
        .reset_index()
        .groupby(c)
        .agg(copyof=('index',lambda x: ','.join(x[:-1])),
             orig=('index', 'last'))
        .reset_index()
        .set_index('orig'))

print (df)
         name  subject marks copyof
orig                               
11    Lucifer  English    98     10
5      Robert    Maths    98    3,4
 

Ответ №2:

Это работает, хотя-

*Предположение: каждая строка будет иметь только одну повторяющуюся строку вместе с ней.

 data = [
  {"name":"John","subject":"Maths","marks":"99"},
  {"name":"John","subject":"English","marks":"95"},
  {"name":"John","subject":"Science","marks":"97"},
  {"name":"Robert","subject":"Maths","marks":"98"},
  {"name":"Robert","subject":"Maths","marks":"98"},
  {"name":"Robert","subject":"Science","marks":"89"},
  {"name":"Robert","subject":"English","marks":"92"},
  {"name":"Lucifer","subject":"Maths","marks":"98"},
  {"name":"Lucifer","subject":"Science","marks":"87"},
  {"name":"Lucifer","subject":"English","marks":"98"},
  {"name":"Lucifer","subject":"English","marks":"98"},
]

originalDF = pd.DataFrame(data)

uniqueDF = originalDF.drop_duplicates()

duplicates = originalDF.duplicated(keep=False)
duplicates = duplicates[duplicates == True]
duplicateDF = originalDF.loc[list(duplicates.index)]
duplicateDF.reset_index(inplace=True)

duplicates = list()
for i, row in duplicateDF.iterrows():
    if i % 2 == 0:
        duplicates.append(row['index'])
        
duplicateDF_ = duplicateDF[np.arange(len(duplicateDF)) % 2 != 0]
duplicateDF_['copyof'] = duplicates
 

Комментарии:

1. Он может иметь любое количество дубликатов.

2. @Inamullah ответ, предоставленный пользователем — jezrael, является правильным подходом к этой проблеме.