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.


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)
)

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
...

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]

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()

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.


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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.