Как удалить «зеркальное копирование» строк в панде Dataframe? - PullRequest
2 голосов
/ 22 октября 2019

У меня есть следующие панды. В DataFrame есть строки «зеркального копирования» между ABE и CDF:

import numpy as np
import pandas as pd

df1 = pd.DataFrame(np.array([[1, 2, 3, 4, 47, 27], [5, 6, 7, 8, 21, 40], [9, 10, 11, 12, 45, 33], 
    [3, 4, 1, 2, 27, 47], [7, 8, 5, 6, 40, 21], [11, 12, 9, 10, 33, 45]]), 
    columns=['A', 'B', 'C', 'D', 'E', 'F'])

print(df1)

##     A   B   C   D   E   F
## 0   1   2   3   4  47  27
## 1   5   6   7   8  21  40
## 2   9  10  11  12  45  33
## 3   3   4   1   2  27  47
## 4   7   8   5   6  40  21
## 5  11  12   9  10  33  45

Под «зеркальными копиями» я имею в виду следующее: если вы посмотрите на строки 3, 4, 5это «зеркальные копии» строк 0, 1, 2. Столбцы A и B в строках 0, 1, 2 - это столбцы C и D в строках 3, 4, 5.

Например, в строке0, ['A', 'B', 'C', 'D'] равно [1, 2, 3, 4]. В строке 3 ['A', 'B', 'C', 'D'] есть [3, 4, 1, 2].

Это верно и для столбцов E и F --- значения E в строках 0, 1, 2 являются значениями F в строках 3, 4, 5.

Я хотел быудалите эти строки «зеркального копирования» и оставьте только «уникальные» пары. Правильный вывод выше должен быть либо:

##     A   B   C   D   E   F
## 0   1   2   3   4  47  27
## 1   5   6   7   8  21  40
## 2   9  10  11  12  45  33

или

##     A   B   C   D   E   F
## 0   3   4   1   2  27  47
## 1   7   8   5   6  40  21
## 2  11  12   9  10  33  45

, но не оба - только одна копия строк.

Я не знаю, как установить подгруппу DataFrame для панд, чтобы удалить подобные строки. Как можно сделать это алгоритмически эффективным (без взрыва памяти) способом?

Моя первая идея неверна, так как она проверяет только одну строку:

df1 = df1[~((df1.A == df1.C) & (df1.B == df1.D) & (df1.E == df1.F))]

Любая помощь приветствуется! Спасибо

1 Ответ

2 голосов
/ 22 октября 2019

Вы можете сделать следующее:

from collections import Counter

import numpy as np
import pandas as pd


def key(x):
    return frozenset(Counter(x).items())


df = pd.DataFrame(np.array([[1, 2, 3, 4, 47, 27], [5, 6, 7, 8, 21, 40], [9, 10, 11, 12, 45, 33],
                            [3, 4, 1, 2, 27, 47], [7, 8, 5, 6, 40, 21], [11, 12, 9, 10, 33, 45]]),
                  columns=['A', 'B', 'C', 'D', 'E', 'F'])

keys = df[['A', 'B', 'C', 'D', 'E', 'F']].apply(key, axis=1)
mask = keys.duplicated(keep='last')

print(df[mask])

Вывод

   A   B   C   D   E   F
0  1   2   3   4  47  27
1  5   6   7   8  21  40
2  9  10  11  12  45  33

Идея состоит в создании столбца keys (Series), который будет иметьодно и то же значение в тех строках, которые являются зеркальными по отношению друг к другу.

This:

def key(x):
    return frozenset(Counter(x).items())


keys = df[['A', 'B', 'C', 'D', 'E', 'F']].apply(key, axis=1)

создает столбец keys, после чего отмечаются дублированные значения:

mask = keys.duplicated(keep='last')

Вы также можете использовать ключ, предложенный @piRSquared:

def key(x): 
    a, b, c, d, e, f = x
    return tuple(map(frozenset, [(a, c), (b, d), (e, f)]))
...