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