Las operaciones aritméticas son algunas de las cosas más fundamentales (e importantes) que puedes hacer con series y dataframes. En este artículo, aprenderemos cómo realizar operaciones básicas usando tanto series como dataframes.
Estamos interesados en los siguientes escenarios:
- Operaciones entre series con el mismo índice.
- Operaciones entre dataframes con el mismo índice.
- Operaciones entre dataframe/serie con el mismo índice.
- Operaciones entre series con diferentes índices.
- Operaciones entre dataframes con diferentes índices.
- Operaciones entre dataframe/serie con diferentes índices.
¡Bien, comencemos!
Mismo índice, comportamiento obvio
Si dos (o más) series/dataframes comparten el mismo índice (tanto el índice de fila como de columna en el caso de dataframes), las operaciones siguen el comportamiento obvio elemento por elemento que esperarías si has usado NumPy en el pasado:
import pandas as pd
ser_1 = pd.Series([1,2,3,4], index=['a', 'b', 'c', 'd'])
ser_2 = pd.Series([10,20,30,40], index=['a', 'b', 'c', 'd'])
print(ser_1)
print(ser_2)
a 1
b 2
c 3
d 4
dtype: int64
a 10
b 20
c 30
d 40
dtype: int64
# Suma de dos series con el mismo índice
ser_1 + ser_2
a 11
b 22
c 33
d 44
dtype: int64
# Resta de dos series con el mismo índice
ser_2 - ser_1
a 9
b 18
c 27
d 36
dtype: int64
# Multiplicación de dos series con el mismo índice
ser_1 * ser_2
a 10
b 40
c 90
d 160
dtype: int64
# División de dos series con el mismo índice
ser_2 / ser_1
a 10.0
b 10.0
c 10.0
d 10.0
dtype: float64
El mismo comportamiento se muestra cuando aplicas operaciones en dos dataframes que comparten tanto el índice de fila como de columna:
import numpy as np
df_1 = pd.DataFrame(np.arange(1,17).reshape(4,4),
index= ['Fi', 'Se', 'Th', 'Fo'],
columns = ['a', 'b', 'c', 'd'])
df_2 = pd.DataFrame(np.arange(1,17).reshape(4,4) * 10,
index= ['Fi', 'Se', 'Th', 'Fo'],
columns = ['a', 'b', 'c', 'd'])
df_1
a | b | c | d | |
---|---|---|---|---|
Fi | 1 | 2 | 3 | 4 |
Se | 5 | 6 | 7 | 8 |
Th | 9 | 10 | 11 | 12 |
Fo | 13 | 14 | 15 | 16 |
df_2
a | b | c | d | |
---|---|---|---|---|
Fi | 10 | 20 | 30 | 40 |
Se | 50 | 60 | 70 | 80 |
Th | 90 | 100 | 110 | 120 |
Fo | 130 | 140 | 150 | 160 |
# Suma de dos dataframes con el mismo índice
df_1 + df_2
a | b | c | d | |
---|---|---|---|---|
Fi | 11 | 22 | 33 | 44 |
Se | 55 | 66 | 77 | 88 |
Th | 99 | 110 | 121 | 132 |
Fo | 143 | 154 | 165 | 176 |
# Multiplicación de dos dataframes con el mismo índice
df_1 * df_2
a | b | c | d | |
---|---|---|---|---|
Fi | 10 | 40 | 90 | 160 |
Se | 250 | 360 | 490 | 640 |
Th | 810 | 1000 | 1210 | 1440 |
Fo | 1690 | 1960 | 2250 | 2560 |
También es posible realizar operaciones entre dataframes y series que comparten un índice. El comportamiento por defecto es alinear el índice de la serie con el índice de columna del dataframe y realizar las operaciones entre cada fila y la serie.
# Suma una serie y un dataframe
ser_1 + df_1
a | b | c | d | |
---|---|---|---|---|
Fi | 2 | 4 | 6 | 8 |
Se | 6 | 8 | 10 | 12 |
Th | 10 | 12 | 14 | 16 |
Fo | 14 | 16 | 18 | 20 |
Índice diferente, uniones externas
Si realizas operaciones entre series/dataframes con diferentes índices, el resultado será una nueva estructura de datos cuyo índice es la unión de los índices originales. Si has trabajado con bases de datos antes, esto es similar a una unión externa usando los índices de las series/dataframes originales. Esto es mucho más fácil de ver con un ejemplo:
ser_1 = pd.Series([1,1,1,1,1], index=['a', 'b', 'c', 'd', 'e'])
ser_2 = pd.Series([5,5,5,5,5], index=['c', 'd', 'e', 'f', 'g'])
print(ser_1)
print(ser_2)
a 1
b 1
c 1
d 1
e 1
dtype: int64
c 5
d 5
e 5
f 5
g 5
dtype: int64
Si la operación se realiza en series con diferentes índices, el resultado contendrá el resultado de la operación en todas las entradas cuyo índice esté contenido en la unión de los índices originales. Los elementos fuera de la unión se llenarán con NaN.
En este caso, la unión es ['c', 'd', 'e']
.
ser_1 + ser_2
a NaN
b NaN
c 6.0
d 6.0
e 6.0
f NaN
g NaN
dtype: float64
ser_1 * ser_2
a NaN
b NaN
c 5.0
d 5.0
e 5.0
f NaN
g NaN
dtype: float64
Los dataframes tienen el mismo comportamiento, pero las uniones se realizan tanto en el índice de fila como en el de columna.
import numpy as np
# En este caso, la unión son los elementos [a,b,c] en las columnas y [Fi,Fo,Th] en las filas
df_1 = pd.DataFrame(np.arange(1,17).reshape(4,4),
index= ['Fi', 'Ma', 'Th', 'Fo'],
columns = ['a', 'b', 'c', 'd'])
df_2 = pd.DataFrame(np.arange(1,17).reshape(4,4) * 10,
index= ['Fi', 'Se', 'Th', 'Fo'],
columns = ['a', 'b', 'c', 'e'])
df_1 + df_2
a | b | c | d | e | |
---|---|---|---|---|---|
Fi | 11.0 | 22.0 | 33.0 | NaN | NaN |
Fo | 143.0 | 154.0 | 165.0 | NaN | NaN |
Ma | NaN | NaN | NaN | NaN | NaN |
Se | NaN | NaN | NaN | NaN | NaN |
Th | 99.0 | 110.0 | 121.0 | NaN | NaN |
En el caso de operaciones entre dataframes y series con diferentes índices, se realizará una unión entre el índice de columna del dataframe y el índice de la serie:
df_1 + ser_2
a | b | c | d | e | f | g | |
---|---|---|---|---|---|---|---|
Fi | NaN | NaN | 8.0 | 9.0 | NaN | NaN | NaN |
Ma | NaN | NaN | 12.0 | 13.0 | NaN | NaN | NaN |
Th | NaN | NaN | 16.0 | 17.0 | NaN | NaN | NaN |
Fo | NaN | NaN | 20.0 | 21.0 | NaN | NaN | NaN |
Llenando valores faltantes
En lugar de usar los operadores aritméticos normales, puedes usar un conjunto de funciones integradas de Pandas que aceptan un argumento para llenar valores faltantes:
- add/radd
- sub/rsub
- div/rdiv
- mul/rmul
- pow/rpow
Revisemos la suma de series y usemos 0 como valor de marcador de posición:
ser_1.add(ser_2, fill_value=1)
a 2.0
b 2.0
c 6.0
d 6.0
e 6.0
f 6.0
g 6.0
dtype: float64
Si una entrada no está en la superposición de las dos series, la operación de suma se realizará contra un valor de marcador de posición de 0. Por ejemplo, para los índices a/b, ambos son 1+0, y para f/g es 5+0. El mismo comportamiento aplica a los dataframes.
¡Ahora sabes matemáticas!
Lo más difícil sobre trabajar con operaciones aritméticas usando estructuras de datos de pandas es entender cómo funciona cuando los índices no son los mismos. Mientras recuerdes que se comporta como una unión externa, todo será claro y fácil.
En el próximo artículo, hablaremos sobre mapeo y aplicación de funciones, ¡nuestros primeros temas avanzados de Pandas!
¡Gracias por leer!
Qué hacer después
- Comparte este artículo con amigos y colegas. Gracias por ayudarme a llegar a personas que podrían encontrar útil esta información.
- Puedes encontrar el código fuente para esta serie en este repositorio.
- Este artículo está basado en el libro: Python for Data Analysis.
- Envíame un email con preguntas, comentarios o sugerencias (está en la página Autor)