---
title: "4. Estructura no declarada"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{4. Estructura no declarada}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
library(lupa)
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
# El ancho se restaura al terminar la viñeta: knitr corre cada una en su propia
# sesion, asi que no se filtra, pero el CRAN Cookbook pide devolver toda opcion
# que se cambie y no cuesta nada cumplirlo.
.opciones_previas <- options(width = 90)
```

Una entrega puede llegar sin diccionario, sin claves y sin relaciones declaradas. ¿Qué
estructura cumplen de hecho los datos recibidos, y qué parte de esa estructura todavía
hay que confirmar con quien conoce el sistema?

> **En esta guía:**
>
> - buscamos una clave candidata con `detectar_claves()`;
> - comparamos dos tablas con `detectar_relaciones()` y leemos su cardinalidad;
> - encontramos una dependencia entre columnas con `detectar_dependencias()`;
> - separamos lo que se cumple en estos datos de lo que es una regla del sistema.

## Dos tablas que se pueden seguir fila por fila

Los conjuntos incluidos en `lupa` sirven para examinar columnas, pero no contienen una
clave exacta: en `datos_operativos`, `id_evento` tiene
`r length(unique(datos_operativos$id_evento))` valores distintos en
`r nrow(datos_operativos)` filas. Sobre ellos, `detectar_claves()` y
`detectar_dependencias()` devolverían tablas sin filas.

Para ver una clave, una relación y una dependencia construimos dos tablas chicas: una de
personas y otra de trámites. Cada conclusión se puede contrastar con las filas impresas.

```{r tablas-construidas}
library(lupa)

personas <- data.frame(
  id_persona = 101:108,
  nombre = rep(c("Ana", "Bruno", "Carla", "Diego"), each = 2),
  ciudad = rep(c("Montevideo", "Salto", "Belén", "Melo"), each = 2),
  departamento = rep(
    c("Montevideo", "Salto", "Salto", "Cerro Largo"), each = 2
  ),
  stringsAsFactors = FALSE
)

tramites <- data.frame(
  id_tramite = 1001:1010,
  id_persona = c(101, 101, 102, 103, 104, 104, 105, 106, 107, 108),
  tipo = rep(c("alta", "renovación"), 5),
  stringsAsFactors = FALSE
)

personas
tramites
```

## Una clave candidata

`id_persona` no falta y no se repite en `personas`. Limitamos la búsqueda a columnas
simples (`max_combinacion = 1`) para que la salida responda sólo esa pregunta:

```{r claves}
claves <- detectar_claves(personas, max_combinacion = 1)
claves[, c(
  "columnas", "n_columnas", "n_filas", "casi_clave", "unicidad_exacta"
)]
```

`nombre`, `ciudad` y `departamento` se repiten, así que no aparecen. Que una columna
identifique cada fila en esta entrega la vuelve candidata, no clave: una magnitud que no
repite valores también pasaría. Declarar la clave al perfilar, con
`perfilar(clave = ...)`, es lo que permite ir de un hallazgo a la fila en el sistema de
origen; eso se explica en [2. Leer un perfil](leer-un-perfil.html).

## Una relación entre dos tablas

`id_persona` también está en `tramites`, y ahí se repite: una persona puede tener más de
un trámite. `detectar_relaciones()` recibe las dos columnas de identificación y compara
sus valores:

```{r relaciones}
detectar_relaciones(
  personas["id_persona"], tramites["id_persona"], muestra = Inf
)
```

La cardinalidad es 1:m, uno a muchos. Las dos coberturas valen 1 porque todos los
identificadores de cada lado aparecen en el otro: no hay trámites de personas que no
estén en `personas`, ni personas sin trámites. `muestra = Inf` deja explícito que se
comparan todos los valores.

## Una dependencia dentro de una tabla

En `personas`, cada ciudad observada pertenece a un solo departamento: conocer la ciudad
determina el departamento. Al revés no vale, porque Salto y Belén comparten departamento.
Bajamos el mínimo de observaciones a cuatro porque la tabla tiene ocho filas:

```{r dependencias}
dependencias <- detectar_dependencias(
  personas[c("ciudad", "departamento")],
  muestra = Inf,
  min_observaciones = 4
)
dependencias
```

`perfilar()` busca las mismas dependencias por su cuenta (`analizar_dependencias = TRUE`,
el valor por omisión) y las deja en `perfil$dependencias`. Una dependencia exacta es
además lo que permite imputar un valor faltante desde los propios datos, como se ve en
[6. Limpiar con un plan](limpiar-con-un-plan.html).

## Lo que se cumple no es una regla

Nada de esto modifica los datos ni declara el modelo. La clave es *candidata*, la
cardinalidad describe estas dos tablas y la dependencia se cumple en estas ocho filas.
Una entrega futura puede contradecirlas; la documentación del sistema es la que puede
confirmarlas como reglas.

## Resumen

- `detectar_claves()` encuentra las columnas que identifican cada fila en esta entrega:
  son candidatas, no claves.
- `detectar_relaciones()` compara dos columnas de identificación y publica la
  cardinalidad y la cobertura de cada lado.
- `detectar_dependencias()` encuentra columnas que determinan a otras; `perfilar()` las
  busca por su cuenta.
- Lo que los datos cumplen hoy lo confirma la documentación del sistema, no el paquete.

## Paso siguiente

[5. El vacío por diseño](vacio-por-diseno.html) (`vignette("vacio-por-diseno")`): por
qué una celda vacía puede ser correcta, y cómo se le dice al paquete.

```{r, cierre, include=FALSE}
options(.opciones_previas)
```
