python pandas numpy

python - Verifique la lista de referencias en la columna de pandas usando vectorización numpy



(3)

Tengo una lista de referencias

ref = [''September'', ''August'', ''July'', ''June'', ''May'', ''April'', ''March'']

Y un marco de datos

df = pd.DataFrame({''Month_List'': [[''July''], [''August''], [''July'', ''June''], [''May'', ''April'', ''March'']]}) df Month_List 0 [July] 1 [August] 2 [July, June] 3 [May, April, March]

Quiero verificar qué elementos de la lista de referencia están presentes en cada fila y convertirlos en una lista binaria

Puedo lograr esto usando apply

def convert_month_to_binary(ref,lst): s = pd.Series(ref) return s.isin(lst).astype(int).tolist() df[''Binary_Month_List''] = df[''Month_List''].apply(lambda x: convert_month_to_binary(ref, x)) df Month_List Binary_Month_List 0 [July] [0, 0, 1, 0, 0, 0, 0] 1 [August] [0, 1, 0, 0, 0, 0, 0] 2 [July, June] [0, 0, 1, 1, 0, 0, 0] 3 [May, April, March] [0, 0, 0, 0, 1, 1, 1]

Sin embargo, el uso de apply en grandes conjuntos de datos es muy lento y, por lo tanto, estoy buscando usar una vectorización numpy. ¿Cómo puedo mejorar mi rendimiento?

Extensión :

Quería usar numpy vectorization porque ahora necesito aplicar otra función en esta lista

Estoy intentando así, pero el rendimiento es muy lento. Resultados similares con apply

def count_one(lst): index = [i for i, e in enumerate(lst) if e != 0] return len(index) vfunc = np.vectorize(count_one) df[''Value''] = vfunc(df[''Binary_Month_List''])


Aquí hay uno con las herramientas NumPy:

def isin_lists(df_col, ref): a = np.concatenate(df_col) b = np.asarray(ref) sidx = b.argsort() c = sidx[np.searchsorted(b,a,sorter=sidx)] l = np.array([len(i) for i in df_col]) r = np.repeat(np.arange(len(l)),l) out = np.zeros((len(l),len(b)), dtype=bool) out[r,c] = 1 return out.view(''i1'')

Salida para muestra dada -

In [79]: bin_ar = isin_lists(df[''Month_List''], ref) In [80]: bin_ar Out[80]: array([[0, 0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1]], dtype=int8) # To assign as lists for each row into `df` In [81]: df[''Binary_Month_List''] = bin_ar.tolist() # To get counts In [82]: df[''Value''] = bin_ar.sum(1) In [83]: df Out[83]: Month_List Binary_Month_List Value 0 [July] [0, 0, 1, 0, 0, 0, 0] 1 1 [August] [0, 1, 0, 0, 0, 0, 0] 1 2 [July, June] [0, 0, 1, 1, 0, 0, 0] 2 3 [May, April, March] [0, 0, 0, 0, 1, 1, 1] 3

Si no puede usar el bin_ar intermedio por alguna razón y solo ''Binary_Month_List'' encabezado ''Binary_Month_List'' para trabajar con -

In [15]: df[''Value''] = np.vstack(df[''Binary_Month_List'']).sum(axis=1)


En pandas es mejor no usar las list esta manera , pero es posible con MultiLabelBinarizer y DataFrame.reindex para agregar categorías faltantes, convertir los últimos valores a una matriz numpy y luego list si el rendimiento es importante:

from sklearn.preprocessing import MultiLabelBinarizer mlb = MultiLabelBinarizer() df1 = pd.DataFrame(mlb.fit_transform(df[''Month_List'']),columns=mlb.classes_) df[''Binary_Month_List''] = df1.reindex(columns=ref, fill_value=0).values.tolist()

O con Series.str.join , Series.str.get_dummies y Series.str.get_dummies :

df[''Binary_Month_List''] = (df[''Month_List''].str.join(''|'') .str.get_dummies() .reindex(columns=ref, fill_value=0) .values .tolist()) print (df) Month_List Binary_Month_List 0 [July] [0, 0, 1, 0, 0, 0, 0] 1 [August] [0, 1, 0, 0, 0, 0, 0] 2 [July, June] [0, 0, 1, 1, 0, 0, 0] 3 [May, April, March] [0, 0, 0, 0, 1, 1, 1]

El rendimiento es diferente:

df = pd.concat([df] * 1000, ignore_index=True) from sklearn.preprocessing import MultiLabelBinarizer mlb = MultiLabelBinarizer() In [338]: %timeit (df[''Month_List''].str.join(''|'').str.get_dummies().reindex(columns=ref, fill_value=0).values.tolist()) 31.4 ms ± 1.41 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) In [339]: %timeit pd.DataFrame(mlb.fit_transform(df[''Month_List'']),columns=mlb.classes_).reindex(columns=ref, fill_value=0).values.tolist() 5.57 ms ± 94.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) In [340]: %timeit df[''Binary_Month_List2''] =df.Month_List.explode().str.get_dummies().sum(level=0).reindex(columns=ref, fill_value=0).values.tolist() 58.6 ms ± 461 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)


Podemos usar la explode con get_dummies , observe que la explode está disponible después de 0.25

df.Month_List.explode().str.get_dummies().sum(level=0).reindex(columns=ref, fill_value=0).values.tolist() Out[79]: [[0, 0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1]] #df[''new'']=df.Month_List.explode().str.get_dummies().sum(level=0).reindex(columns=ref, fill_value=0).values.tolist()