python pandas numpy

python - Encuentra pares simétricos rápidamente en numpy



pandas (6)

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]

¿Cómo encuentro rápidamente identificar y eliminar el último duplicado de todos los pares simétricos en este marco de datos?

Por par simétrico quiero decir que (0, 1) es igual a (1, 0) . Este último debe ser eliminado.

Tiene que ser rápido, por lo que se aprecian soluciones vacías. No hay conversión a objetos python por favor :)


frozenset

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


Aquí hay uno basado en NumPy para enteros:

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 desea mantener los datos del índice tal como están, use return df.iloc[np.sort(sidx[m])] .

Para números genéricos (ints / floats, etc.), usaremos uno view-based :

# https://.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()

y simplemente reemplace el paso para obtener idx con idx = view1D(b) en remove_symm_pairs .


Puede ordenar los valores, luego groupby :

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

Opción 2 : si tiene muchos pares c1, c2 , groupby puede ser lento. En ese caso, podemos asignar nuevos valores y filtrar por 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) )


Si esto necesita ser rápido , y si sus variables son enteras, entonces el siguiente truco puede ayudar: sea v,w las columnas de su vector; construir [v+w, np.abs(vw)] =: [x, y] ; luego ordene esta matriz lexicográficamente, elimine los duplicados y finalmente vuelva a asignarla a [v, w] = [(x+y), (xy)]/2 .


Una forma es usar np.unique con return_index=True y usar el resultado para indexar el marco de datos:

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


voy a hacer

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

De pandas y 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()