Diagnosticar no autoriza a modificar datos. En lupa, el
producto de la etapa de mejora es primero un plan inspeccionable,
filtrable y editable.
library(lupa)
data(datos_administrativos)
perfil <- perfilar(datos_administrativos)
plan <- planificar_limpieza(perfil, datos_administrativos)
plan[, c(
"id_accion", "grupo", "columna", "estrategia",
"recomendada", "aplicar", "reversible", "estado"
)]
#> id_accion grupo columna estrategia recomendada
#> 1 accion-0001 <NA> cedula revisar_cardinalidad FALSE
#> 2 accion-0002 <NA> cedula convertir_ausencias_textuales TRUE
#> 3 accion-0003 <NA> fecha_nacimiento revisar_cardinalidad FALSE
#> 4 accion-0004 <NA> fecha_nacimiento convertir_ausencias_textuales FALSE
#> 5 accion-0005 <NA> fecha_nacimiento convertir_fecha_confirmada FALSE
#> 6 accion-0006 <NA> sexo convertir_ausencias_textuales TRUE
#> 7 accion-0007 grupo-0010 ingreso convertir_sentinelas_numericos FALSE
#> 8 accion-0008 <NA> departamento revisar_cardinalidad FALSE
#> 9 accion-0009 grupo-0012 pais eliminar_columna_constante FALSE
#> 10 accion-0010 <NA> correo revisar_cardinalidad FALSE
#> 11 accion-0011 grupo-0017 <NA> marcar_filas_duplicadas TRUE
#> 12 accion-0012 grupo-0017 <NA> conservar_primera_duplicada FALSE
#> 13 accion-0013 grupo-0017 <NA> conservar_mas_completa FALSE
#> 14 accion-0014 grupo-0018 id_persona marcar_columnas_duplicadas TRUE
#> 15 accion-0015 grupo-0018 id_persona eliminar_columna_duplicada FALSE
#> aplicar reversible estado
#> 1 FALSE NA informativa
#> 2 TRUE FALSE lista
#> 3 FALSE NA informativa
#> 4 FALSE FALSE lista
#> 5 FALSE FALSE bloqueada
#> 6 TRUE FALSE lista
#> 7 FALSE FALSE lista
#> 8 FALSE NA informativa
#> 9 FALSE FALSE lista
#> 10 FALSE NA informativa
#> 11 TRUE TRUE lista
#> 12 FALSE FALSE lista
#> 13 FALSE FALSE bloqueada
#> 14 TRUE TRUE lista
#> 15 FALSE FALSE listaRecomendaciones y decisiones de dominio
Una acción se recomienda sólo si es correcta con independencia del
dominio: por ejemplo, convertir un sentinela textual inequívoco a
NA o quitar espacios de borde. Normalizar mayúsculas,
convertir un sentinela numérico o winsorizar un valor extremo exige
contexto y queda desactivado.
La justificación acompaña cada alternativa.
plan[, c("estrategia", "justificacion")]
#> estrategia
#> 1 revisar_cardinalidad
#> 2 convertir_ausencias_textuales
#> 3 revisar_cardinalidad
#> 4 convertir_ausencias_textuales
#> 5 convertir_fecha_confirmada
#> 6 convertir_ausencias_textuales
#> 7 convertir_sentinelas_numericos
#> 8 revisar_cardinalidad
#> 9 eliminar_columna_constante
#> 10 revisar_cardinalidad
#> 11 marcar_filas_duplicadas
#> 12 conservar_primera_duplicada
#> 13 conservar_mas_completa
#> 14 marcar_columnas_duplicadas
#> 15 eliminar_columna_duplicada
#> justificacion
#> 1 El perfil señala el problema, pero no contiene conocimiento suficiente del dominio para elegir una transformación.
#> 2 Las representaciones textuales del catálogo son marcadores habituales de ausencia. El cambio no es reversible: confirmar que ninguno de esos textos sea un valor legítimo de la columna -`NA` es el código de Namibia, `NULL` puede ser un apellido-.
#> 3 El perfil señala el problema, pero no contiene conocimiento suficiente del dominio para elegir una transformación.
#> 4 Uno de los textos detectados (null) podría ser un valor legítimo de la columna: `NA` es el código de Namibia, `NULL` puede ser un apellido. El cambio no es reversible y el paquete no puede decidirlo, así que la acción queda para activar a mano.
#> 5 La conversión no es ejecutable sobre los datos completos: Hay valores presentes que no responden a los formatos confirmados. Se conserva como acción destructiva no recomendada.
#> 6 Las representaciones textuales del catálogo son marcadores habituales de ausencia. El cambio no es reversible: confirmar que ninguno de esos textos sea un valor legítimo de la columna -`NA` es el código de Namibia, `NULL` puede ser un apellido-.
#> 7 Un sentinela numérico también puede ser un valor legítimo; requiere confirmar el diccionario del campo.
#> 8 El perfil señala el problema, pero no contiene conocimiento suficiente del dominio para elegir una transformación.
#> 9 Eliminarla pierde contexto potencial; dejarla es la recomendación hasta confirmar que no aporta significado administrativo.
#> 10 El perfil señala el problema, pero no contiene conocimiento suficiente del dominio para elegir una transformación.
#> 11 Marcar conserva todas las filas, identifica las repeticiones y asigna un grupo a todos los registros que participan. No elimina filas; mientras las marcas esten incluidas, un perfil posterior no vuelve a contar esas filas como duplicadas exactas.
#> 12 Conserva la primera aparición exacta y elimina las siguientes; el orden de entrada pasa a determinar qué registro sobrevive.
#> 13 Requiere configurar una clave: entre duplicados exactos todas las filas tienen la misma completitud y esta opción sería equivalente a la primera.
#> 14 La anotación conserva ambas columnas y registra explícitamente la redundancia.
#> 15 Eliminar una columna puede romper consumidores que dependan de su nombre aunque el contenido sea redundante.normalizacion() permite declarar qué diferencias se
ignoran al comparar. El perfil cambia sólo la representación de
comparación; nunca modifica los datos. Los pasos de ligaduras y ancho
completo se aplican por punto de código y los bytes UTF-8 válidos se
declaran antes de operar, así que cumplen igual bajo un locale UTF-8 y
bajo LC_CTYPE = "C".
normalizacion(acentos = FALSE, puntuacion = TRUE)
#> Perfil de normalizacion de lupa
#> minusculas = TRUE
#> espacios = TRUE
#> acentos = FALSE
#> comillas = TRUE
#> puntuacion = TRUE
#> ligaduras = FALSE
#> ancho = FALSE
#> proteger = ñ, ü, g̃Grupos mutuamente excluyentes
Las alternativas de un mismo hallazgo comparten grupo.
Como máximo una puede tener aplicar = TRUE.
decision_grupo distingue un grupo pendiente de una decisión
explícita de no actuar; no se inventa una fila ficticia de “no hacer
nada”.
grupos <- plan[!is.na(plan$grupo), c(
"grupo", "estrategia", "recomendada", "aplicar", "decision_grupo"
)]
grupos
#> grupo estrategia recomendada aplicar decision_grupo
#> 7 grupo-0010 convertir_sentinelas_numericos FALSE FALSE pendiente
#> 9 grupo-0012 eliminar_columna_constante FALSE FALSE recomendada
#> 11 grupo-0017 marcar_filas_duplicadas TRUE TRUE recomendada
#> 12 grupo-0017 conservar_primera_duplicada FALSE FALSE recomendada
#> 13 grupo-0017 conservar_mas_completa FALSE FALSE recomendada
#> 14 grupo-0018 marcar_columnas_duplicadas TRUE TRUE recomendada
#> 15 grupo-0018 eliminar_columna_duplicada FALSE FALSE recomendadaEl modo guiado es una capa opcional. Fuera de una sesión interactiva devuelve el plan sin bloquear; en una consola recorre sólo decisiones pendientes o riesgosas.
identical(guiar_limpieza(plan, datos_administrativos), plan)
#> [1] TRUEAplicar conserva evidencia
copia <- datos_administrativos
resultado <- aplicar(plan, datos_administrativos)
identical(datos_administrativos, copia)
#> [1] TRUE
resultado$registro[, c(
"estrategia", "n_cambiadas", "n_filas_eliminadas", "n_columnas_eliminadas"
)]
#> estrategia n_cambiadas n_filas_eliminadas n_columnas_eliminadas
#> 1 marcar_filas_duplicadas 2 0 0
#> 2 convertir_ausencias_textuales 1 0 0
#> 3 convertir_ausencias_textuales 2 0 0
#> 4 marcar_columnas_duplicadas 1 0 0El plan se puede editar antes de aplicar: quitar una acción, corregir
un parámetro o cambiar n_afectadas no altera la obligación
de observar qué pasó. Si una acción seleccionada no cambia ningún valor,
el registro dice fallida con su motivo, incluso cuando el
estimado está ausente (NA).
Las acciones destructivas nunca son recomendadas. Aunque el usuario
las active en el plan, aplicar() exige además
permitir_eliminacion = TRUE; lo retirado se conserva en
resultado$eliminados salvo decisión contraria. Sin ese
consentimiento la llamada se niega antes de tocar nada:
no corre ninguna acción del plan, tampoco las que no eliminan, y el
error dice cuáles son los dos caminos.
n_no_reversibles no se lee por el nombre de la acción
sino por lo que quedó en el resultado: una normalización que funde dos
valores que eran distintos —pasar ana y ANA a
ANA— cuenta esas celdas, porque lo que las separaba no
quedó en ningún lado.
Lo que el plan no cubre lo dice
Leer tres acciones no significa que lo demás esté bien, así que el
plan declara sus huecos en tres atributos:
cobertura_diagnosticos —los diagnósticos que el perfil no
pudo evaluar—, hallazgos_sin_accion_por_columna_ambigua
—los hallazgos cuya columna comparte nombre con otra, así que no hay
forma de saber sobre cuál actuaría la limpieza— y
hallazgos_sin_accion —los hallazgos que el perfil midió y
que ninguna acción atiende, con el motivo medido de cada uno—. La
impresión del plan los anuncia y el informe HTML les da su propia
sección.
Imputar por una dependencia
Una dependencia funcional exacta permite deducir un valor desde los propios datos, pero sigue siendo una regularidad observada en una entrega. Puede representar una regla real o un error sistemático. Por eso la acción se ofrece con mapa y soporte, pero no queda recomendada ni activa.
datos <- data.frame(
codigo = rep(1:3, each = 4),
descripcion = rep(c("A", "B", "C"), each = 4),
stringsAsFactors = FALSE
)
datos$descripcion[c(2, 6)] <- NA
perfil_fd <- perfilar(datos, muestra = Inf)
plan_fd <- planificar_limpieza(perfil_fd, datos)
imputacion <- grep(
"^imputar_dependencia_funcional", plan_fd$estrategia
)
plan_fd[imputacion, c(
"estrategia", "recomendada", "aplicar", "justificacion"
)]
#> estrategia recomendada aplicar
#> 6 imputar_dependencia_funcional__codigo FALSE FALSE
#> justificacion
#> 6 La relación codigo -> descripcion es exacta en 10 filas presentes y cada valor usado tiene al menos 2 observaciones de soporte. Debe confirmarse como regla antes de imputar.Después de confirmar la regla, el usuario activa una alternativa y registra la decisión. La dependencia vuelve a validarse al aplicar el plan.
plan_fd$aplicar[imputacion[1]] <- TRUE
plan_fd$decision_grupo[imputacion[1]] <- "elegida"
resultado_fd <- aplicar(plan_fd, datos)
resultado_fd$datos
#> codigo descripcion .fila_duplicada .grupo_duplicado
#> 1 1 A FALSE 1
#> 2 1 A FALSE NA
#> 3 1 A TRUE 1
#> 4 1 A TRUE 1
#> 5 2 B FALSE 2
#> 6 2 B FALSE NA
#> 7 2 B TRUE 2
#> 8 2 B TRUE 2
#> 9 3 C FALSE 3
#> 10 3 C TRUE 3
#> 11 3 C TRUE 3
#> 12 3 C TRUE 3
resultado_fd$registro[, c("estrategia", "n_cambiadas")]
#> estrategia n_cambiadas
#> 1 marcar_filas_duplicadas 10
#> 2 imputar_dependencia_funcional__codigo 2El ciclo termina volviendo a perfilar. Así la mejora queda vinculada a un plan y a un registro, no a una transformación invisible.
