---
title: "IA para Científicos Sociales"
subtitle: "Sesión 1.4: Laboratorio - Exploración avanzada y comparación de modelos"
author:
- name: Danilo Freire
orcid: 0000-0002-4712-6810
email: danilofreire@gmail.com
affiliations: "Departament of Data and Decision Sciences
Emory University"
format:
clean-revealjs:
self-contained: true
footer: "[Sesión 1.4](https://danilofreire.github.io/introduccion-ia-ucu/clases/dia-01/04-laboratorio-02.html)"
transition: slide
transition-speed: default
scrollable: true
revealjs-plugins:
- multimodal
engine: knitr
editor:
render-on-save: true
lang: es
---
```{r setup, include=FALSE}
options(htmltools.dir.version = FALSE)
library(knitr)
opts_chunk$set(
prompt = T,
fig.align = "center",
dpi = 300,
cache = T,
engine.opts = list(bash = "-l")
)
knit_hooks$set(
prompt = function(before, options, envir) {
options(
prompt = if (options$engine %in% c("sh", "bash", "zsh")) "$ " else "R> ",
continue = if (options$engine %in% c("sh", "bash", "zsh")) "$ " else "+ "
)
}
)
options(repos = c(CRAN = "https://cran.rstudio.com/"))
if (!require("fontawesome", character.only = TRUE)) {
install.packages("fontawesome", dependencies = TRUE)
library(fontawesome, character.only = TRUE)
}
```
# Laboratorio 2: Exploración avanzada {background-color="#2d4563"}
## Objetivos del laboratorio
:::{style="margin-top: 30px; font-size: 28px;"}
:::{.columns}
:::{.column width=50%}
**Lo que vamos a hacer:**
1. Trabajar con un nuevo dataset
2. Análisis exploratorio detallado
3. Feature engineering básico
4. Comparar múltiples modelos
5. Visualizar resultados
6. Discutir interpretaciones
:::
:::{.column width=50%}
**Lo que vamos a practicar:**
- Decisiones de [preprocesamiento]{.alert}
- [Comparación]{.alert} sistemática de modelos
- [Visualización]{.alert} de resultados
- [Interpretación]{.alert} de modelos
:::{style="margin-top: 30px; font-size: 28px;"}
[Hay menos código predefinido. Ustedes van a escribir más!]{.alert}
[¡No se preocupen! Les damos una estructura para que puedan completar.]{.alert} 😉
:::
:::
:::
:::
# Parte 1: Nuevo dataset {background-color="#2d4563"}
## Cargar los paquetes
:::{style="margin-top: 30px; font-size: 22px;"}
```{r lab2-setup, message=FALSE, warning=FALSE, prompt=FALSE, echo=TRUE}
# Cargar paquetes
# install.packages("tidymodels", "tidyverse") # Instalar si es necesario
library(tidymodels)
library(tidyverse)
# Configurar tema de ggplot
theme_set(theme_minimal(base_size = 14))
```
O de una forma más automatizada:
```{r lab2-install, eval=FALSE, prompt=FALSE, echo=TRUE}
paquetes <- c("tidymodels", "tidyverse", "rpart")
# require(): intenta cargar el paquete y devuelve TRUE/FALSE
# Si no está instalado (FALSE), lo instala y carga
for (pkg in paquetes) {
if (!require(pkg, character.only = TRUE)) {
install.packages(pkg, dependencies = TRUE)
library(pkg, character.only = TRUE)
}
}
```
:::
## El dataset: satisfacción democrática
:::{style="margin-top: 30px; font-size: 22px;"}
Vamos a trabajar con datos simulados de [satisfacción con la democracia]{.alert} en América Latina:
```{r lab2-datos, message=FALSE, warning=FALSE, prompt=FALSE, echo=TRUE}
# Cargar datos
satisfaccion <- read_csv("datos/satisfaccion_democracia.csv")
# Ver estructura
glimpse(satisfaccion) # Ver las variables y tipos
```
**Variable objetivo:** `satisfecho` (sí/no) - ¿El encuestado está satisfecho con la democracia?
:::
## Descripción de las variables
:::{style="margin-top: 30px; font-size: 30px;"}
| Variable | Descripción | Tipo |
|----------|-------------|------|
| `satisfecho` | Satisfacción con la democracia (sí/no) | Categórica |
| `edad` | Edad del encuestado | Numérica |
| `educacion_anos` | Años de educación formal | Numérica |
| `ingreso_hogar` | Ingreso mensual del hogar (USD) | Numérica |
| `confianza_gobierno` | Confianza en el gobierno (1-10) | Numérica |
| `consumo_noticias` | Horas semanales de noticias | Numérica |
| `participacion_politica` | Índice de participación (0-100) | Numérica |
| `zona` | Urbano/Rural | Categórica |
| `genero` | Masculino/Femenino/Otro | Categórica |
| `pais` | País de residencia | Categórica |
:::
## Visualizar distribuciones
:::{style="margin-top: 30px; font-size: 22px;"}
```{r lab2-boxplots, prompt=FALSE, fig.width=10, fig.height=4.5, echo=TRUE}
# Variables numéricas por nivel de satisfacción
satisfaccion |>
select(satisfecho, confianza_gobierno, participacion_politica, edad) |>
pivot_longer(-satisfecho, names_to = "variable", values_to = "valor") |>
ggplot(aes(x = satisfecho, y = valor, fill = satisfecho)) +
geom_boxplot(alpha = 0.7) +
facet_wrap(~variable, scales = "free_y") +
scale_fill_manual(values = c("#e74c3c", "#27ae60")) +
labs(title = "Variables numéricas por nivel de satisfacción") +
theme(legend.position = "none")
```
Quienes tengan tiempo pueden ver también `geom_histogram()` por variable. Ejemplo completo en [Apéndice 1]{.alert}.
:::
## Ejercicio 1: Exploración {#sec:exercise01}
:::{style="margin-top: 30px; font-size: 24px;"}
**Tarea:** Exploren el dataset y produzcan una visualización que les llame la atención.
1. ¿Cuántas observaciones? ¿Hay valores faltantes?
2. ¿Cómo se distribuye la variable objetivo `satisfecho`?
3. Elijan [una]{.alert} de estas preguntas y hagan un gráfico para responderla:
- ¿Cómo varía la satisfacción por [zona]{.alert} (urbano/rural) o por [país]{.alert}?
- ¿Qué relación hay entre [ingreso]{.alert} y [educación]{.alert}?
```{r ej1-exploracion, eval=FALSE, prompt=FALSE, echo=TRUE}
# Código para empezar
dim(satisfaccion)
satisfaccion |> count(satisfecho) |> mutate(prop = n / sum(n))
# Ejemplo: satisfacción por zona
satisfaccion |>
count(zona, satisfecho) |>
group_by(zona) |> mutate(prop = n / sum(n)) |>
ggplot(aes(x = zona, y = prop, fill = satisfecho)) +
geom_col(position = "dodge")
```
[Tómense 5-10 minutos.]{.alert}
[[Ir al Apéndice 1]{.button}](#sec:appendix01) · [[Más visualizaciones: Apéndice 2]{.button}](#sec:appendix02)
:::
# Parte 2: Feature engineering {background-color="#2d4563"}
## Preparar los datos
:::{style="margin-top: 30px; font-size: 22px;"}
Primero, preparemos los datos básicos:
```{r lab2-preparar, prompt=FALSE, echo=TRUE}
# Convertir variables categóricas a factores
satisfaccion <- satisfaccion |>
mutate(
satisfecho = factor(satisfecho, levels = c("no", "si")),
zona = factor(zona),
genero = factor(genero),
pais = factor(pais)
)
# Verificar
glimpse(satisfaccion)
```
:::
## Crear nuevas variables
:::{style="margin-top: 30px; font-size: 22px;"}
El [feature engineering]{.alert} puede mejorar el rendimiento del modelo:
```{r lab2-features, prompt=FALSE, echo=TRUE}
# Crear nuevas variables
satisfaccion <- satisfaccion |>
mutate(
# Grupos de edad
grupo_edad = cut(edad,
breaks = c(0, 30, 50, 70, 100),
labels = c("joven", "adulto", "mayor", "anciano")),
# Ingreso per cápita (asumiendo hogar promedio de 3.5 personas)
ingreso_percapita = ingreso_hogar / 3.5,
# Indicador de alta participación
alta_participacion = if_else(participacion_politica > 50, "alta", "baja")
)
# Ver las nuevas variables
satisfaccion |> select(grupo_edad, ingreso_percapita, alta_participacion) |> head()
```
:::
## Ejercicio 2: Crear un feature {#sec:exercise03}
:::{style="margin-top: 30px; font-size: 24px;"}
**Tarea:** Elijan [una]{.alert} variable derivada y créenla.
Opciones sugeridas (elijan la que más les interese). Entre paréntesis, la variable base:
- Grupos de ingreso por terciles: bajo, medio, alto (`ingreso_hogar`)
- Consumidor alto de noticias: más de 5 horas por semana (`consumo_noticias`)
- Baja confianza en el gobierno: puntaje menor o igual a 4 (`confianza_gobierno`)
- Interacción zona y género: combinación de ambas categorías (`zona`, `genero`)
```{r ej3-features, eval=FALSE, prompt=FALSE, echo=TRUE}
# Ejemplo: Crear variable educacion_alta
satisfaccion <- satisfaccion |>
mutate(
educacion_alta = if_else(educacion_anos > 12, "alta", "baja")
)
```
[Tómense 5 minutos.]{.alert}
[[Más ejemplos en el Apéndice 3]{.button}](#sec:appendix03)
:::
## Dividir los datos
:::{style="margin-top: 30px; font-size: 24px;"}
```{r lab2-split, prompt=FALSE, echo=TRUE}
# Fijar semilla
set.seed(2026)
# Dividir datos
datos_split <- initial_split(satisfaccion, prop = 0.75, strata = satisfecho)
datos_train <- training(datos_split)
datos_test <- testing(datos_split)
# Crear folds para validación cruzada
folds <- vfold_cv(datos_train, v = 5, strata = satisfecho)
cat("Train:", nrow(datos_train), "| Test:", nrow(datos_test))
```
- `initial_split()`: Divide el dataset en train/test
- `training()` y `testing()`: Extraen los datasets de train y test
- `vfold_cv()`: Crea folds para validación cruzada (5 folds, estratificados por `satisfecho`)
:::
# Parte 3: Comparación de modelos {background-color="#2d4563"}
## Definir los modelos a comparar
:::{style="margin-top: 30px; font-size: 22px;"}
Vamos a comparar dos modelos de naturaleza distinta: uno lineal y uno no lineal.
```{r lab2-modelos, prompt=FALSE, echo=TRUE}
# 1. Regresión logística (lineal)
modelo_logistico <- logistic_reg() |>
set_engine("glm") |>
set_mode("classification")
# 2. Árbol de decisión (no lineal, captura interacciones automáticamente)
modelo_arbol <- decision_tree() |>
set_engine("rpart") |>
set_mode("classification")
```
La [misma sintaxis]{.alert} sirve para ambos: esa es la ventaja de `parsnip`. Otros motores (`kknn`, `ranger`, `xgboost`) funcionan igual cambiando solo `set_engine()`.
:::
## Crear una fórmula
:::{style="margin-top: 30px; font-size: 24px;"}
Decidamos qué variables usar:
```{r lab2-formula, prompt=FALSE, echo=TRUE}
# Fórmula con variables originales
formula_basica <- satisfecho ~ edad + educacion_anos + ingreso_hogar +
confianza_gobierno + consumo_noticias +
participacion_politica + zona
```
Más adelante añadiremos una variable derivada para ver si mejora el ajuste.
:::
## Función para evaluar un modelo
:::{style="margin-top: 30px; font-size: 20px;"}
Creemos una función que facilite la evaluación:
```{r lab2-funcion-evaluar, prompt=FALSE, echo=TRUE}
evaluar_modelo <- function(modelo, formula, folds, nombre = "modelo") {
# Validación cruzada
# event_level = "second" porque "si" es el segundo nivel del factor
resultados <- fit_resamples(
modelo,
formula,
resamples = folds,
metrics = metric_set(accuracy, precision, recall, roc_auc),
control = control_resamples(event_level = "second")
)
# Extraer métricas
collect_metrics(resultados) |>
mutate(modelo = nombre)
}
```
```{r lab2-evaluar-logistico, prompt=FALSE, echo=TRUE}
# Evaluar regresión logística
eval_logistico <- evaluar_modelo(modelo_logistico, formula_basica, folds, "Logístico")
eval_logistico
```
:::
## Evaluar todos los modelos
:::{style="margin-top: 30px; font-size: 22px;"}
```{r lab2-evaluar-todos, prompt=FALSE, echo=TRUE}
# Evaluar el árbol con la misma fórmula
eval_arbol <- evaluar_modelo(modelo_arbol, formula_basica, folds, "Árbol")
# Combinar resultados
resultados <- bind_rows(eval_logistico, eval_arbol)
# Mostrar comparación
resultados |>
select(modelo, .metric, mean, std_err) |>
pivot_wider(names_from = .metric, values_from = c(mean, std_err))
```
:::
## Visualizar la comparación
:::{style="margin-top: 30px; font-size: 22px;"}
```{r lab2-visualizar-comparacion, prompt=FALSE, fig.width=10, fig.height=5, echo=TRUE}
resultados |>
ggplot(aes(x = modelo, y = mean, fill = modelo)) +
geom_col(alpha = 0.8) +
geom_errorbar(aes(ymin = mean - std_err, ymax = mean + std_err),
width = 0.2) +
facet_wrap(~.metric, scales = "free_y") +
scale_fill_manual(values = c("#2d4563", "#27ae60")) +
labs(title = "Comparación de modelos", y = "Valor", x = "") +
theme(legend.position = "none")
```
:::
## Ejercicio 3: ¿Ayuda el feature engineering? {#sec:exercise04}
:::{style="margin-top: 30px; font-size: 24px;"}
**Tarea:** Agreguen [la variable derivada que crearon antes]{.alert} a la fórmula y re-evalúen.
1. ¿Mejora la regresión logística? ¿Y el árbol?
2. ¿Cuál de los dos modelos es más sensible al feature nuevo?
```{r ej4-features-nuevos, eval=FALSE, prompt=FALSE, echo=TRUE}
# Ejemplo con la variable educacion_alta
formula_ext <- satisfecho ~ edad + educacion_anos + ingreso_hogar +
confianza_gobierno + consumo_noticias +
participacion_politica + zona + educacion_alta
eval_log_ext <- evaluar_modelo(modelo_logistico, formula_ext, folds, "Logístico (ext)")
eval_arb_ext <- evaluar_modelo(modelo_arbol, formula_ext, folds, "Árbol (ext)")
bind_rows(eval_logistico, eval_log_ext, eval_arbol, eval_arb_ext) |>
filter(.metric == "accuracy") |> select(modelo, mean, std_err)
```
[Tómense 10 minutos.]{.alert}
[[Ir al Apéndice 4]{.button}](#sec:appendix04)
:::
## Modelo final en datos de test
:::{style="margin-top: 30px; font-size: 22px;"}
Una vez elegido el mejor modelo, evaluamos en test:
```{r lab2-test-final, prompt=FALSE, echo=TRUE}
# Elegimos el modelo logístico (por ejemplo)
ajuste_final <- modelo_logistico |>
fit(formula_basica, data = datos_train)
# Predicciones en test
pred_test <- ajuste_final |>
predict(datos_test, type = "prob") |>
bind_cols(predict(ajuste_final, datos_test)) |>
bind_cols(datos_test)
# Métricas finales
pred_test |>
metrics(truth = satisfecho, estimate = .pred_class)
# AUC-ROC
pred_test |>
roc_auc(truth = satisfecho, .pred_si, event_level = "second")
```
:::
## Tarea para casa
:::{style="margin-top: 30px; font-size: 24px;"}
Hay una [tarea para esta sesión]{.alert} con preguntas prácticas que aplican todo lo que vimos hoy.
- Página de [Laboratorios](https://danilofreire.github.io/introduccion-ia-ucu/laboratorios.html) del sitio del curso
- [Tarea 2](https://danilofreire.github.io/introduccion-ia-ucu/clases/dia-01/tarea-02.html)
- [Respuestas Tarea 2](https://danilofreire.github.io/introduccion-ia-ucu/clases/dia-01/tarea-02-respuestas.html)
[Hagan la tarea antes de la próxima clase. Las respuestas ya están disponibles para que verifiquen su trabajo.]{.alert}
:::
# Cierre del Día 1 {background-color="#2d4563"}
## Lo que cubrimos hoy
:::{style="margin-top: 30px; font-size: 24px;"}
:::{.columns}
:::{.column width=50%}
**Sesión 1.1: ¿Qué es la IA?**
- Definición y tipos de IA
- Historia: de Turing a GPT
- Tipos de aprendizaje automático
- Ética básica
**Sesión 1.2: Fundamentos de ML**
- Flujo de trabajo de ML
- División y validación
- Sobreajuste y regularización
- Métricas de evaluación
:::
:::{.column width=50%}
**Sesión 1.3: Laboratorio 1**
- Ecosistema tidymodels
- Primer modelo de clasificación
- Matriz de confusión y métricas
**Sesión 1.4: Laboratorio 2**
- Exploración guiada
- Feature engineering básico
- Comparación logístico vs. árbol
- Tarea 2 disponible en la página de laboratorios
:::
:::
:::
## Para mañana
:::{style="margin-top: 40px; font-size: 28px;"}
**Día 2: Aprendizaje supervisado**
- Sesión 2.1: Métodos de clasificación
- Regresión logística en detalle
- Árboles de decisión
- Random Forests
- Sesión 2.2: Regresión y predicción
- Regularización: LASSO, Ridge, Elastic Net
- Ingeniería de variables para datos sociales
- Sesiones 2.3 y 2.4: Laboratorios con datos de Latinobarómetro
[Descansen y vengan con energía mañana!]{.alert} 😄
:::
## Recursos adicionales
:::{style="margin-top: 30px; font-size: 24px;"}
:::{.columns}
:::{.column width=50%}
**Documentación oficial:**
- [tidymodels.org](https://www.tidymodels.org/)
- [Tidy Modeling with R](https://www.tmwr.org/) (libro gratuito)
- [parsnip models](https://parsnip.tidymodels.org/reference/index.html)
:::
:::{.column width=50%}
**Tutoriales recomendados:**
- [Get Started with tidymodels](https://www.tidymodels.org/start/)
- [Julia Silge's blog](https://juliasilge.com/)
- [R for Data Science](https://r4ds.hadley.nz/)
:::
:::
[Todos estos recursos están disponibles gratuitamente en línea.]{.alert}
:::
# Fin del Día 1 🥳 {background-color="#2d4563"}
# Apéndices {background-color="#2d4563"}
## Apéndice 1: Exploración inicial {#sec:appendix01}
:::{style="margin-top: 30px; font-size: 20px;"}
```{r appendix01, prompt=FALSE, echo=TRUE}
# 1. Dimensiones
dim(satisfaccion)
# 2. Distribución de la variable objetivo
satisfaccion |>
count(satisfecho) |>
mutate(prop = round(n / sum(n), 3))
# 3. Valores faltantes por variable
colSums(is.na(satisfaccion))
# 4. Resumen de variables numéricas
satisfaccion |>
select(where(is.numeric)) |>
summary()
# 5. Distribución por país y zona
satisfaccion |> count(pais, sort = TRUE)
satisfaccion |> count(zona)
```
[[Volver al Ejercicio 1]{.button}](#sec:exercise01)
:::
## Apéndice 2: Más visualizaciones {#sec:appendix02}
:::{style="margin-top: 30px; font-size: 20px;"}
```{r appendix02a, prompt=FALSE, fig.width=10, fig.height=4, echo=TRUE}
# 1. Satisfacción por zona
satisfaccion |>
count(zona, satisfecho) |>
group_by(zona) |>
mutate(prop = n / sum(n)) |>
ggplot(aes(x = zona, y = prop, fill = satisfecho)) +
geom_col(position = "dodge", alpha = 0.8) +
scale_fill_manual(values = c("#e74c3c", "#27ae60")) +
labs(title = "Satisfacción por zona", y = "Proporción")
```
:::
## Apéndice 2 (cont.)
:::{style="margin-top: 30px; font-size: 20px;"}
```{r appendix02b, prompt=FALSE, fig.width=10, fig.height=4, echo=TRUE}
# 2. Satisfacción por país
satisfaccion |>
count(pais, satisfecho) |>
group_by(pais) |>
mutate(prop = n / sum(n)) |>
filter(satisfecho == "si") |>
ggplot(aes(x = reorder(pais, prop), y = prop)) +
geom_col(fill = "#27ae60", alpha = 0.8) +
coord_flip() +
labs(title = "Proporción de satisfechos por país", x = "", y = "Proporción")
```
:::
## Apéndice 2 (cont.)
:::{style="margin-top: 30px; font-size: 20px;"}
```{r appendix02c, prompt=FALSE, fig.width=10, fig.height=4, echo=TRUE}
# 3. Satisfacción por género
satisfaccion |>
count(genero, satisfecho) |>
group_by(genero) |>
mutate(prop = n / sum(n)) |>
ggplot(aes(x = genero, y = prop, fill = satisfecho)) +
geom_col(position = "dodge", alpha = 0.8) +
scale_fill_manual(values = c("#e74c3c", "#27ae60")) +
labs(title = "Satisfacción por género", y = "Proporción")
```
```{r appendix02d, prompt=FALSE, fig.width=10, fig.height=4, echo=TRUE}
# 4. Ingreso vs. educación
ggplot(satisfaccion, aes(x = educacion_anos, y = ingreso_hogar, color = satisfecho)) +
geom_point(alpha = 0.4) +
geom_smooth(method = "lm", se = FALSE) +
scale_color_manual(values = c("#e74c3c", "#27ae60")) +
labs(title = "Ingreso vs. educación por satisfacción")
```
[[Volver al Ejercicio 1]{.button}](#sec:exercise01)
:::
## Apéndice 3: Crear más features {#sec:appendix03}
:::{style="margin-top: 30px; font-size: 20px;"}
```{r appendix03, prompt=FALSE, echo=TRUE}
# Una posible solución para cada una de las cuatro opciones sugeridas
satisfaccion <- satisfaccion |>
mutate(
# 1. Grupos de ingreso por terciles (ingreso_hogar)
grupo_ingreso = cut(ingreso_hogar,
breaks = quantile(ingreso_hogar, c(0, 1/3, 2/3, 1)),
labels = c("bajo", "medio", "alto"),
include.lowest = TRUE),
# 2. Consumidor alto de noticias (consumo_noticias)
noticias_alto = if_else(consumo_noticias > 5, "alto", "bajo"),
# 3. Baja confianza en el gobierno (confianza_gobierno)
confianza_baja = if_else(confianza_gobierno <= 4, "si", "no"),
# 4. Interacción zona + género
zona_genero = paste(zona, genero, sep = "_")
)
# Verificar las nuevas variables
satisfaccion |> count(grupo_ingreso)
satisfaccion |> count(noticias_alto)
satisfaccion |> count(confianza_baja)
satisfaccion |> count(zona_genero)
```
[[Volver al Ejercicio 3]{.button}](#sec:exercise03)
:::
## Apéndice 4: ¿Ayuda el feature engineering? {#sec:appendix04}
:::{style="margin-top: 30px; font-size: 20px;"}
```{r appendix04, prompt=FALSE, echo=TRUE}
# Crear el feature derivado (si no lo hicieron antes)
satisfaccion <- satisfaccion |>
mutate(educacion_alta = if_else(educacion_anos > 12, "alta", "baja"),
educacion_alta = factor(educacion_alta))
# Re-crear folds con la columna nueva disponible
set.seed(2026)
split_ext <- initial_split(satisfaccion, prop = 0.75, strata = satisfecho)
train_ext <- training(split_ext)
folds_ext <- vfold_cv(train_ext, v = 5, strata = satisfecho)
# Fórmula con el feature nuevo
formula_ext <- satisfecho ~ edad + educacion_anos + ingreso_hogar +
confianza_gobierno + consumo_noticias +
participacion_politica + zona + educacion_alta
# Evaluar los dos modelos con y sin feature nuevo
eval_log_ext <- evaluar_modelo(modelo_logistico, formula_ext, folds_ext, "Logístico (ext)")
eval_arb_ext <- evaluar_modelo(modelo_arbol, formula_ext, folds_ext, "Árbol (ext)")
bind_rows(eval_logistico, eval_log_ext, eval_arbol, eval_arb_ext) |>
filter(.metric == "accuracy") |>
select(modelo, mean, std_err) |>
arrange(desc(mean))
```
La mejora por agregar una sola variable derivada suele ser modesta. El feature engineering rinde cuando las variables nuevas capturan relaciones no lineales o interacciones que el modelo no puede descubrir por sí solo (en un árbol esto pesa menos, porque ya captura no linealidades automáticamente).
[[Volver al Ejercicio 3]{.button}](#sec:exercise04)
:::