Aplicación 1.2: Exploración de datos
Comparación de los lenguajes R y Python
En esta aplicación se usarán las librerías estándar de R y Python para explorar la base de datos seleccionada, replicando los resultados con los correspondientes comandos en ambos lenguajes.
En concreto, para el lenguaje R se utilizará la colección de librerías contenidas en el paquete tidyverse (https://www.tidyverse.org/packages/), y para Python se usarán las librerías numpy (https://numpy.org/), pandas (https://pandas.pydata.org/), matplotlib (https://matplotlib.org/) y seaborn (https://seaborn.pydata.org/). Las librerías especializadas en estadística y econometría se verán en aplicaciones posteriores.
Lectura de librerías
Code
library(tidyverse)
# Datos de la aplicación: base de datos palmerpenguins
# (https://allisonhorst.github.io/palmerpenguins/)
library(palmerpenguins)Lectura de datos
Code
data("penguins")
df <- penguins
df %>%
head()# A tibble: 6 × 8
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
<fct> <fct> <dbl> <dbl> <int> <int>
1 Adelie Torgersen 39.1 18.7 181 3750
2 Adelie Torgersen 39.5 17.4 186 3800
3 Adelie Torgersen 40.3 18 195 3250
4 Adelie Torgersen NA NA NA NA
5 Adelie Torgersen 36.7 19.3 193 3450
6 Adelie Torgersen 39.3 20.6 190 3650
# ℹ 2 more variables: sex <fct>, year <int>
Análisis exploratorio
Recuento de casos:
Recuento de los NAs en cada columna
Code
df %>%
summarize(across(.cols = everything(),
~sum(is.na(.x)))) %>%
pivot_longer(cols = everything())# A tibble: 8 × 2
name value
<chr> <int>
1 species 0
2 island 0
3 bill_length_mm 2
4 bill_depth_mm 2
5 flipper_length_mm 2
6 body_mass_g 2
7 sex 11
8 year 0
Para eliminar todas las filas con un NA habría que ejecutar el siguiente código
Code
# df <- df %>% na.omit()Número de especies
Code
df %>%
count(species, sort = TRUE)# A tibble: 3 × 2
species n
<fct> <int>
1 Adelie 152
2 Gentoo 124
3 Chinstrap 68
Número de islas
Code
df %>%
count(island, sort = TRUE)# A tibble: 3 × 2
island n
<fct> <int>
1 Biscoe 168
2 Dream 124
3 Torgersen 52
Número de especies en cada isla
Code
df %>%
count(species, island, sort = TRUE)# A tibble: 5 × 3
species island n
<fct> <fct> <int>
1 Gentoo Biscoe 124
2 Chinstrap Dream 68
3 Adelie Dream 56
4 Adelie Torgersen 52
5 Adelie Biscoe 44
Tabla 3x3 de recuento de especies por isla
Code
table(species = df$species,
island = df$island) island
species Biscoe Dream Torgersen
Adelie 44 56 52
Chinstrap 0 68 0
Gentoo 124 0 0
Tabla 3x3 de proporciones de especies por isla
Code
table(species = df$species,
island = df$island) / nrow(df) island
species Biscoe Dream Torgersen
Adelie 0.1279070 0.1627907 0.1511628
Chinstrap 0.0000000 0.1976744 0.0000000
Gentoo 0.3604651 0.0000000 0.0000000
Gráfico de barras de especies
Code
df %>%
count(species, sort = TRUE) %>%
ggplot(aes(x = reorder(species, -n), y = n)) +
geom_col(aes(fill = species)) +
xlab('species')Descripción de todas la columnas de la base de datos
Code
summary(df) species island bill_length_mm bill_depth_mm
Adelie :152 Biscoe :168 Min. :32.10 Min. :13.10
Chinstrap: 68 Dream :124 1st Qu.:39.23 1st Qu.:15.60
Gentoo :124 Torgersen: 52 Median :44.45 Median :17.30
Mean :43.92 Mean :17.15
3rd Qu.:48.50 3rd Qu.:18.70
Max. :59.60 Max. :21.50
NA's :2 NA's :2
flipper_length_mm body_mass_g sex year
Min. :172.0 Min. :2700 female:165 Min. :2007
1st Qu.:190.0 1st Qu.:3550 male :168 1st Qu.:2007
Median :197.0 Median :4050 NA's : 11 Median :2008
Mean :200.9 Mean :4202 Mean :2008
3rd Qu.:213.0 3rd Qu.:4750 3rd Qu.:2009
Max. :231.0 Max. :6300 Max. :2009
NA's :2 NA's :2
Cálculo de la media de la longitud y la profundidad del pico
Code
df %>%
select(bill_length_mm, bill_depth_mm) %>%
summarize(across(.cols = everything(),
~mean(.x, na.rm = TRUE)))# A tibble: 1 × 2
bill_length_mm bill_depth_mm
<dbl> <dbl>
1 43.9 17.2
Cálculo de los cuantiles 25, 50 y 75 para la longitud y profundidad del pico en la Isla Biscoe
Code
df %>%
filter(island == "Biscoe") %>%
select(bill_length_mm, bill_depth_mm) %>%
summarize(length25 = quantile(bill_length_mm, probs = 0.25, na.rm = TRUE),
length50 = quantile(bill_length_mm, probs = 0.50, na.rm = TRUE),
length75 = quantile(bill_length_mm, probs = 0.75, na.rm = TRUE),
depth25 = quantile(bill_depth_mm, probs = 0.25, na.rm = TRUE),
depth50 = quantile(bill_depth_mm, probs = 0.50, na.rm = TRUE),
depth75 = quantile(bill_depth_mm, probs = 0.75, na.rm = TRUE))# A tibble: 1 × 6
length25 length50 length75 depth25 depth50 depth75
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 42 45.8 48.7 14.5 15.5 17
Diagrama de cajas (boxplot) vertical de la longitud del pico por especie
Code
df %>%
ggplot(aes(x = species, y = bill_length_mm, fill = species)) +
geom_boxplot()Warning: Removed 2 rows containing non-finite outside the scale range
(`stat_boxplot()`).
Boxplot horizontal
Code
df %>%
ggplot(aes(x = bill_length_mm, y = species, fill = species)) +
geom_boxplot()Warning: Removed 2 rows containing non-finite outside the scale range
(`stat_boxplot()`).
Densidad estimada de la longitud del pico agrupada por sexo
Code
df %>%
na.omit() %>%
ggplot(aes(x = bill_length_mm, fill = sex)) +
geom_density(alpha = 0.4)con facetas por especie
Code
df %>%
na.omit() %>%
ggplot(aes(x = bill_length_mm, fill = sex)) +
geom_density(alpha = 0.4) +
facet_wrap(~species)Diagrama de dispersión de la masa corporal en relación con la longitud de las aletas
Code
df %>%
ggplot(aes(x = flipper_length_mm, y = body_mass_g)) +
geom_point()Warning: Removed 2 rows containing missing values or values outside the scale range
(`geom_point()`).
con línea de regresión añadida
Code
df %>%
ggplot(aes(x = flipper_length_mm, y = body_mass_g)) +
geom_point() +
geom_smooth(method = "lm")`geom_smooth()` using formula = 'y ~ x'
Warning: Removed 2 rows containing non-finite outside the scale range
(`stat_smooth()`).
Warning: Removed 2 rows containing missing values or values outside the scale range
(`geom_point()`).
Diferenciado por sexo
Code
df %>%
ggplot(aes(x = flipper_length_mm, y = body_mass_g,
color = sex)) +
geom_point()Warning: Removed 2 rows containing missing values or values outside the scale range
(`geom_point()`).
con línea de regresión añadida
Code
df %>%
filter(!is.na(sex)) %>%
ggplot(aes(x = flipper_length_mm, y = body_mass_g,
color = sex)) +
geom_point() +
geom_smooth(method = "lm")`geom_smooth()` using formula = 'y ~ x'
Variación de la masa corporal media a lo largo de los años por especie
Code
df %>%
group_by(species, year) %>%
summarize(N = n(),
avg = mean(body_mass_g, na.rm = TRUE),
SE = sd(body_mass_g, na.rm = TRUE) / sqrt(N),
.groups = "drop") %>%
ggplot(aes(x = year, y = avg)) +
geom_ribbon(aes(ymin = avg - SE, ymax = avg + SE,
fill = species),
alpha = 0.3) +
geom_line(aes(color = species))Agrupación - resumen
Media y desviación estándar de la longitud del pico para cada especie
Code
df %>%
group_by(species) %>%
summarize(avg_bill_length = mean(bill_length_mm, na.rm = TRUE),
sd_bill_length = sd(bill_length_mm, na.rm = TRUE))# A tibble: 3 × 3
species avg_bill_length sd_bill_length
<fct> <dbl> <dbl>
1 Adelie 38.8 2.66
2 Chinstrap 48.8 3.34
3 Gentoo 47.5 3.08
Media y desviación estándar de la longitud del pico de cada especie por sexo
Code
df %>%
filter(!is.na(sex)) %>%
group_by(species, sex) %>%
summarize(avg_bill_length = mean(bill_length_mm, na.rm = TRUE),
sd_bill_length = sd(bill_length_mm, na.rm = TRUE))`summarise()` has grouped output by 'species'. You can override using the
`.groups` argument.
# A tibble: 6 × 4
# Groups: species [3]
species sex avg_bill_length sd_bill_length
<fct> <fct> <dbl> <dbl>
1 Adelie female 37.3 2.03
2 Adelie male 40.4 2.28
3 Chinstrap female 46.6 3.11
4 Chinstrap male 51.1 1.56
5 Gentoo female 45.6 2.05
6 Gentoo male 49.5 2.72
Agrupación - cálculo
Añadir una nueva columna al fichero de datos que muestre la longitud media de las aletas agrupadas por especies
Code
df <- df %>%
group_by(species) %>%
mutate(mean_flipper_length = mean(flipper_length_mm, na.rm = TRUE))
df %>%
head()# A tibble: 6 × 9
# Groups: species [1]
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
<fct> <fct> <dbl> <dbl> <int> <int>
1 Adelie Torgersen 39.1 18.7 181 3750
2 Adelie Torgersen 39.5 17.4 186 3800
3 Adelie Torgersen 40.3 18 195 3250
4 Adelie Torgersen NA NA NA NA
5 Adelie Torgersen 36.7 19.3 193 3450
6 Adelie Torgersen 39.3 20.6 190 3650
# ℹ 3 more variables: sex <fct>, year <int>, mean_flipper_length <dbl>
Puntuación estandarizada (z-score) por especie para la longitud de las aletas
Code
df <- df %>%
group_by(species) %>%
mutate(flipper_z = (flipper_length_mm - mean(flipper_length_mm, na.rm = TRUE)) / sd(flipper_length_mm, na.rm = TRUE))
df %>%
head()# A tibble: 6 × 10
# Groups: species [1]
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
<fct> <fct> <dbl> <dbl> <int> <int>
1 Adelie Torgersen 39.1 18.7 181 3750
2 Adelie Torgersen 39.5 17.4 186 3800
3 Adelie Torgersen 40.3 18 195 3250
4 Adelie Torgersen NA NA NA NA
5 Adelie Torgersen 36.7 19.3 193 3450
6 Adelie Torgersen 39.3 20.6 190 3650
# ℹ 4 more variables: sex <fct>, year <int>, mean_flipper_length <dbl>,
# flipper_z <dbl>
Añadir una columna para la media y la desviación estándar por especie para la longitud del pico
Code
df <- df %>%
group_by(species) %>%
mutate(mean_val = mean(bill_length_mm, na.rm = TRUE),
sd_val = sd(bill_length_mm, na.rm = TRUE))
df %>%
head()# A tibble: 6 × 12
# Groups: species [1]
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
<fct> <fct> <dbl> <dbl> <int> <int>
1 Adelie Torgersen 39.1 18.7 181 3750
2 Adelie Torgersen 39.5 17.4 186 3800
3 Adelie Torgersen 40.3 18 195 3250
4 Adelie Torgersen NA NA NA NA
5 Adelie Torgersen 36.7 19.3 193 3450
6 Adelie Torgersen 39.3 20.6 190 3650
# ℹ 6 more variables: sex <fct>, year <int>, mean_flipper_length <dbl>,
# flipper_z <dbl>, mean_val <dbl>, sd_val <dbl>
Lectura de librerías
Code
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# Datos de la aplicación: base datos palmerpenguins
# (https://github.com/mcnakhaee/palmerpenguins)
from palmerpenguins import load_penguinsLectura de datos
Code
df = load_penguins()
df.head() species island bill_length_mm ... body_mass_g sex year
0 Adelie Torgersen 39.1 ... 3750.0 male 2007
1 Adelie Torgersen 39.5 ... 3800.0 female 2007
2 Adelie Torgersen 40.3 ... 3250.0 female 2007
3 Adelie Torgersen NaN ... NaN NaN 2007
4 Adelie Torgersen 36.7 ... 3450.0 female 2007
[5 rows x 8 columns]
Análisis exploratorio
Recuento de casos:
Recuento de los NAs en cada columna
Code
df.isnull().any()species False
island False
bill_length_mm True
bill_depth_mm True
flipper_length_mm True
body_mass_g True
sex True
year False
dtype: bool
Code
len(df) - df.count()species 0
island 0
bill_length_mm 2
bill_depth_mm 2
flipper_length_mm 2
body_mass_g 2
sex 11
year 0
dtype: int64
Para eliminar todas las filas con un NA habría que ejecutar el siguiente código
Code
# df = df.dropna()Número de especies
Code
df['species'].value_counts()species
Adelie 152
Gentoo 124
Chinstrap 68
Name: count, dtype: int64
Número de islas
Code
df['island'].value_counts()island
Biscoe 168
Dream 124
Torgersen 52
Name: count, dtype: int64
Número de especies en cada isla
Code
df[['species', 'island']].value_counts()species island
Gentoo Biscoe 124
Chinstrap Dream 68
Adelie Dream 56
Torgersen 52
Biscoe 44
Name: count, dtype: int64
Tabla 3x3 de recuento de especies por isla
Code
pd.crosstab(df['species'], df['island'])island Biscoe Dream Torgersen
species
Adelie 44 56 52
Chinstrap 0 68 0
Gentoo 124 0 0
Tabla 3x3 de proporciones de especies por isla
Code
pd.crosstab(df['species'], df['island']) / len(df)island Biscoe Dream Torgersen
species
Adelie 0.127907 0.162791 0.151163
Chinstrap 0.000000 0.197674 0.000000
Gentoo 0.360465 0.000000 0.000000
Gráfico de barras de especies
Code
sns.countplot(x = 'species', data = df);
plt.show()Descripción de todas la columnas de la base de datos
Code
df.describe() bill_length_mm bill_depth_mm ... body_mass_g year
count 342.000000 342.000000 ... 342.000000 344.000000
mean 43.921930 17.151170 ... 4201.754386 2008.029070
std 5.459584 1.974793 ... 801.954536 0.818356
min 32.100000 13.100000 ... 2700.000000 2007.000000
25% 39.225000 15.600000 ... 3550.000000 2007.000000
50% 44.450000 17.300000 ... 4050.000000 2008.000000
75% 48.500000 18.700000 ... 4750.000000 2009.000000
max 59.600000 21.500000 ... 6300.000000 2009.000000
[8 rows x 5 columns]
Cálculo de la media de la longitud y la profundidad del pico
Code
df[['bill_length_mm', 'bill_depth_mm']].mean()bill_length_mm 43.92193
bill_depth_mm 17.15117
dtype: float64
Cálculo de los cuantiles 25, 50 y 75 para la longitud y profundidad del pico en la Isla Biscoe
Code
df.loc[df['island'] == 'Biscoe', ['bill_length_mm', 'bill_depth_mm']].quantile([0.25, 0.5, 0.75]) bill_length_mm bill_depth_mm
0.25 42.0 14.5
0.50 45.8 15.5
0.75 48.7 17.0
Boxplot vertical de la longitud del pico por especie
Code
sns.boxplot(x = 'species', y = 'bill_length_mm', data = df, orient = 'v', palette = 'rainbow');<string>:1: FutureWarning:
Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `x` variable to `hue` and set `legend=False` for the same effect.
Code
plt.show()Boxplot horizontal
Code
sns.boxplot(x = 'bill_length_mm', y = 'species', data = df, orient = 'h', palette = 'rainbow');<string>:1: FutureWarning:
Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `y` variable to `hue` and set `legend=False` for the same effect.
Code
plt.show()Densidad estimada de la longitud del pico agrupada por sexo
Code
sns.displot(x = 'bill_length_mm',
data = df,
kind = 'kde',
hue = 'sex',
fill = True);
plt.show()con facetas por especie
Code
sns.displot(x = 'bill_length_mm',
data = df,
kind = 'kde',
hue = 'sex',
col = 'species',
fill = True);
plt.show()Diagrama de dispersión de la masa corporal en relación con la longitud de las aletas
Code
sns.relplot(x = 'flipper_length_mm', y = 'body_mass_g', data = df);
plt.show()con línea de regresión añadida
Code
sns.lmplot(x = 'flipper_length_mm', y = 'body_mass_g', data = df);
plt.show()Diferenciado por sexo
Code
sns.relplot(x = 'flipper_length_mm', y = 'body_mass_g', data = df, hue = 'sex');
plt.show()y con línea de regresión añadida
Code
sns.lmplot(x = 'flipper_length_mm', y = 'body_mass_g', data = df, hue = 'sex');
plt.show()Variación de la masa corporal media a lo largo de los años por especie
Code
sns.relplot(x = 'year', y = 'body_mass_g', kind = 'line',
hue = 'species', data = df);
plt.show()Agrupación - resumen
Media y desviación estándar de la longitud del pico para cada especie
Code
species_bill_length = (df
.groupby('species')
.agg(avg_bill_length = ('bill_length_mm', 'mean'),
sd_bill_length = ('bill_length_mm', 'std')).round(1)
.reset_index())
species_bill_length species avg_bill_length sd_bill_length
0 Adelie 38.8 2.7
1 Chinstrap 48.8 3.3
2 Gentoo 47.5 3.1
Media y desviación estándar de la longitud del pico de cada especie por sexo
Code
species_bill_length_sex = (df
.groupby(['species', 'sex'])
.agg(avg_bill_length = ('bill_length_mm', 'mean'),
sd_bill_length = ('bill_length_mm', 'std')).round(1)
.reset_index())
species_bill_length_sex species sex avg_bill_length sd_bill_length
0 Adelie female 37.3 2.0
1 Adelie male 40.4 2.3
2 Chinstrap female 46.6 3.1
3 Chinstrap male 51.1 1.6
4 Gentoo female 45.6 2.1
5 Gentoo male 49.5 2.7
Agrupación - cálculo
Añadir una nueva columna al fichero de datos que muestre la longitud media de las aletas agrupadas por especies
Code
df['mean_flipper_length'] = df.groupby('species')['flipper_length_mm'].transform('mean')
df.head() species island bill_length_mm ... sex year mean_flipper_length
0 Adelie Torgersen 39.1 ... male 2007 189.953642
1 Adelie Torgersen 39.5 ... female 2007 189.953642
2 Adelie Torgersen 40.3 ... female 2007 189.953642
3 Adelie Torgersen NaN ... NaN 2007 189.953642
4 Adelie Torgersen 36.7 ... female 2007 189.953642
[5 rows x 9 columns]
Puntuación estandarizada (z-score) por especie para la longitud de las aletas
Code
df['flipper_z'] = df.groupby('species')['flipper_length_mm'].transform(lambda x: (x - x.mean()) / x.std()).round(2)
df.head() species island bill_length_mm ... year mean_flipper_length flipper_z
0 Adelie Torgersen 39.1 ... 2007 189.953642 -1.37
1 Adelie Torgersen 39.5 ... 2007 189.953642 -0.60
2 Adelie Torgersen 40.3 ... 2007 189.953642 0.77
3 Adelie Torgersen NaN ... 2007 189.953642 NaN
4 Adelie Torgersen 36.7 ... 2007 189.953642 0.47
[5 rows x 10 columns]
Añadir una columna para la media y la desviación estándar por especie para la longitud del pico
Code
df = df.assign(
mean_val = df.groupby(["species"]).bill_length_mm.transform('mean'),
sd_val = df.groupby(["species"]).bill_length_mm.transform('std'))
df.head() species island bill_length_mm ... flipper_z mean_val sd_val
0 Adelie Torgersen 39.1 ... -1.37 38.791391 2.663405
1 Adelie Torgersen 39.5 ... -0.60 38.791391 2.663405
2 Adelie Torgersen 40.3 ... 0.77 38.791391 2.663405
3 Adelie Torgersen NaN ... NaN 38.791391 2.663405
4 Adelie Torgersen 36.7 ... 0.47 38.791391 2.663405
[5 rows x 12 columns]