---
id: infer_semantic_type_py_datascience
name: infer_semantic_type
kind: function
lang: py
domain: datascience
version: "1.0.0"
purity: pure
signature: "def infer_semantic_type(values: list, sample: int = 200, min_match: float = 0.8) -> dict"
description: "Detects the semantic type of a text column via regex (email, url, ipv4, ipv6, uuid, iban, credit_card, phone_intl, postal_code_es, currency, datetime_iso, date_eu, integer, decimal, boolean, hex_color). Cheap first pass for EDA without an LLM: samples non-null values and returns the type whose match rate is highest and above a threshold."
tags: [eda, semantic-type, profiling, regex, column-inference, datascience]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: [re]
example: |
  from infer_semantic_type import infer_semantic_type
  infer_semantic_type(["ana@example.com", "bob@test.org"])
  # {"semantic_type": "email", "match_rate": 1.0, "candidates": [...]}
tested: true
tests:
  - "test_emails_dominante"
  - "test_uuids_dominante"
  - "test_mezcla_sin_tipo_dominante"
  - "test_lista_vacia"
  - "test_solo_nulos_y_blancos"
test_file_path: "python/functions/datascience/infer_semantic_type_test.py"
file_path: "python/functions/datascience/infer_semantic_type.py"
params:
  - name: values
    desc: "Column values (any type). Each is coerced to str and stripped before matching. None and empty/whitespace-only strings are treated as null and skipped."
  - name: sample
    desc: "Maximum number of non-null values to test against the pattern catalog. Default 200. Caps cost on large columns."
  - name: min_match
    desc: "Minimum fraction (0.0-1.0) of sampled values that must match a type for it to be returned as semantic_type. Default 0.8."
output: >
  Dict with three keys: "semantic_type" (str) = best matching type if its
  match_rate >= min_match, else ""; "match_rate" (float) = fraction of sampled
  values matching the best type (0.0 when no candidate); "candidates"
  (list of {"type": str, "match_rate": float}) = every type with match_rate > 0,
  sorted by match_rate descending (for debugging).
---

## Ejemplo

```python
from infer_semantic_type import infer_semantic_type

# Columna homogenea de emails -> tipo claro
infer_semantic_type([
    "ana@example.com",
    "bob@test.org",
    "carol.smith@mail.co.uk",
    "dev+tag@domain.io",
])
# {"semantic_type": "email", "match_rate": 1.0,
#  "candidates": [{"type": "email", "match_rate": 1.0}]}

# Columna mezclada sin tipo dominante -> "" pero candidates ayuda a depurar
infer_semantic_type([
    "ana@example.com",
    "https://example.com/path",
    "550e8400-e29b-41d4-a716-446655440000",
    "just free text",
])
# {"semantic_type": "", "match_rate": 0.25,
#  "candidates": [{"type": "email", "match_rate": 0.25}, ...]}
```

## Cuando usarla

Cuando perfilas un dataset y necesitas saber QUE representa una columna de texto
(email, url, iban, uuid, fecha, importe...) antes de decidir parsing, validacion
o anonimizacion. Es el primer paso barato del EDA: corre en regex puro, sin LLM
ni dependencias, y dejas la inferencia cara (LLM, ML) solo para las columnas que
salen ambiguas (`semantic_type == ""`, mirar `candidates`).

## Notas

- Funcion pura: solo usa `re` de stdlib, sin I/O ni estado mutable.
- El match es por `fullmatch` (el valor entero debe conformar al tipo, no un
  substring), asi un texto libre que "contiene" un email no cuenta como email.
- Tipos solapan a proposito (un entero matchea `integer` y `boolean` para "0"/"1");
  por eso se devuelve el de mayor `match_rate` y, en empate, el alfabeticamente
  menor para que el resultado sea determinista. Revisar `candidates` cuando el
  resultado sorprenda.
- `credit_card` no aplica validacion Luhn; el regex de 16 digitos basta para EDA.
