Gestionando la ausencia de datos
Ocurre con frecuencia que disponemos de catálogos de datos donde hay muestras incompletas. Por ejemplo, los datos obtenidos a partir de encuestas donde se registran preguntas sin responder o sensores que no proporcionan ningún valor viable, etc.
Hay que aceptarlo y saber gestionarlo
Pandas asigna el valor o el código NaN (Not a Number) a los valores desconocidos. Más especificamente, los objetos son designados como: None y las fechas como NaT.
Las operaciones que involucren este tipo de datos internamente han de manejar los correspondientes códigos: NaN, None o NaT. ¿Cómo afecta un NaN a una media aritmética?
En este capítulo trabajaremos con esta típología de valores.
[1]:
# Y finalmente, podemos asignar y usar nans
import numpy as np
datos = np.array([1,2,np.nan,4,5,6,np.nan,8])
print(datos)
print(datos.mean())
[ 1. 2. nan 4. 5. 6. nan 8.]
nan
[2]:
import pandas as pd
[8]:
#Empezamos cargando datos: who.csv con 358 columnas!
df = pd.read_csv("data/who.csv")
df.isna().sum()
# df = df[["Country",df.columns[-2]]]
# print(df[:5])
[8]:
Country 0
CountryID 0
Continent 0
Adolescent fertility rate (%) 25
Adult literacy rate (%) 71
..
Under_five_mortality_from_IHME 32
Under_five_mortality_rate 21
Urban_population 14
Urban_population_growth 14
Urban_population_pct_of_total 14
Length: 358, dtype: int64
[66]:
# Como ya sabéis através de la API se puede obtener una descripción más detallada de las posibilidades de cada método de Python, y en especial
# de los métodos de Pandas.
# Para cargar un fichero de tamaño elevado es recomendable cargar aquellos atributos que nos interesen desde un principio usando el argumento: usecols
# https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html
df = pd.read_csv("data/who.csv", usecols=["Country","Urban_population_growth"])
print(df[:5])
Country Urban_population_growth
0 Afghanistan 5.44
1 Albania 2.21
2 Algeria 2.61
3 Andorra NaN
4 Angola 4.14
[71]:
# ¿Qué valor corresponde a un NA del dataframe?
# https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.isna.html
df.isna().sum()
[71]:
Country 0
Urban_population_growth 14
dtype: int64
[ ]:
#¿Qué columnas tienen datos sin valor: NaN, NaT, None?
# https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.any.html
print(df.columns[df.isna().any()])
# Equivale a preguntar si ¿existe algún valor positivo dentro de esas series?
print("-"*30)
print(df..any())isna()
Index(['Urban_population_growth'], dtype='object')
------------------------------
Country False
Urban_population_growth True
dtype: bool
[31]:
#No dudéis en ejecutar "partes" (dividamos la instrucción para comprenderla)
print(df.isna()[:5])
Country Urban_population_growth
0 False False
1 False False
2 False False
3 False True
4 False False
[11]:
#¿Cuántas muestras son correctas?
df.notna().sum()
# https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.notna.html
# y de cuantas muestras?
[11]:
Country 202
Urban_population_growth 188
dtype: int64
[13]:
df.notnull().sum() #ambas funcionas son equivalentes en Pandas, no en numpy
[13]:
Country 202
Urban_population_growth 188
dtype: int64
Tratando la ausencia de datos
Ignorando: “Hay X muestras válidas de tantas”
Rellenando: reemplazar muestras desconocidas por otros valores: media, valor neutro, etc.
[39]:
#La manera más optima de remplazar estos valores es con la función: fillna
print(df.fillna(0)[:5])
Country Urban_population_growth
0 Afghanistan 5.44
1 Albania 2.21
2 Algeria 2.61
3 Andorra 0.00
4 Angola 4.14
[14]:
# Si queremos que nuestra variable de dataframe contenga dichas asignaciones recordad asignar la operación a la variable pertinente o a una nueva
df = df.fillna(0)
Maneras de rellenar una serie con datos NA
Cuando los dataframes contienen números la operabildad con valores perdidos puede gestionarse de manera más eficiente. Pongamos un ejemplo:
[5]:
import numpy as np
np.random.seed(20)
#Creamos un dataframe
df = pd.DataFrame(np.random.randn(5, 3),
index=['a', 'b', 'c', 'd', 'e'],
columns=['one', 'two', 'three'])
print(df)
one two three
a 0.883893 0.195865 0.357537
b -2.343262 -1.084833 0.559696
c 0.939469 -0.978481 0.503097
d 0.406414 0.323461 -0.493411
e -0.792017 -0.842368 -1.279503
[7]:
#Creamos valores NaN para testear
df.two[df.two<0]=np.nan
print(df)
one two three
a 0.883893 0.195865 0.357537
b -2.343262 NaN 0.559696
c 0.939469 NaN 0.503097
d 0.406414 0.323461 -0.493411
e -0.792017 NaN -1.279503
/var/folders/6j/7gfvt_29797dypw8t1wttblw0000gn/T/ipykernel_10061/13172693.py:2: FutureWarning: ChainedAssignmentError: behaviour will change in pandas 3.0!
You are setting values through chained assignment. Currently this works in certain cases, but when using Copy-on-Write (which will become the default behaviour in pandas 3.0) this will never work to update the original DataFrame or Series, because the intermediate object on which we are setting values will behave as a copy.
A typical example is when you are setting values in a column of a DataFrame, like:
df["col"][row_indexer] = value
Use `df.loc[row_indexer, "col"] = values` instead, to perform the assignment in a single step and ensure this keeps updating the original `df`.
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df.two[df.two<0]=np.nan
Podemos usar fillna para rellenar de diversas maneras la serie o series. Por ejemplo, usando una operación de agregación como la media
[21]:
print(df)
print("-"*33)
print(df.fillna(df.mean()))
one two three
a 0.883893 0.195865 0.357537
b -2.343262 NaN 0.559696
c 0.939469 NaN 0.503097
d 0.406414 0.323461 -0.493411
e -0.792017 NaN -1.279503
---------------------------------
one two three
a 0.883893 0.195865 0.357537
b -2.343262 0.259663 0.559696
c 0.939469 0.259663 0.503097
d 0.406414 0.323461 -0.493411
e -0.792017 0.259663 -1.279503
[30]:
#Con un valor en concreto del propio dataframe
print(df.fillna("HOLA"))
print("-"*33)
print(df.fillna(df.loc["a", ["one"]].values[0]))
one two three
a 0.883893 0.195865 0.357537
b -2.343262 HOLA 0.559696
c 0.939469 HOLA 0.503097
d 0.406414 0.323461 -0.493411
e -0.792017 HOLA -1.279503
---------------------------------
one two three
a 0.883893 0.195865 0.357537
b -2.343262 0.883893 0.559696
c 0.939469 0.883893 0.503097
d 0.406414 0.323461 -0.493411
e -0.792017 0.883893 -1.279503
Podemos rellenar con datos interpolados
En la documentación vemos una serie de ejemplos: Interpolate
[8]:
print(df)
print("-"*35)
print(df.interpolate())
one two three
a 0.883893 0.195865 0.357537
b -2.343262 NaN 0.559696
c 0.939469 NaN 0.503097
d 0.406414 0.323461 -0.493411
e -0.792017 NaN -1.279503
-----------------------------------
one two three
a 0.883893 0.195865 0.357537
b -2.343262 0.238397 0.559696
c 0.939469 0.280929 0.503097
d 0.406414 0.323461 -0.493411
e -0.792017 0.323461 -1.279503
[53]:
print(df.interpolate(axis=1)) # Tomemos como referencia el valor NA de (b,"two")
print("--"*35)
print(df.mean(axis=1).b)
one two three
a 0.883893 0.195865 0.357537
b -2.343262 -0.891783 0.559696
c 0.939469 0.721283 0.503097
d 0.406414 0.323461 -0.493411
e -0.792017 -1.035760 -1.279503
----------------------------------------------------------------------
-0.8917828081181468
[62]:
# Para usar otro tipo de interpolaciones es recomendable tener un índice numérico por cuestiones de frecuencia en el método de interpolación
df.index = range(len(df))
print(df.two.interpolate(method="pad"))
0 0.195865
1 0.195865
2 0.195865
3 0.323461
4 0.323461
Name: two, dtype: float64
[63]:
print(df.two.interpolate(method="nearest"))
0 0.195865
1 0.195865
2 0.323461
3 0.323461
4 NaN
Name: two, dtype: float64
[64]:
print("Valores interpolados:" + str(df.two.interpolate().count()-df.two.count()))
Valores interpolados:3
Eliminación de valores NA
Existen operaciones para la eliminación de valores NA
[31]:
print(df)
print("-"*35)
print(df.dropna())
# https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.dropna.html
one two three
a 0.883893 0.195865 0.357537
b -2.343262 NaN 0.559696
c 0.939469 NaN 0.503097
d 0.406414 0.323461 -0.493411
e -0.792017 NaN -1.279503
-----------------------------------
one two three
a 0.883893 0.195865 0.357537
d 0.406414 0.323461 -0.493411
[32]:
#O bien, podemos borrar cambiando el eje AXIS=0 o 1
df.dropna(axis=1)
[32]:
| one | three | |
|---|---|---|
| a | 0.883893 | 0.357537 |
| b | -2.343262 | 0.559696 |
| c | 0.939469 | 0.503097 |
| d | 0.406414 | -0.493411 |
| e | -0.792017 | -1.279503 |
[36]:
# el argumento AXIS está en un gran número de métodos de Pandas
print(df.mean()) # y por defecto, suele ser axis=0 (considerar las columnas ejeX)
print("-"*35)
print(df.mean(axis=1))
one -0.181100
two 0.259663
three -0.070517
dtype: float64
-----------------------------------
a 0.479098
b -0.891783
c 0.721283
d 0.078822
e -1.035760
dtype: float64
Ejercicios
1) Del fichero who.csv, contabiliza cuántos paises tienen algun valor NaN.
[ ]:
df = pd.read_csv("data/who.csv")
df.isna()
1b) Ordena el anterior resultado para identificar cuál es el pais con mayor número de campos desconocidos.
[ ]:
2) who.csv, Selecciona la primera, tercera y decima columna, de las filas comprendidas entre la 100 y la 150.
[ ]:
2b) ¿Cuántos valores NaN hay presentes?
[ ]:
2c) Crea un nuevo dataframe donde los NaN sean cero.
[ ]:
2d) Elimina aquellas filas de la anterior selección donde haya NaN.
[ ]:
Series Temporales
Las series temporales son muestras de valores tomadas a lo largo del tiempo con un muestreo generalmente equidistante. Por ejemplo, información económica, demográfica, meteorológica; registros de seguridad, actividad, etc.
La biblioteca Pandas gestiona las series temporales utilizando el índice: una fecha (datetime): https://docs.python.org/es/3/library/datetime.html
El índice de un dataframe es el pilar básico de acceso a los valores, por lo que su uso simplifica procesos de filtrado, selección, interpolación, etc.
Enlace a la documentación: TimeSeries
[9]:
import pandas as pd
df = pd.read_csv("data/rdu-weather-history.csv",sep=";")
#Qué contiene el fichero
print(df.head())
date temperaturemin temperaturemax precipitation snowfall \
0 2015-04-08 62.1 84.0 0.00 0.0
1 2015-04-20 63.0 78.1 0.28 0.0
2 2015-04-26 45.0 54.0 0.02 0.0
3 2015-04-28 39.0 69.1 0.00 0.0
4 2015-05-03 46.9 79.0 0.00 0.0
snowdepth avgwindspeed fastest2minwinddir fastest2minwindspeed \
0 0.0 5.82 40.0 29.97
1 0.0 11.86 180.0 21.92
2 0.0 5.82 50.0 12.97
3 0.0 2.68 40.0 12.08
4 0.0 2.68 200.0 12.08
fastest5secwinddir ... drizzle snow freezingrain smokehaze thunder \
0 30.0 ... No No No Yes No
1 170.0 ... No No No No Yes
2 40.0 ... No No No No No
3 40.0 ... No No No No No
4 210.0 ... No No No No No
highwind hail blowingsnow dust freezingfog
0 No No No No No
1 No No No No No
2 No No No No No
3 No No No No No
4 No No No No No
[5 rows x 28 columns]
[10]:
print(df.date.sort_values())
2509 2007-01-01
1065 2007-01-02
1066 2007-01-03
1067 2007-01-04
3251 2007-01-05
...
2507 2019-06-19
2508 2019-06-20
488 2019-06-21
489 2019-06-22
3623 2019-06-23
Name: date, Length: 4557, dtype: object
Nosotros solo cubriremos los aspectos básicos de estos tipos de datos; lo que queremos es poder responder preguntas similares a las siguientes: - ¿Cómo podría obtener la temperatura media de un año? - ¿Cómo podría obtener la temperatura más alta de todos los meses de julio?
En primer lugar, se ha de transformar el índice en una Fecha:
[16]:
from pandas import DatetimeIndex
import pandas as pd
df = pd.read_csv("data/rdu-weather-history.csv",sep=";")
df.index = DatetimeIndex(df["date"])
df.sort_index(inplace=True)
df.head()
[16]:
| date | temperaturemin | temperaturemax | precipitation | snowfall | snowdepth | avgwindspeed | fastest2minwinddir | fastest2minwindspeed | fastest5secwinddir | ... | drizzle | snow | freezingrain | smokehaze | thunder | highwind | hail | blowingsnow | dust | freezingfog | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| date | |||||||||||||||||||||
| 2007-01-01 | 2007-01-01 | 48.9 | 68.0 | 0.45 | 0.0 | 0.0 | 12.75 | 190.0 | 25.05 | 180.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2007-01-02 | 2007-01-02 | 32.0 | 55.9 | 0.00 | 0.0 | 0.0 | 3.13 | 320.0 | 12.97 | 330.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2007-01-03 | 2007-01-03 | 28.9 | 62.1 | 0.00 | 0.0 | 0.0 | 2.24 | 220.0 | 14.09 | 220.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2007-01-04 | 2007-01-04 | 46.0 | 69.1 | 0.00 | 0.0 | 0.0 | 4.47 | 220.0 | 14.09 | 230.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2007-01-05 | 2007-01-05 | 57.0 | 72.0 | 0.86 | 0.0 | 0.0 | 8.05 | 190.0 | 21.03 | 190.0 | ... | No | No | No | No | No | No | No | No | No | No |
5 rows × 28 columns
[12]:
df = df.drop(columns="date")
[17]:
df.index.day
[17]:
Index([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
...
14, 15, 16, 17, 18, 19, 20, 21, 22, 23],
dtype='int32', name='date', length=4557)
[18]:
df.loc["2014"]
[18]:
| date | temperaturemin | temperaturemax | precipitation | snowfall | snowdepth | avgwindspeed | fastest2minwinddir | fastest2minwindspeed | fastest5secwinddir | ... | drizzle | snow | freezingrain | smokehaze | thunder | highwind | hail | blowingsnow | dust | freezingfog | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| date | |||||||||||||||||||||
| 2014-01-01 | 2014-01-01 | 29.1 | 51.1 | 0.00 | 0.0 | 0.0 | 2.46 | 200.0 | 8.95 | 210.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2014-01-02 | 2014-01-02 | 37.0 | 48.9 | 0.33 | 0.0 | 0.0 | 2.68 | 310.0 | 12.97 | 320.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2014-01-03 | 2014-01-03 | 22.1 | 43.0 | 0.00 | 0.0 | 0.0 | 7.38 | 300.0 | 21.92 | 310.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2014-01-04 | 2014-01-04 | 19.2 | 37.9 | 0.00 | 0.0 | 0.0 | 2.24 | 120.0 | 8.05 | 120.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2014-01-05 | 2014-01-05 | 37.0 | 62.1 | 0.00 | 0.0 | 0.0 | 4.92 | 180.0 | 16.11 | 180.0 | ... | No | No | No | No | No | No | No | No | No | No |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2014-12-27 | 2014-12-27 | 31.1 | 62.1 | 0.00 | 0.0 | 0.0 | 3.13 | 230.0 | 12.08 | 240.0 | ... | No | No | No | Yes | No | No | No | No | No | No |
| 2014-12-28 | 2014-12-28 | 48.0 | 61.0 | 0.01 | 0.0 | 0.0 | 6.71 | 230.0 | 14.99 | 230.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2014-12-29 | 2014-12-29 | 41.0 | 55.0 | 0.72 | 0.0 | 0.0 | 6.71 | 30.0 | 12.08 | 50.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2014-12-30 | 2014-12-30 | 28.2 | 41.0 | 0.02 | 0.0 | 0.0 | 5.82 | 40.0 | 17.00 | 40.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2014-12-31 | 2014-12-31 | 26.2 | 46.0 | 0.00 | 0.0 | 0.0 | 1.34 | 50.0 | 8.95 | 270.0 | ... | No | No | No | No | No | No | No | No | No | No |
365 rows × 28 columns
[19]:
df.loc["2014-01-03"]
[19]:
date 2014-01-03
temperaturemin 22.1
temperaturemax 43.0
precipitation 0.0
snowfall 0.0
snowdepth 0.0
avgwindspeed 7.38
fastest2minwinddir 300.0
fastest2minwindspeed 21.92
fastest5secwinddir 310.0
fastest5secwindspeed 31.99
fog No
fogheavy No
mist No
rain No
fogground No
ice No
glaze No
drizzle No
snow No
freezingrain No
smokehaze No
thunder No
highwind No
hail No
blowingsnow No
dust No
freezingfog No
Name: 2014-01-03 00:00:00, dtype: object
[20]:
df.loc["2014":"2016"]
[20]:
| date | temperaturemin | temperaturemax | precipitation | snowfall | snowdepth | avgwindspeed | fastest2minwinddir | fastest2minwindspeed | fastest5secwinddir | ... | drizzle | snow | freezingrain | smokehaze | thunder | highwind | hail | blowingsnow | dust | freezingfog | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| date | |||||||||||||||||||||
| 2014-01-01 | 2014-01-01 | 29.1 | 51.1 | 0.00 | 0.0 | 0.0 | 2.46 | 200.0 | 8.95 | 210.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2014-01-02 | 2014-01-02 | 37.0 | 48.9 | 0.33 | 0.0 | 0.0 | 2.68 | 310.0 | 12.97 | 320.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2014-01-03 | 2014-01-03 | 22.1 | 43.0 | 0.00 | 0.0 | 0.0 | 7.38 | 300.0 | 21.92 | 310.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2014-01-04 | 2014-01-04 | 19.2 | 37.9 | 0.00 | 0.0 | 0.0 | 2.24 | 120.0 | 8.05 | 120.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2014-01-05 | 2014-01-05 | 37.0 | 62.1 | 0.00 | 0.0 | 0.0 | 4.92 | 180.0 | 16.11 | 180.0 | ... | No | No | No | No | No | No | No | No | No | No |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2016-12-27 | 2016-12-27 | 52.0 | 68.0 | 0.01 | 0.0 | 0.0 | 10.29 | 240.0 | 19.91 | 230.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2016-12-28 | 2016-12-28 | 36.0 | 60.1 | 0.00 | 0.0 | 0.0 | 2.91 | 10.0 | 8.95 | 20.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2016-12-29 | 2016-12-29 | 39.0 | 63.0 | 0.35 | 0.0 | 0.0 | 7.83 | 290.0 | 21.92 | 320.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2016-12-30 | 2016-12-30 | 28.2 | 48.0 | 0.00 | 0.0 | 0.0 | 8.28 | 280.0 | 21.03 | 280.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2016-12-31 | 2016-12-31 | 23.2 | 50.0 | 0.00 | 0.0 | 0.0 | 8.72 | 220.0 | 21.03 | 230.0 | ... | No | No | No | No | No | No | No | No | No | No |
1096 rows × 28 columns
[7]:
# Aggregations
df.loc["2015"].temperaturemin.mean()
[7]:
51.70246575342466
[16]:
# Conditional operatives
df.loc["2015"].temperaturemin.min() > df.loc["2016"].temperaturemin.min()
[16]:
False
[9]:
# Slicing
df.loc["2015":"2019"]
df.index.dtype
[9]:
dtype('<M8[ns]')
Actividades
¿Cuántas veces ha nevado por año (
snowfall)?
[21]:
pd.__version__
[21]:
'2.2.2'
[ ]:
df.groupby(df.index.year).agg()
<bound method DataFrameGroupBy.aggregate of <pandas.core.groupby.generic.DataFrameGroupBy object at 0x1059fa950>>
¿En qué año se han registrado más nieve (
snowdepth)?
[ ]:
Crea un dataframe que contenga la temperatura máxima de julio por cada año.
Haz una agrupación que contenga las temperaturas máximas y mínimas de cada mes de cada año.
Pivotar una tabla consiste en organizar las columnas a filas o las filas a columnas. Con ello disponemos los datos transpuestos a la modelización original.
Enlace a la documentación: - https://pandas.pydata.org/docs/reference/api/pandas.pivot_table.html - https://pandas.pydata.org/docs/reference/api/pandas.pivot.html
[25]:
import pandas as pd
import numpy as np
samples=5
df= pd.DataFrame(
{
"Municipio":np.repeat(["muni%i"%i for i in range(samples)],3) ,
"Categoria" :["Inscritos","Censo","Población"]*(samples),
"Values" : np.random.randint(1,10,samples*3)
})
print(df)
Municipio Categoria Values
0 muni0 Inscritos 7
1 muni0 Censo 5
2 muni0 Población 7
3 muni1 Inscritos 5
4 muni1 Censo 9
5 muni1 Población 7
6 muni2 Inscritos 3
7 muni2 Censo 4
8 muni2 Población 2
9 muni3 Inscritos 6
10 muni3 Censo 3
11 muni3 Población 2
12 muni4 Inscritos 9
13 muni4 Censo 3
14 muni4 Población 5
[ ]:
df[df["Categoria"]=="Censo"].mean()
[32]:
# indexcolumn, Grouper, array, or list of the previous
# Keys to group by on the pivot table index. If a list is passed, it can contain any of the other types (except list).
# If an array is passed, it must be the same length as the data and will be used in the same manner as column values.
pd.pivot_table(df, index=['Categoria'],values="Values")
[32]:
| Values | |
|---|---|
| Categoria | |
| Censo | 4.8 |
| Inscritos | 6.0 |
| Población | 4.6 |
[3]:
# columnscolumn, Grouper, array, or list of the previous
# Keys to group by on the pivot table column. If a list is passed, it can contain any of the other types (except list).
# If an array is passed, it must be the same length as the data and will be used in the same manner as column values.
pd.pivot_table(df, columns=['Categoria'])
/var/folders/6j/7gfvt_29797dypw8t1wttblw0000gn/T/ipykernel_82835/1386358381.py:4: FutureWarning: pivot_table dropped a column because it failed to aggregate. This behavior is deprecated and will raise in a future version of pandas. Select only the columns that can be aggregated.
pd.pivot_table(df, columns=['Categoria'])
[3]:
| Categoria | Censo | Inscritos | Población |
|---|---|---|---|
| Values | 4.8 | 6.4 | 6.6 |
[34]:
df2 = pd.pivot_table(df, index=['Municipio'],columns=["Categoria"])
df2
[34]:
| Values | |||
|---|---|---|---|
| Categoria | Censo | Inscritos | Población |
| Municipio | |||
| muni0 | 5.0 | 7.0 | 7.0 |
| muni1 | 9.0 | 5.0 | 7.0 |
| muni2 | 4.0 | 3.0 | 2.0 |
| muni3 | 3.0 | 6.0 | 2.0 |
| muni4 | 3.0 | 9.0 | 5.0 |
[ ]:
df2["Censo"].mean() #Alerta, pivotar también genera multi-columas/indices.
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
File ~/.pyenv/versions/3.11.0rc2/envs/my3110/lib/python3.11/site-packages/pandas/core/indexes/base.py:3805, in Index.get_loc(self, key)
3804 try:
-> 3805 return self._engine.get_loc(casted_key)
3806 except KeyError as err:
File index.pyx:167, in pandas._libs.index.IndexEngine.get_loc()
File index.pyx:196, in pandas._libs.index.IndexEngine.get_loc()
File pandas/_libs/hashtable_class_helper.pxi:7081, in pandas._libs.hashtable.PyObjectHashTable.get_item()
File pandas/_libs/hashtable_class_helper.pxi:7089, in pandas._libs.hashtable.PyObjectHashTable.get_item()
KeyError: 'Censo'
The above exception was the direct cause of the following exception:
KeyError Traceback (most recent call last)
Cell In[35], line 1
----> 1 df2["Censo"].mean()
File ~/.pyenv/versions/3.11.0rc2/envs/my3110/lib/python3.11/site-packages/pandas/core/frame.py:4101, in DataFrame.__getitem__(self, key)
4099 if is_single_key:
4100 if self.columns.nlevels > 1:
-> 4101 return self._getitem_multilevel(key)
4102 indexer = self.columns.get_loc(key)
4103 if is_integer(indexer):
File ~/.pyenv/versions/3.11.0rc2/envs/my3110/lib/python3.11/site-packages/pandas/core/frame.py:4159, in DataFrame._getitem_multilevel(self, key)
4157 def _getitem_multilevel(self, key):
4158 # self.columns is a MultiIndex
-> 4159 loc = self.columns.get_loc(key)
4160 if isinstance(loc, (slice, np.ndarray)):
4161 new_columns = self.columns[loc]
File ~/.pyenv/versions/3.11.0rc2/envs/my3110/lib/python3.11/site-packages/pandas/core/indexes/multi.py:3040, in MultiIndex.get_loc(self, key)
3037 return mask
3039 if not isinstance(key, tuple):
-> 3040 loc = self._get_level_indexer(key, level=0)
3041 return _maybe_to_slice(loc)
3043 keylen = len(key)
File ~/.pyenv/versions/3.11.0rc2/envs/my3110/lib/python3.11/site-packages/pandas/core/indexes/multi.py:3391, in MultiIndex._get_level_indexer(self, key, level, indexer)
3388 return slice(i, j, step)
3390 else:
-> 3391 idx = self._get_loc_single_level_index(level_index, key)
3393 if level > 0 or self._lexsort_depth == 0:
3394 # Desired level is not sorted
3395 if isinstance(idx, slice):
3396 # test_get_loc_partial_timestamp_multiindex
File ~/.pyenv/versions/3.11.0rc2/envs/my3110/lib/python3.11/site-packages/pandas/core/indexes/multi.py:2980, in MultiIndex._get_loc_single_level_index(self, level_index, key)
2978 return -1
2979 else:
-> 2980 return level_index.get_loc(key)
File ~/.pyenv/versions/3.11.0rc2/envs/my3110/lib/python3.11/site-packages/pandas/core/indexes/base.py:3812, in Index.get_loc(self, key)
3807 if isinstance(casted_key, slice) or (
3808 isinstance(casted_key, abc.Iterable)
3809 and any(isinstance(x, slice) for x in casted_key)
3810 ):
3811 raise InvalidIndexError(key)
-> 3812 raise KeyError(key) from err
3813 except TypeError:
3814 # If we have a listlike key, _check_indexing_error will raise
3815 # InvalidIndexError. Otherwise we fall through and re-raise
3816 # the TypeError.
3817 self._check_indexing_error(key)
KeyError: 'Censo'
[5]:
# aggfuncfunction, list of functions, dict, default “mean”
# If a list of functions is passed, the resulting pivot table will have hierarchical columns whose top level are the function names
# (inferred from the function objects themselves).
pd.pivot_table(df, index=['Categoria'], aggfunc=sum)
/var/folders/6j/7gfvt_29797dypw8t1wttblw0000gn/T/ipykernel_82835/1620381455.py:4: FutureWarning: The operation <built-in function sum> failed on a column. If any error is raised, this will raise an exception in a future version of pandas. Drop these columns to avoid this warning.
pd.pivot_table(df, index=['Categoria'], aggfunc=sum)
[5]:
| Values | |
|---|---|
| Categoria | |
| Censo | 24 |
| Inscritos | 32 |
| Población | 33 |
[ ]: