…para obtener nuevas series de datos derivadas de una serie original.
Muchas veces, cuando usamos pandas
, tenemos una serie de datos a la que le aplicamos una transformación. En muchos casos, esa transformación puede ser aplicarle una función. Por ejemplo, tengo una serie de datos de temperatura en grados Farenheit y la quiero transformar a grados Celsius. Podría aplicar algo como lo siguiente:
import numpy as np
import pandas as pd
df = pd.DataFrame({'T_Farenheit': range(100)})
df['T_Celsius'] = df.loc[:, 'T_Farenheit'].map(lambda t: (t - 32) * 5 / 9)
print(df)
El anterior DataFrame
se vería así:
T_Farenheit T_Celsius
0 0 -17.777778
1 1 -17.222222
2 2 -16.666667
3 3 -16.111111
4 4 -15.555556
.. ... ...
95 95 35.000000
96 96 35.555556
97 97 36.111111
98 98 36.666667
99 99 37.222222
[100 rows x 2 columns]
Esto está muy bien pero no siempre es lo que necesitamos porque no siempre tenemos una función que defina la transformación que necesitamos hacer de forma sencilla. Por ejemplo, podemos hacer un experimento del cual derivamos una Look-up table que nos permite transformar valores o podemos obtener esta Look-up Table de un artículo.
Como alternativa podemos usar un diccionario que haga un mapeo de los valores de la serie original a la serie que deseeamos obtener.
Un ejemplo (sin mucho sentido) de esto podría ser:
mapeo = {i: np.random.rand() for i in range(100)}
df['T_exp'] = df.loc[:, 'T_Farenheit'].map(mapeo)
print(df)
Y el anterior DataFrame
se vería ahora así:
T_Farenheit T_Celsius T_exp
0 0 -17.777778 0.687012
1 1 -17.222222 0.128531
2 2 -16.666667 0.324474
3 3 -16.111111 0.022591
4 4 -15.555556 0.889970
.. ... ... ...
95 95 35.000000 0.449293
96 96 35.555556 0.054644
97 97 36.111111 0.928684
98 98 36.666667 0.289097
99 99 37.222222 0.450386
[100 rows x 3 columns]
¿Qué pasaría si parte de los datos no estuvieran definidos en la transformación, estuvieran fuera de rango,etc? pandas
nos lo pone fácil ya que nos permite usar un diccionario que defina un método __missing__
(nuestra propia subclase de un diccionario). Por ejemplo, imaginemos que no tenemos valores definidos para los valores de partida superiores a 50? o que a partir de ese valor deberíamos considerarlos como constantes. Lo podríamos hacer así de la siguiente forma donde los valores por encima de 50? les doy un valor de -999 y a los que están por debajo les damos un valor aleatorio (valor sin sentido):
class MyDict(dict):
def __missing__(self, key):
return -999
mapeo = MyDict({i: np.random.randn() for i in range(51)})
df['T_map'] = df.loc[:, 'T_Farenheit'].map(mapeo)
print(df)
Y el resultado del anterior DataFrame
se vería:
T_Farenheit T_Celsius T_exp T_map
0 0 -17.777778 0.687012 0.510506
1 1 -17.222222 0.128531 -0.299574
2 2 -16.666667 0.324474 1.181474
3 3 -16.111111 0.022591 0.506276
4 4 -15.555556 0.889970 0.299538
.. ... ... ... ...
95 95 35.000000 0.449293 -999.000000
96 96 35.555556 0.054644 -999.000000
97 97 36.111111 0.928684 -999.000000
98 98 36.666667 0.289097 -999.000000
99 99 37.222222 0.450386 -999.000000
[100 rows x 4 columns]
Y eso es todo, un artículo sencillo sobre una funcionalidad de pandas
que no es nueva. El otro día me hizo falta y me he decidido a escribir sobre ello.