explotando una columna de dataframe pandas

Tengo un Dataframe de Pandas que se parece a esto:

text = ["abcd", "efgh", "ijkl", "mnop", "qrst", "uvwx", "yz"] labels = ["label_1, label_2", "label_1, label_3, label_2", "label_2, label_4", "label_1, label_2, label_5", "label_2, label_3", "label_3, label_5, label_1, label_2", "label_1, label_3"] df = pd.DataFrame(dict(text=text, labels=labels)) df text labels 0 abcd label_1, label_2 1 efgh label_1, label_3, label_2 2 ijkl label_2, label_4 3 mnop label_1, label_2, label_5 4 qrst label_2, label_3 5 uvwx label_3, label_5, label_1, label_2 6 yz label_1, label_3 

Me gustaría formatear el dataframe en algo como esto:

 text label_1 label_2 label_3 label_4 label_5 abcd 1.0 1.0 0.0 0.0 0.0 efgh 1.0 1.0 1.0 0.0 0.0 ijkl 0.0 1.0 0.0 1.0 0.0 mnop 1.0 1.0 0.0 0.0 1.0 qrst 0.0 1.0 1.0 0.0 0.0 uvwx 1.0 1.0 1.0 0.0 1.0 yz 1.0 0.0 1.0 0.0 0.0 

¿Cómo puedo lograr esto? (Sé que puedo dividir las cadenas en las tags y convertirlas en listas haciendo algo como df.labels.str.split(",") pero no estoy seguro de cómo proceder desde allí.

(así que básicamente me gustaría convertir esas palabras clave en las columnas de tags en sus propias columnas y completar 1 cuando aparezcan como se muestran en el resultado esperado)

Puede usar pd.Series.str.get_dummies y combinar con la serie de text :

 dummies = df['labels'].str.replace(' ', '').str.get_dummies(',') res = df['text'].to_frame().join(dummies) print(res) text label_1 label_2 label_3 label_4 label_5 0 abcd 1 1 0 0 0 1 efgh 1 1 1 0 0 2 ijkl 0 1 0 1 0 3 mnop 1 1 0 0 1 4 qrst 0 1 1 0 0 5 uvwx 1 1 1 0 1 6 yz 1 0 1 0 0 

código:

 text = ["abcd", "efgh", "ijkl", "mnop", "qrst", "uvwx", "yz"] labels = ["label_1, label_2", "label_1, label_3, label_2", "label_2, label_4", "label_1, label_2, label_5", "label_2, label_3", "label_3, label_5, label_1, label_2", "label_1, label_3"] df = pd.DataFrame(dict(text=text, labels=labels)) df = df.drop('labels', axis=1).join( df.labels .str .split(', ', expand=True) .stack() .reset_index(drop=True, level=1) .rename('labels') ) df['value'] = 1 df_new = df.pivot(values = 'value', index='text', columns = 'labels').fillna(0) print(df_new) 

salida:

 labels text label_1 label_2 label_3 label_4 label_5 0 abcd 1.0 1.0 0.0 0.0 0.0 1 efgh 1.0 1.0 1.0 0.0 0.0 2 ijkl 0.0 1.0 0.0 1.0 0.0 3 mnop 1.0 1.0 0.0 0.0 1.0 4 qrst 0.0 1.0 1.0 0.0 0.0 5 uvwx 1.0 1.0 1.0 0.0 1.0 6 yz 1.0 0.0 1.0 0.0 0.0 

En este aspecto principal está el uso dividido ( , ) con espacio, debido a su formato de cadena, si cambia ese formato en lugar de usar la división apropiada.

por ejemplo:

Si está usando split con una sola coma como esta

 df = df.drop('labels', axis=1).join( df.labels .str .split(',', expand=True) .stack() .reset_index(drop=True, level=1) .rename('labels') ) 

entonces necesitarás un código adicional para eliminar espacios

 df['labels'] = df['labels'].str.replace(" ", "") 

El rest del código será igual.

Una solución simple sería usar pd.get_dummies siguiente manera:

 pd.get_dummies( df.set_index('text')['labels'].str.split(', ', expand=True).stack() ).groupby('text').sum() 

Si el número de columnas es dynamic, esto ayudará a encontrar las posibles.

 unique = df['labels'].apply(lambda x: x.split(", ")).values.tolist() unique = [i for sublist in unique for i in sublist] unique = set(unique) 

Por lo tanto, lo único es ahora.
{‘label_1’, ‘label_2’, ‘label_3’, ‘label_4’, ‘label_5’}

 max_label = len(unique) 

Lo que nos dará el número máximo de columnas.

Responder

 def labeller(labels): value = [0] * max_label for label in labels: value[int(label[-1])-1] = 1 return value df['labels'] = df['labels'].apply(lambda x: x.split(", ")).apply(labeller) df[['label_' + str(i+1) for i in range(max_label)]] = df.labels.apply(pd.Series) df.drop(['labels'], axis=1, inplace=True) text label_1 label_2 label_3 label_4 label_5 0 abcd 1 1 0 0 0 1 efgh 1 1 1 0 0 2 ijkl 0 1 0 1 0 3 mnop 1 1 0 0 1 4 qrst 0 1 1 0 0 5 uvwx 1 1 1 0 1 6 yz 1 0 1 0 0