Как фильтровать дубликаты с заменой имен столбцов в pandas

#python #pandas #dataframe #filter

#python #pandas #фрейм данных #Фильтр

Вопрос:

У меня есть pd.Dataframe, который выглядит следующим образом:

    a_p1  a_x1  a_x2  b_p1  b_x1  b_x2
1   0.0   0.0   0.0   1.0  -1.0   0.0
2   1.0  -1.0   0.0   0.0   0.0   0.0
3   0.0   0.0   0.0   0.0  -1.0   0.0
4   0.0   0.0   1.0   0.0   0.0   1.0
5   0.0   1.0   0.0   0.0   0.0   1.0
6   0.1   0.0   0.0   0.2   0.0   1.0
7   0.1   0.0   1.0   0.2   0.0   0.0
...
 

a_ и b_ представляют азартные игры. Их порядок не является обязательным, поэтому a_ с таким же успехом может быть b_ .
Я хочу удалить дубликаты, как в строках 1 и 2: пара gamble в строке 1 такая же, как и в строке 2, только что gamble a и b поменялись местами.

Как мне отфильтровать мой фрейм данных, чтобы осталась только одна из этих строк?

Желаемый результат:

    a_p1  a_x1  a_x2  b_p1  b_x1  b_x2
1   0.0   0.0   0.0   1.0  -1.0   0.0
2   0.0   0.0   0.0   0.0  -1.0   0.0
3   0.0   0.0   1.0   0.0   0.0   1.0
4   0.0   1.0   0.0   0.0   0.0   1.0
5   0.1   0.0   0.0   0.2   0.0   1.0
6   0.1   0.0   1.0   0.2   0.0   0.0
...
 

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

1. может a_p1 быть b_x1 ? и a_p1 быть a_x1 ?

2. Нет. ‘a_p1’ может быть ‘b_p1’ тогда и только тогда, когда ‘a_x1’ равно ‘b_x1’, а ‘a_x2’ равно ‘b_x2’. В принципе, есть два блока: столбцы, начинающиеся с a_, и столбцы, начинающиеся с b_. Они взаимозаменяемы, однако внутри блока обмен невозможен.

Ответ №1:

Одна идея, если все имена столбцов отсортированы — группировка по значениям столбцов после _ , преобразование значений в кортежи, сортировка и использование duplicated для маски:

 df1 = df.rename(columns=lambda x: x.split('_')[0])
print (df1)
     a    a    a    b    b    b
1  0.0  0.0  0.0  1.0 -1.0  0.0
2  1.0 -1.0  0.0  0.0  0.0  0.0
3  0.0  0.0  0.0  0.0 -1.0  0.0
4  0.0  0.0  1.0  0.0  0.0  1.0
5  0.0  1.0  0.0  0.0  0.0  1.0
6  0.1  0.0  0.0  0.2  0.0  1.0
7  0.1  0.0  1.0  0.2  0.0  0.0

print (df1.groupby(df1.columns, axis=1)
          .apply(lambda x: x.apply(lambda x: tuple(x), 1))
          .apply(lambda x: tuple(sorted(x)), axis=1))
1    ((0.0, 0.0, 0.0), (1.0, -1.0, 0.0))
2    ((0.0, 0.0, 0.0), (1.0, -1.0, 0.0))
3    ((0.0, -1.0, 0.0), (0.0, 0.0, 0.0))
4     ((0.0, 0.0, 1.0), (0.0, 0.0, 1.0))
5     ((0.0, 0.0, 1.0), (0.0, 1.0, 0.0))
6     ((0.1, 0.0, 0.0), (0.2, 0.0, 1.0))
7     ((0.1, 0.0, 1.0), (0.2, 0.0, 0.0))
dtype: object
 

 m = (df1.groupby(df1.columns, axis=1)
         .apply(lambda x: x.apply(lambda x: tuple(x), 1))
         .apply(lambda x: tuple(sorted(x)), axis=1)
         .duplicated())

df2 = df[~m]
print (df2)
   a_p1  a_x1  a_x2  b_p1  b_x1  b_x2
1   0.0   0.0   0.0   1.0  -1.0   0.0
3   0.0   0.0   0.0   0.0  -1.0   0.0
4   0.0   0.0   1.0   0.0   0.0   1.0
5   0.0   1.0   0.0   0.0   0.0   1.0
6   0.1   0.0   0.0   0.2   0.0   1.0
7   0.1   0.0   1.0   0.2   0.0   0.0
 

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

1. Разве это не будет также рассматривать эти строки как дубликаты: 0.1 0 0 0.2 0 1, 0.1 0 1 0.2 0 0?

2. Предположим, у меня есть столбцы, описанные в моем комментарии. Я думаю, что ваш код будет ошибочно рассматривать их как дубликаты. Нет?

3. @MaxJ. — Ответ был отредактирован на оригинал и не удален только вторая строка, последняя строка — нет.