Trouvez rapidement des paires symétriques dans 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]

Comment trouver, identifier et supprimer rapidement le dernier doublon de toutes les paires symétriques de cette trame de données?

Un exemple de paire symétrique est que «(0, 1)» est égal à «(1, 0)». Ce dernier doit être supprimé.

L'algorithme doit être rapide, il est donc recommandé d'utiliser numpy. La conversion en objet python n'est pas autorisée.


1
Pourriez-vous donner un exemple de ce que vous comprenez symmetric pairs?
yatu

(0, 1) == (1,0) est vrai
The Unfun Cat

1
Est-ce que (0, 1) == (0, 1) est également vrai?
wundermahn

@JerryM. Oui, mais il est trivial d'enlever avecdf.drop_duplicates()
The Unfun Cat

2
@ molybdenum42 J'utilise le produit itertools pour créer un exemple, les données elles-mêmes ne sont pas créées avec le produit itertools.
The Unfun Cat

Réponses:


13

Vous pouvez trier les valeurs, puis groupby:

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

Option 2 : Si vous avez beaucoup de paires c1, c2, cela groupbypeut être lent. Dans ce cas, nous pouvons attribuer de nouvelles valeurs et filtrer par 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

Une façon consiste à utiliser np.uniqueavec return_index=Trueet à utiliser le résultat pour indexer la trame de données:

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
Oui sinon échoue unique de détecter des paires symétriques
YATU

Ok, je vois donc vous
triez

Oui mais je veux dire que vous transformez [1, 0] en [0, 1] non?
Dani Mesejo

6

frozenset

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

df[~mask]

1
N'êtes-vous pas en train d'itérer lentement sur des tuples sur chaque colonne ici? Pourtant, vote positif.
The Unfun Cat

Oui, je répète. Non, ce n'est pas aussi lent que vous le pensez.
piRSquared

5

je ferai

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

De pandas et 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

En voici un basé sur NumPy pour les entiers -

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

Si vous souhaitez conserver les données d'index telles quelles, utilisez return df.iloc[np.sort(sidx[m])].

Pour les nombres génériques (ints / float, etc.), nous utiliserons un view-based-

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

et remplacer simplement l'étape pour obtenir idxavec idx = view1D(b)en remove_symm_pairs.


1

Si cela doit être rapide , et si vos variables sont entières, alors l'astuce suivante peut vous aider: v,wsoit les colonnes de votre vecteur; construire [v+w, np.abs(v-w)] =: [x, y]; puis triez cette matrice lexicographiquement, supprimez les doublons et enfin mappez-la à nouveau [v, w] = [(x+y), (x-y)]/2.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.