Группировка дубликатов, позволяющая NaN быть равной любому значению - PullRequest
2 голосов
/ 20 марта 2020

Я хочу объединить дубликаты строк в DataFrame на основе нескольких столбцов, но с нерегулярным определением того, что означает «дубликат».

Представьте себе DataFrame с двумя столбцами, A и B:


In [45]: df = pd.DataFrame([[0, 0], [pd.NA, 0], [0, 1], [pd.NA, 1], [1, 1]], columns=['A', 'B']).convert_dtypes()

In [63]: df
Out[63]: 
      A  B
0     0  0
1  <NA>  0
2     0  1
3  <NA>  1
4     1  1

По сути, пропущенное значение должно быть равно любому значению, если оно не нужно «быть равным» нескольким значениям одновременно.

Таким образом, первая и вторая строки должны быть объявлены дубликатами и агрегироваться вместе. Строки 0 и 1 являются дубликатами, потому что они имеют одинаковое значение в столбце B, а также потому, что в столбце A имеется только 1 уникальное значение (не считая пропущенных значений). Это создает проблему с последние три строки, поскольку отсутствующее значение может заполнить либо 0, либо 1. В этом случае я не хочу, чтобы строки агрегировались вместе; ни строки 2 и 3 не должны быть дубликатами, ни строки 3 и 4. Несмотря на то, что строки 2, 3 и 4 имеют одинаковое значение в столбце B, ни одно из них не является дубликатом другого, поскольку существует 2 уникальных значения (не считая пропущенных) значение) в столбце A.

Конечная цель - объединить дублирующиеся строки вместе, как с DataFrame.groupby().aggregate(), но если вы знаете решение просто пометить строки как дубликаты, возвращая логическую серию, такую ​​как DataFrame.duplicated , тогда мне это немного помогает.

В частности, для моей проблемы будет произвольно много столбцов, но только 1 столбец с пропущенными значениями. Вы можете предположить, что существует уникальное значение заполнения для заполнения пропущенных значений в этом столбце, чтобы избежать удаления этих строк в groupby.

1 Ответ

1 голос
/ 20 марта 2020

в одну сторону может быть groupby все остальные ваши столбцы (здесь только B) и transform с False, если nunique в группе равно 1 (nan не считаются) и True в противном случае. Затем вы можете использовать эту маску или notna, чтобы сохранить нужные вам строки:

print (df.loc[ df.groupby('B')['A'].transform(lambda x: False if x.nunique()==1 else True)
                |df['A'].notna(), :])
      A  B
0     0  0
2     0  1
3  <NA>  1
4     1  1

РЕДАКТИРОВАТЬ: создать группу, если с преобразованием можно было сделать только одно значение, отличное от np.nan, и заменить nan на уникальное значение:

df['gr'] = df.groupby('B')['A'].transform(lambda x: x.max() if x.nunique()==1 else x)

, затем вы можете выполнить групповую операцию на B и в этом столбце gr, не уверенный в ожидаемом результате

...