Estaba usando python y pandas para hacer un análisis estadístico de los datos y en algún momento necesitaba agregar algunas columnas nuevas con la función de asignación

df_res = (
    df
    .assign(col1 = lambda x: np.where(x['event'].str.contains('regex1'),1,0))
    .assign(col2 = lambda x: np.where(x['event'].str.contains('regex2'),1,0))
    .assign(mycol = lambda x: np.where(x['event'].str.contains('regex3'),1,0))
    .assign(newcol = lambda x: np.where(x['event'].str.contains('regex4'),1,0))
)

Quería saber si hay alguna forma de agregar nombres de columnas y mi expresión regular a un diccionario y usar un bucle for u otra expresión lambda para asignar estas columnas automáticamente:

Dic = {'col1':'regex1','col2':'regex2','mycol':'regex3','newcol':'regex4'}

df_res = (
    df
    .assign(...using Dic here...)
)

Necesito agregar más columnas más tarde y creo que será más fácil agregar columnas nuevas más adelante.

1
MhDG7 4 oct. 2019 a las 18:34

3 respuestas

La mejor respuesta

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.assign.html

Asignar múltiples columnas dentro de la misma asignación es posible. Para Python 3.6 y superior, los elementos posteriores en ‘** kwargs 'pueden referirse a columnas recién creadas o modificadas en‘ df'; los elementos se calculan y se asignan a ‘df 'en orden. Para Python 3.5 y versiones posteriores, el orden de los argumentos de palabras clave no se especifica, no puede hacer referencia a columnas recién creadas o modificadas. Todos los artículos se calculan primero y luego se asignan en orden alfabético. Modificado en la versión 0.23.0: el orden de los argumentos de las palabras clave se mantiene para Python 3.6 y posteriores.

Si asigna toda su expresión regular para que cada valor del diccionario contenga una lambda en lugar de solo la expresión regular, simplemente puede descomprimir el dic en asignar:

lambda_dict = {
    col:
    lambda x, regex=regex: (
        x['event'].
        str.contains(regex)
        .astype(int)
    ) 
    for col, regex in Dic.items()
}
res = df.assign(**lambda_dict)

EDITAR Aquí hay un ejemplo:

import pandas as pd
import random

random.seed(0)
events = ['apple_one', 'chicken_one', 'chicken_two', 'apple_two']
data = [random.choice(events) for __ in range(10)]
df = pd.DataFrame(data, columns=['event'])

regex_dict = {
        'apples': 'apple',
        'chickens': 'chicken',
        'ones': 'one',
        'twos': 'two',
}

lambda_dict = {
    col:
    lambda x, regex=regex: (
        x['event']
        .str.contains(regex)
        .astype(int)
    )
    for col, regex in regex_dict.items()
}

res = df.assign(**lambda_dict)
print(res)

# Output
         event  apples  chickens  ones  twos
0    apple_two       1         0     0     1
1    apple_two       1         0     0     1
2    apple_one       1         0     1     0
3  chicken_two       0         1     0     1
4    apple_two       1         0     0     1
5    apple_two       1         0     0     1
6  chicken_two       0         1     0     1
7    apple_two       1         0     0     1
8  chicken_two       0         1     0     1
9  chicken_one       0         1     1     0

El problema con el código anterior era que la expresión regular solo se evaluó durante el último bucle. Agregarlo como argumento predeterminado corrige esto.

1
adrianp 6 oct. 2019 a las 06:24

Esto puede hacer lo que quieres hacer

pd.concat([df,pd.DataFrame({a:list(df["event"].str.contains(b)) for a,b in Dic.items()})],axis=1)

En realidad, usar un bucle for hará lo mismo

0
Luk Aron 4 oct. 2019 a las 16:51

Si entiendo su pregunta correctamente, está tratando de cambiar el nombre de las columnas, en cuyo caso creo que podría usar Pandas función de cambio de nombre. Esto se vería como

df_res = df_res.rename(mapper=Dic)

-Ben

-1
Ben 4 oct. 2019 a las 15:46
58239458