Finden Sie schnell symmetrische Paare in numpy

15
from itertools import product
import pandas as pd

df = pd.DataFrame.from_records(product(range(10), range(10)))
df = df.sample(90)
df.columns = "c1 c2".split()
df = df.sort_values(df.columns.tolist()).reset_index(drop=True)
#     c1  c2
# 0    0   0
# 1    0   1
# 2    0   2
# 3    0   3
# 4    0   4
# ..  ..  ..
# 85   9   4
# 86   9   5
# 87   9   7
# 88   9   8
# 89   9   9
# 
# [90 rows x 2 columns]

Wie finde, identifiziere und entferne ich schnell das letzte Duplikat aller symmetrischen Paare in diesem Datenrahmen?

Ein Beispiel für ein symmetrisches Paar ist, dass '(0, 1)' gleich '(1, 0)' ist. Letzteres sollte entfernt werden.

Der Algorithmus muss schnell sein, daher wird empfohlen, numpy zu verwenden. Das Konvertieren in ein Python-Objekt ist nicht zulässig.

Die Unfun Cat
quelle
1
Können Sie ein Beispiel dafür geben, was Sie verstehen symmetric pairs?
Yatu
(0, 1) == (1,0) ist wahr
The Unfun Cat
1
Ist (0, 1) == (0, 1) auch wahr?
Wundermahn
@ JerryM. Ja, aber es ist trivial zu entfernen mitdf.drop_duplicates()
The Unfun Cat
2
@ molybdenum42 Ich verwende das Produkt itertools, um ein Beispiel zu erstellen. Die Daten selbst werden nicht mit dem Produkt itertools erstellt.
Die Unfun Cat

Antworten:

13

Sie können die Werte dann sortieren groupby:

a= np.sort(df.to_numpy(), axis=1)
df.groupby([a[:,0], a[:,1]], as_index=False, sort=False).first()

Option 2 : Wenn Sie viele Paare haben c1, c2, groupbykann dies langsam sein. In diesem Fall können wir neue Werte zuweisen und filtern nach drop_duplicates:

a= np.sort(df.to_numpy(), axis=1) 

(df.assign(one=a[:,0], two=a[:,1])   # one and two can be changed
   .drop_duplicates(['one','two'])   # taken from above
   .reindex(df.columns, axis=1)
)
Quang Hoang
quelle
7

Eine Möglichkeit besteht darin, den Datenrahmen np.uniquemit return_index=Truezu indizieren und das Ergebnis zu indizieren:

a = np.sort(df.values)
_, ix = np.unique(a, return_index=True, axis=0)

print(df.iloc[ix, :])

    c1  c2
0    0   0
1    0   1
20   2   0
3    0   3
40   4   0
50   5   0
6    0   6
70   7   0
8    0   8
9    0   9
11   1   1
21   2   1
13   1   3
41   4   1
51   5   1
16   1   6
71   7   1
...
Yatu
quelle
1
Ja, sonst erkennt Unique keine symmetrischen Paare. @DanielMesejo
yatu
Ok, ich
verstehe
Ja, aber ich meine, Sie verwandeln [1, 0] in [0, 1], oder?
Dani Mesejo
6

frozenset

mask = pd.Series(map(frozenset, zip(df.c1, df.c2))).duplicated()

df[~mask]
piRSquared
quelle
1
Iterieren Sie hier nicht langsam über Tupel über jede Spalte? Trotzdem positiv.
Die Unfun Cat
Ja, ich iteriere. Nein, es ist nicht so langsam wie du denkst.
piRSquared
5

Ich werde tun

df[~pd.DataFrame(np.sort(df.values,1)).duplicated().values]

Von Pandas und Numpy Tri

s=pd.crosstab(df.c1,df.c2)
s=s.mask(np.triu(np.ones(s.shape)).astype(np.bool) & s==0).stack().reset_index()
YOBEN_S
quelle
5

Hier ist eine NumPy-basierte für Ganzzahlen -

def remove_symm_pairs(df):
    a = df.to_numpy(copy=False)
    b = np.sort(a,axis=1)
    idx = np.ravel_multi_index(b.T,(b.max(0)+1))
    sidx = idx.argsort(kind='mergesort')
    p = idx[sidx]
    m = np.r_[True,p[:-1]!=p[1:]]
    a_out = a[np.sort(sidx[m])]
    df_out = pd.DataFrame(a_out)
    return df_out

Wenn Sie die Indexdaten unverändert lassen möchten, verwenden Sie return df.iloc[np.sort(sidx[m])].

Für generische Zahlen (Ints / Floats usw.) verwenden wir eine view-basedEins -

# https://stackoverflow.com/a/44999009/ @Divakar
def view1D(a): # a is array
    a = np.ascontiguousarray(a)
    void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
    return a.view(void_dt).ravel()

und ersetzen Sie einfach den Schritt zu bekommen idxmit idx = view1D(b)in remove_symm_pairs.

Divakar
quelle
1

Wenn dies schnell sein muss und Ihre Variablen ganzzahlig sind, kann der folgende Trick hilfreich sein: Lassen Sie v,wdie Spalten Ihres Vektors sein; konstruieren [v+w, np.abs(v-w)] =: [x, y]; Sortieren Sie diese Matrix dann lexikografisch, entfernen Sie Duplikate und ordnen Sie sie schließlich wieder zu [v, w] = [(x+y), (x-y)]/2.

Federico Poloni
quelle