tutorial tablas notebook hacer filtrar espaƱol documentacion datos data como columna agregar python pandas

python - tablas - Pandas: crea dos nuevas columnas en un marco de datos con valores calculados a partir de una columna preexistente



pandas python (2)

Estoy trabajando con la biblioteca de pandas y quiero agregar dos nuevas columnas a un marco de datos df con n columnas (n> 0).
Estas nuevas columnas son el resultado de la aplicación de una función a una de las columnas en el marco de datos.

La función para aplicar es como:

def calculate(x): ...operate... return z, y

Un método para crear una nueva columna para una función que solo devuelve un valor es:

df[''new_col'']) = df[''column_A''].map(a_function)

Entonces, lo que quiero, y lo intenté sin éxito (*), es algo así como:

(df[''new_col_zetas''], df[''new_col_ys'']) = df[''column_A''].map(calculate)

¿Cuál es la mejor manera de lograr esto? Escaneé la documentation sin ninguna pista.

* df[''column_A''].map(calculate) devuelve una serie panda cada elemento que consta de una tupla z, y. E intentar asignar esto a dos columnas de marco de datos produce un ValueError.


La respuesta principal es defectuosa en mi opinión. Con suerte, nadie importa de forma masiva todos los pandas en su espacio de nombres con from pandas import * . Además, el método del map debe reservarse para aquellos momentos en que se le pasa un diccionario o serie. Puede tomar una función, pero esto es para lo que se usa apply .

Entonces, si debe usar el enfoque anterior, lo escribiría así

df["A1"], df["A2"] = zip(*df["a"].apply(calculate))

En realidad, no hay razón para usar zip aquí. Simplemente puede hacer esto:

df["A1"], df["A2"] = calculate(df[''a''])

Este segundo método también es mucho más rápido en DataFrames de mayor tamaño

df = pd.DataFrame({''a'': [1,2,3] * 100000, ''b'': [2,3,4] * 100000})

DataFrame creado con 300,000 filas

%timeit df["A1"], df["A2"] = calculate(df[''a'']) 2.65 ms ± 92.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) %timeit df["A1"], df["A2"] = zip(*df["a"].apply(calculate)) 159 ms ± 5.24 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

60 veces más rápido que zip

En general, evita el uso de aplicar

Aplicar generalmente no es mucho más rápido que iterar sobre una lista de Python. Probemos el rendimiento de un for-loop para hacer lo mismo que arriba

%%timeit A1, A2 = [], [] for val in df[''a'']: A1.append(val**2) A2.append(val**3) df[''A1''] = A1 df[''A2''] = A2 298 ms ± 7.14 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Así que esto es dos veces más lento, lo cual no es una regresión de rendimiento terrible, pero si hacemos una ciclación de lo anterior, obtenemos un rendimiento mucho mejor. Asumiendo, estás usando ipython:

%load_ext cython %%cython cpdef power(vals): A1, A2 = [], [] cdef double val for val in vals: A1.append(val**2) A2.append(val**3) return A1, A2 %timeit df[''A1''], df[''A2''] = power(df[''a'']) 72.7 ms ± 2.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Asignación directa sin aplicar

Puede obtener mejoras de velocidad aún mayores si usa las operaciones vectorizadas directas.

%timeit df[''A1''], df[''A2''] = df[''a''] ** 2, df[''a''] ** 3 5.13 ms ± 320 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Esto aprovecha las operaciones vectorizadas extremadamente rápidas de NumPy en lugar de nuestros bucles. Ahora tenemos una aceleración de 30 veces sobre el original.

La prueba de velocidad más simple con apply

El ejemplo anterior debe mostrar claramente cómo puede ser lenta la apply , pero así es más claro, veamos el ejemplo más básico. Vamos a cuadrar una serie de 10 millones de números con y sin aplicar

s = pd.Series(np.random.rand(10000000)) %timeit s.apply(calc) 3.3 s ± 57.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Sin aplicar es 50 veces más rápido

%timeit s ** 2 66 ms ± 2 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)


Yo solo usaría zip :

In [1]: from pandas import * In [2]: def calculate(x): ...: return x*2, x*3 ...: In [3]: df = DataFrame({''a'': [1,2,3], ''b'': [2,3,4]}) In [4]: df Out[4]: a b 0 1 2 1 2 3 2 3 4 In [5]: df["A1"], df["A2"] = zip(*df["a"].map(calculate)) In [6]: df Out[6]: a b A1 A2 0 1 2 2 3 1 2 3 4 6 2 3 4 6 9