Pandas práctico(4): Aritmética con DataFrames y Series

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

Juan Luis Orozco Villalobos

¡Hola! Soy Juan, ingeniero de software y consultor en Budapest. Me especializo en computación en la nube e IA, y me encanta ayudar a otros a aprender sobre tecnología e ingeniería