Ir al contenido
wannacode

Columnas nuevas

En resumen: Una columna nueva en pandas se calcula a partir de las otras columnas de una vez: aritmética, np.where o map; assign devuelve una tabla nueva, y apply es la forma más lenta.

Problema

Lo que vale cada línea

order_items.csv te dice, para cada línea de un pedido, qué producto es, cuántas unidades y a qué precio. Lo que valía la línea entera no está escrito en ningún sitio:

Pythondatos: las tablas de la tienda

El gerente quiere los ingresos, pero sin los pedidos cancelados. También quiere saber qué líneas son grandes, y el informe debe tener nombres de categorías, no números. Para todo esto necesitas columnas que no están en el archivo. Las calcularás a partir de las que sí están.

La idea

Una columna a partir de aritmética

Una columna es una Serie, y la aritmética con Series está vectorizada, como con los arreglos de NumPy. Unidades por precio da el valor de las 152 líneas de una vez. Guarda el resultado con un nombre nuevo y la tabla recibe una columna nueva:

Pythondatos: las tablas de la tienda

total apareció a la derecha: la primera línea son 4 unidades a 7,90 €, es decir, 31,60 €. Si el nombre ya existe, la columna se reemplaza por los valores nuevos.

La suma de todas las líneas es 1963,50 €. Eso todavía no son los ingresos: entre estas líneas hay también pedidos que los clientes cancelaron.

Míralo

Ingresos sin los cancelados

Un pedido cancelado no se paga, así que no cuenta en los ingresos. El estado está en orders.csv, y las líneas en order_items.csv. Tomas los números de los pedidos cancelados con loc, y luego isin de la lección anterior encuentra sus líneas:

Pythondatos: las tablas de la tienda

7 pedidos fueron cancelados. Sin sus líneas quedan 131 de 152, y los ingresos son 1697,00 €. La regla vale para todo el curso: cuando la pregunta es sobre ingresos, los pedidos cancelados no cuentan.

Pruébalo

Dinero en los estantes

Añade a products una columna stock_value: cuánto dinero hay parado en stock de cada producto (precio por stock). Luego pon en top3 los tres productos con mayor stock_value, sin la tarjeta de regalo (id 25).

Pythondatos: las tablas de la tienda

La idea

Una tabla nueva con assign

items['total'] = … cambia la tabla misma. assign hace lo contrario: devuelve una tabla nueva con una columna más, y la vieja se queda igual. Así puedes seguir directamente con un filtro:

Pythondatos: las tablas de la tienda

6 líneas valen 50 € o más. La última línea muestra que items no tiene total: assign no la tocó. Esto es Copy-on-Write de la lección sobre seleccionar: un cambio da una tabla nueva, y el original no cambia.

Dentro de assign puedes pasar una función en lugar de una columna. lambda d: … recibe la tabla en ese momento, así que el segundo assign ve el total del primero:

Pythondatos: las tablas de la tienda

Una secuencia de métodos así, cada uno trabajando con el resultado del anterior, se llama una cadena. Los paréntesis alrededor te permiten escribirla en varias líneas.

La idea

Una cosa o la otra: np.where

Una línea «grande» vale 20 € o más. np.where de la lección de NumPy también funciona con columnas: para cada fila toma un valor o el otro:

Pythondatos: las tablas de la tienda

Hay 35 líneas grandes y 117 pequeñas. El resultado tiene un valor para cada fila, así que se convierte en una columna.

La idea

De número a nombre: map

En products la categoría es un número, y el gerente quiere un nombre. map con un diccionario reemplaza cada valor por el que le corresponde en el diccionario:

Pythondatos: las tablas de la tienda

3 pasa a ser «Pan y bollería», 8 pasa a ser «Cocina». La tarjeta de regalo no tiene categoría, no hay clave para ella en el diccionario, y map deja NaN.

No hace falta teclear el diccionario a mano. categories.set_index('id')['name'] es una Serie con los números como índice y los nombres como valores, y map también funciona con una Serie así: busca el valor en su índice.

1. El diccionario names no tiene clave para la tarjeta de regalo. ¿Qué da map para ella?

La idea

Tu propia función: apply

La tienda da descuento en una línea grande: 10 % desde 50 € y 5 % desde 20 €. La regla es una función de Python con if. apply la ejecuta para cada valor de la columna:

Pythondatos: las tablas de la tienda

117 líneas no reciben descuento, 29 reciben un 5 % y 6 reciben un 10 %. Todos los descuentos juntos suman 84,14 €.

apply es cómodo cuando la regla ya es una función que trabaja con un valor. Esta regla también se podría escribir vectorizada, con dos np.where uno dentro del otro. Con 152 líneas no notarás la diferencia. Con muchas líneas, sí.

Míralo

Lo que cuesta apply

Aquí está la misma aritmética hecha de dos maneras sobre las 26 619 líneas de los pedidos del año. apply(…, axis=1) ejecuta la función para cada fila, y time.perf_counter() mide cuánto tiempo pasa:

Pythondatos: las tablas de la tienda

El resultado es el mismo (True en la penúltima línea). En nuestras pruebas apply fue más de cien veces más lento que la aritmética vectorizada. Los números exactos dependen de la máquina, pero la diferencia se mantiene.

La regla: primero buscas aritmética vectorizada, np.where o map. apply queda para una regla que no se puede escribir de otra manera.

Más precisamente, para curiosos

apply con axis=1 convierte cada fila en una Serie pequeña y llama a tu función de Python 26 619 veces. La aritmética vectorizada recorre la columna una vez, en un bucle de C dentro de NumPy. Por eso la diferencia crece con el número de filas: con 152 filas es invisible, y con un millón es la diferencia entre un segundo y un minuto.

La idea

El informe: rename y drop

Antes de mandar la tabla al gerente, quitas las columnas que no necesita y pones nombres que entienda. drop(columns=[…]) quita columnas, y rename(columns={viejo: nuevo}) las renombra:

Pythondatos: las tablas de la tienda

Las dos devuelven una tabla nueva, como assign. Las columnas que no están en el diccionario de rename conservan su nombre viejo.

Ejercicio

Los ingresos del año

¿Cuáles son los ingresos de todo el año? Añade una columna total a year_items (unidades por precio), quita las líneas de los pedidos cancelados y pon la suma, redondeada a 2 decimales, en revenue.

Pythondatos: las tablas de la tienda

¿Cuánto aportó el café en grano (producto 17) en el año, sin los pedidos cancelados? Pon la suma, redondeada a 2 decimales, en coffee_revenue.

Pythondatos: las tablas de la tienda

Test

Ponte a prueba

1. Ejecutas items.assign(total=...) y no guardas el resultado en ningún sitio. ¿Qué hay en items después?
2. ¿Qué es mejor para el valor de una línea con 26 619 líneas?
3. ¿Cuándo es apply con tu propia función la elección correcta?
4. El café costó 13,90 € hasta el 1 de marzo, y ahora cuesta 14,90 €. ¿Qué precio usas para los ingresos del café del año?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·