---
title: "Librería-reticulate"
author: "Julián Ramajo"
editor: visual
engine: knitr
excerpt: ""
draft: false
format: 
  html:
    self-contained: true
    max-width: 1920px
    code-fold: show
    code-tools: true
---


```{css, echo = FALSE}
.justify { text-align: justify !important }
```

::: justify
# Programación conjunta en R y Python con `reticulate` {.unnumbered}

## Justificación {.unnumbered}

En este apartado se demuestra cómo los ficheros **Quarto** (con extensión *qmd*) o **R Markdown** (con extensión *Rmd*) son un buen entorno para codificar un proyecto simultáneamente en los dos lenguajes de programación más usados en *Data Science*, R y Python, permitiendo programar algunos elementos del proyecto en cada lenguaje y manipular objetos creados en un lenguaje usando el otro, y viceversa.

Esto puede ser útil por varias razones:

1.  Permite codificar en la *"lengua nativa de la estadística"* (**R**) pero añadiendo características que podrían existir sólo en la *"segunda lengua"* (**Python**); o al contrario. Obviamente, cuando se usa la palabra *lengua* se hace referencia al término *lenguaje de programación*.
2.  Permite colaborar directamente con otro colega que sea un experto programador en el otro lenguaje (equipos multi-lenguaje).
3.  Da la oportunidad de trabajar en ambos lenguajes de programación y de adquirir fluidez en ellos, intentando alcanzar a largo plazo el *bilingüismo*.

## ¿Qué se necesita? {.unnumbered}

Para que la interacción R-Python funcione correctamente se necesita lo siguiente:

1.  R y Python instalados en el ordenador.
2.  El entorno de ejecución (IDE) RStudio también instalado.
3.  La librería `reticulate` instalada en R. Se pueden encontrar todos los detalles de la librería en la página web siguiente: <https://rstudio.github.io/reticulate/>

Trabajaremos en el IDE de RStudio, escribiendo en un fichero tipo Quarto o R Markdown, moviéndonos entre trozos de código que están escritos en R o en Python.

A continuación se hará una demostración con tres ejemplos sencillos.

## Primer ejemplo {.unnumbered}

A través de este caso se verá fácilmente cómo interactúan R y Python a través de la librería `reticulate`. Para configurar RStudio y permitir la interacción R-Python simplemente hay que leer la librería para activar ambos lenguajes:

```{r setup}
library(reticulate)
```

Cuando se quiera escribir código en Python, se deben envolver las líneas con los habituales signos de puntuación (\`\`\`), pero etiquetarlo como un trozo de código python usando {python}; y cuando se quiera escribir en R debe usarse {r}.

1.  **Desde Python hacia R**

En primer lugar se usa Python para leer y manipular los datos:

```{python}
import pandas
flights = pandas.read_csv("data/flights.csv")
flights = flights[flights['dest'] == "ORD"]
flights = flights[['carrier', 'dep_delay', 'arr_delay']]
flights = flights.dropna()
flights
flights.describe()
```

Ahora se usa R para visualizar los datos guardados en Python (en formato Pandas DataFrame):

```{r, fig.width=7, fig.height=3}
library(ggplot2)
ggplot(py$flights, aes(carrier, arr_delay)) + geom_point() + geom_jitter()
```

2.  **Desde R hacia Python**

Primero se usa R para leer y manipular los datos:

```{r, message=FALSE}
library(tidyverse)
flights <- read_csv("data/flights.csv") %>%
  filter(dest == "ORD") %>%
  select(carrier, dep_delay, arr_delay) %>%
  na.omit()
head(flights)
tail(flights)
summary(flights)
```

Y luego se usa Python para visualizar los datos guardados en R (en formato R DataFrame):

```{python print}
from plotnine import *
(ggplot(r.flights, aes(x="carrier", y="arr_delay"))+geom_point()+geom_jitter())
```

## Segundo ejemplo {.unnumbered}

En este ejemplo se va a estimar en Python una regresión con un conjunto de datos sobre las calificaciones finales de Grado de los estudiantes en función de sus resultados en los diferentes años académicos.

1.  Código Python para estimar el modelo:

```{python}
import pandas as pd
import statsmodels.formula.api as smf
# Datos
ugtests = pd.read_csv("data/ugtests.csv")
# Modelo
model = smf.ols(formula = "Final ~ Yr3 + Yr2 + Yr1", data = ugtests)
# Estimación del modelo y resultados
fitted_model = model.fit()
model_summary = fitted_model.summary()
print(model_summary)
```

2.  En este momento has tenido que dejar este trabajo debido a algo más urgente y se lo has pasado a otro colega que sólo programa en R para que él haga algunos diagnósticos del modelo estimado. Pues bien, el nuevo programador puede acceder a todos los objetos Python que se han creado anteriormente dentro de una lista general llamada `py` en el entorno R.

Así, si escribe un cógigo R como el que sigue puede acceder a los parámetros del modelo estimado:

```{r}
py$fitted_model$params
```

o realizar unas estadísticas básicas y un histograma de los *residuos* (errores estimados del modelo):

```{r}
summary(py$fitted_model$resid)
hist(py$fitted_model$resid)
```

Además, puede hacer fácilmente algunos *diagnósticos* más sofisticados usando la librería `car`:

```{r}
library(car)
densityPlot(py$fitted_model$resid)
qqnorm(py$fitted_model$resid)
qqPlot(py$fitted_model$resid)
```

### Tercer ejemplo {.unnumbered}

Supongamos ahora que se han estado analizando algunos datos en Python y se ha creado un *dataframe* de la librería `pandas` con todos ellos. Vamos a cargar los datos del fichero [speed_dating](https://search.r-project.org/CRAN/refmans/peopleanalyticsdata/html/speed_dating.html) y a echarles un vistazo:

```{python}
import pandas as pd
speed_dating = pd.read_csv("data/speed_dating.csv")
print(speed_dating.head())
```

Supongamos que se estima una *regresión logística simple* en Python para intentar relacionar la variable decisión `dec` en función de algunas de las variables de la base de datos:

```{python}
import pandas as pd
import statsmodels.api as sm
import statsmodels.formula.api as smf
# Datos
speed_dating = pd.read_csv("data/speed_dating.csv")
# Modelo
model = smf.glm(formula = "dec ~ agediff + samerace + attr + intel + prob", 
                data = speed_dating, 
                family = sm.families.Binomial())
# Estimación del modelo
promotion_model = model.fit()
# Resultados
print(promotion_model.summary())
```

Sin embargo, alguien se da cuenta de que estos datos son en realidad jerárquicos ya que el mismo `iid` individual puede tener múltiples fechas, así que es necesario estimar un *modelo de regresión logística de efectos mixtos*, ¡pero nadie es capaz de encontrar una librería en Python que lo haga! Sin embargo, para un colega especializado en R es fácil estimar ese tipo de modelos con la librería `lme4`:

```{r}
library(lme4)
speed_dating <- py$speed_dating
iid_intercept_model <- lme4:::glmer(dec ~ 
                                      agediff + samerace + attr + intel + prob + (1 | iid), 
                                    data = speed_dating, family = "binomial")
summary(iid_intercept_model)
coefficients <- coef(iid_intercept_model)$iid
```

Ahora se pueden recuperar los resultados en Python y echar un vistazo a las estimaciones de los coeficientes, por ejemplo. Para acceder a los objetos de R en Python se utiliza el objeto de lista general `r`.

```{python}
coefs = r.coefficients
print(coefs.head())
```
:::
