Series y DataFrame
En resumen: En pandas una Serie es una columna con etiquetas y un DataFrame es una tabla de esas columnas; el índice lleva los nombres de las filas y alinea la aritmética por ellos.
Problema
«¿Cuánto dinero hay en el almacén?»
El gerente pregunta cuánto vale el stock del almacén. La respuesta es precio por stock de cada producto, y luego una suma. Después querrá ver el número de un producto, por nombre.
Con NumPy ya lo puedes calcular. Pero en la lección de resúmenes argmax devolvía 22, una posición, y tenías que sacar el nombre de un arreglo names aparte. Si ordenas un arreglo y olvidas el otro, los nombres y los números se separan y nadie lo nota.
pandas guarda una etiqueta junto a cada número: de qué producto es. En esta lección verás cómo.
La idea
Una columna con etiquetas: Serie
Una Serie es un arreglo de NumPy con una etiqueta junto a cada valor. Las etiquetas se llaman el índice. Aquí hay tres precios con los nombres de los productos como índice:
prices['Queso blanco'] da 7.9: el valor se toma por etiqueta, no por lugar. prices.index muestra las etiquetas, y to_numpy() da los números desnudos como arreglo.
La idea
Una tabla de columnas: DataFrame
Un DataFrame son varias Series con un índice compartido, una al lado de otra. Cada columna tiene un nombre y su propio tipo. Lo viste en el primer vistazo; ahora míralo pieza por pieza:
columnsson los nombres de las columnas: 6.indexes unRangeIndexde 0 a 24:read_csvnumera las filas desde 0 si no le dices otra cosa. La columnaides otra cosa y empieza en 1.dtypeses el tipo de cada columna.int64yfloat64son números,stres texto.
Míralo
Una columna es una Serie
Tomas una columna con su nombre entre corchetes, como en el primer vistazo. El resultado es una Serie:
A la izquierda está el índice de la tabla (0, 1, 2), y abajo el nombre de la columna (Name: price) y su tipo. Todo lo que puedes hacer con una Serie lo puedes hacer con cada columna.
La idea
Nombres en el índice: set_index
Los números del 0 al 24 no le dicen nada al gerente. set_index('name') convierte la columna name en el índice: los nombres de los productos pasan a ser las etiquetas de las filas.
Ahora el stock de café es by_name['stock']['Café en grano']: 15 paquetes. Y el producto más caro es una respuesta con nombre:
argmax()sigue dando la posición: 22.idxmax()da la etiqueta del mayor valor: «Juego de cuchillos». También existeidxmin().
Las etiquetas viajan con los números: hagas lo que hagas con una Serie, el nombre se queda junto al precio.
La idea
Y de vuelta: reset_index
set_index no cambia products; devuelve una tabla nueva. La columna name es ahora su índice, así que hay 5 columnas en lugar de 6. reset_index() vuelve a convertir el índice en una columna normal y numera las filas desde 0 otra vez:
Qué va en el índice depende de la pregunta. Para «por nombre» pones ahí los nombres; para una tabla normal que vas a escribir en un archivo, los vuelves a convertir en una columna.
Pruébalo
El producto más barato
¿Qué producto es el más barato? Pon los nombres en el índice (by_name), y guarda en cheapest el nombre del producto con el menor precio.
Solución
import pandas as pd
products = pd.read_csv('products.csv')
by_name = products.set_index('name')
cheapest = by_name['price'].idxmin()
print(cheapest)by_name = products.set_index('name') y cheapest = by_name['price'].idxmin() da «Bollo de mantequilla» (0,80 €). argmin() devolvería 2: una posición, de la que todavía tienes que buscar el nombre. Sin set_index, idxmin() también da 2, porque entonces las etiquetas son los números de fila.
Míralo
El índice alinea la aritmética
El proveedor manda una lista de precios nueva. Los productos son los mismos, pero en otro orden. Con arreglos de NumPy restarías el primero del primero y el segundo del segundo. Con Series, pandas resta los valores con la misma etiqueta, estén donde estén:
Con Series, el café subió 1 €, el pan 0,10 € y el queso 0,50 €. Con los arreglos el primer número es 13,70 €: el precio nuevo del café menos el precio viejo del pan. El último es -12,30 €: la leche menos el café. Los números parecen perfectamente serios y están mal.
Esto se llama alineación por índice. El resultado queda ordenado por etiqueta, alfabéticamente.
Míralo
Una etiqueta que falta
Si una etiqueta está solo en una de las Series, pandas no tiene con qué calcularla:
El queso blanco está solo en esta semana, así que su diferencia es NaN. Es honesto: no sabemos cuánto queso vendimos la semana pasada. Viste en los resúmenes que faltante no es cero, y pandas lo respeta.
Más precisamente, para curiosos
Si sabes que faltante significa cero (un producto que no vendimos la semana pasada), dilo explícitamente: this_week.sub(last_week, fill_value=0). Así la decisión se ve en el código, no queda escondida. La alineación vale para +, -, *, / y para las comparaciones entre dos Series.
Pruébalo
Qué subió
Las dos listas de precios están en distinto orden. Guarda en change cuánto cambió el precio de cada producto (nuevo menos viejo), redondeado a 2 decimales, con los nombres de los productos en el índice.
Solución
import pandas as pd
old_prices = pd.Series([1.2, 1.6, 7.9, 13.9], index=['Pan blanco', 'Leche fresca', 'Queso blanco', 'Café en grano'])
new_prices = pd.Series([14.9, 1.3, 8.4, 1.6], index=['Café en grano', 'Pan blanco', 'Queso blanco', 'Leche fresca'])
change = (new_prices - old_prices).round(2)
print(change)change = (new_prices - old_prices).round(2): pandas encuentra cada producto en las dos listas. El café es +1,00 €, el queso +0,50 €, el pan +0,10 €, y la leche no cambia. Con to_numpy() los números se restan por lugar: el primero es 13,70 €, café nuevo menos pan viejo.
Ejercicio
El stock del almacén
Responde al gerente. Pon los nombres de los productos en el índice. Guarda en stock_value el valor del stock de cada producto (precio por stock), en total su suma, y en real_total la suma sin la tarjeta de regalo, redondeada a 2 decimales.
Solución
import pandas as pd
products = pd.read_csv('products.csv')
by_name = products.set_index('name')
stock_value = by_name['price'] * by_name['stock']
total = stock_value.sum()
real_total = round(total - stock_value['Tarjeta de regalo'], 2)
print(round(total, 2), real_total)stock_value = by_name['price'] * by_name['stock'] es una Serie con los nombres en el índice. total es 22 542,30 €, pero 19 980 € de eso es la tarjeta de regalo: stock 999 a 20 €. Del primer vistazo sabes que 999 significa «sin límite», no 999 tarjetas en el estante. real_total = total - stock_value['Tarjeta de regalo'] da 2562,30 €: ese es el stock. Con los nombres en el índice sacas la tarjeta por nombre, no por el número 24, que se mueve en cuanto la tabla se ordena de otra manera.
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: La primera tabla · El arreglo de NumPy · Vectorización · Resúmenes y valores faltantes
- Continúa en: Seleccionar: [], loc e iloc · Filtrar y ordenar · Columnas nuevas · Tipos y valores faltantes
- Ejercicios sobre el tema: Tablas con pandas