Más allá del solapamiento total: cobertura adaptativa de anotadores para grandes conjuntos de datos
Etiquetar todo por duplicado sale caro; etiquetarlo todo una sola vez te deja a ciegas. Potato 2.6 te permite asignar un anotador a la mayoría de los ítems y tres a una muestra estratificada, con refuerzos adaptativos y enrutamiento automático de arbitraje.
En todo proyecto de anotación de cierto tamaño existe una tensión habitual. Si cada ítem recibe dos o tres anotadores, puedes medir el acuerdo y confiar en tus etiquetas, pero acabas de multiplicar tu presupuesto por dos o por tres. Si cada ítem recibe un solo anotador, etiquetas tres veces más datos por el mismo dinero y no tienes ni idea de cuán fiable es ninguno de ellos.
El compromiso de siempre lo conoce bien cualquiera que haya dirigido un estudio: anotar una sola vez la mayor parte del corpus y anotar por duplicado o triplicado una pequeña muestra para vigilar la calidad. El problema siempre ha estado en lograr que las herramientas hagan eso con limpieza, y luego en hacer algo con el solapamiento una vez que lo tienes. Potato 2.6 incorpora ese diseño de fábrica, mediante dos bloques de configuración (num_annotators_per_item y per_annotator_quota) más refuerzos adaptativos y enrutamiento de arbitraje.
Este artículo recorre el diseño de cobertura desde el caso sencillo hasta el adaptativo. La documentación de cobertura heterogénea contiene la referencia completa.
Cobertura adaptativa de anotadores en Potato
Topes por ítem con una muestra de solapamiento
num_annotators_per_item admite un único entero como tope uniforme, o un mapeo estructurado cuando quieres cubrir ítems distintos de forma distinta. La forma habitual es un valor por defecto de uno, con una muestra estratificada elevada a tres:
num_annotators_per_item:
default: 1
overlap_sample:
fraction: 0.1
count: 3
stratify_by: domain
seed: 42
min: 1El bloque overlap_sample eleva el tope sobre un subconjunto determinista de ítems. El muestreo ocurre una sola vez al arrancar, y los ítems elegidos quedan marcados internamente, de modo que la lógica de asignación los trata como de alta cobertura a partir de ahí. Los campos son sencillos: fraction es la proporción muestreada, count es el tope elevado (debe superar al valor por defecto) y seed hace que la elección sea reproducible entre reinicios.
El detalle que merece atención es stratify_by. Apúntalo a un campo de tus datos (domain aquí) y la proporción se aplica por estrato en lugar de sobre el conjunto entero. Cada categoría aporta a la muestra de solapamiento de forma proporcional, así que no mides el acuerdo sobre una muestra que resulta ser un 90 % de un solo dominio. Si tu corpus mezcla noticias, redes sociales y texto clínico, cada uno aparece en la muestra de calidad en proporción a su tamaño.
Refuerzo adaptativo: gasta más donde cuesta
Una muestra de solapamiento fija se elige a ciegas, antes de que nadie haya anotado nada. Pero los ítems que más necesitan una segunda y una tercera mirada son aquellos en los que los anotadores realmente discrepan, y solo descubres cuáles son después de la primera pasada. El refuerzo adaptativo se ocupa precisamente de eso:
num_annotators_per_item:
default: 1
adaptive:
enabled: true
disagreement_threshold: 0.5
boost_to: 3En cuanto un ítem tiene al menos dos anotaciones y su puntuación de desacuerdo cruza disagreement_threshold, su tope se eleva a boost_to y el ítem vuelve a entrar en la cola de asignación para otra pasada. El refuerzo se aplica una sola vez por ítem, de modo que un ítem polémico recibe un único escalado en lugar de descontrolarse. Es una cobertura que sigue la dificultad de los datos en vez de adivinarla de antemano.
Cupos por anotador
Los topes de cobertura controlan cuántos anotadores recibe cada ítem. Un bloque aparte controla cuántos ítems recibe cada anotador, algo que normalmente conviene variar según la experiencia o el contrato:
per_annotator_quota:
default: 100
by_user:
alice: 30
by_user_role:
expert: 30
novice: 200
user_roles:
alice: expert
carol: noviceLa resolución va de lo más específico a lo más general: primero by_user[uid], luego by_user_role[user_roles[uid]] y, por último, default. Así puedes limitar a un experto concreto a 30 ítems, a todos los demás expertos a 30 por rol y a los principiantes a 200, sin que ambos sistemas interfieran con los topes por ítem anteriores.
Convertir el solapamiento en una decisión
Recoger el solapamiento es solo la mitad del trabajo; lo importante es actuar sobre los desacuerdos. Con el bloque de arbitraje activado, los ítems de la muestra de solapamiento que alcanzan su tope se puntúan automáticamente y se envían a una cola de arbitraje cuando el acuerdo cae por debajo de tu umbral:
adjudication:
enabled: true
adjudicator_users: [admin]
min_annotations: 2
agreement_threshold: 0.75El efecto es que los ítems con poco acuerdo afloran en el momento mismo en que la muestra se satura, en lugar de esperar a que alguien se acuerde de reconstruir la cola a mano. Un árbitro abre la cola y ve los ítems realmente disputados, ya filtrados del grueso en el que todos coincidieron.
Leer el acuerdo
En cuanto los ítems de la muestra de solapamiento se saturan, las estadísticas de acuerdo están disponibles en /admin/iaa. El endpoint calcula la métrica apropiada para el tipo de cada esquema en vez de imponer una sola cifra a todo: kappa de Cohen y de Fleiss para los esquemas nominales, weighted kappa para los ordinales, y kappa a nivel de token más span F1 para los spans. Esto importa porque un κ calculado como si tus valoraciones Likert ordinales fueran categorías sin orden subestimará el acuerdo real.
Para probarlo
Con la versión se incluye una demostración ejecutable. Desde la raíz del repositorio:
python potato/flask_server.py start examples/advanced/heterogeneous-coverage/config.yaml -p 8000Usa 20 ítems de dos dominios, muestrea el 20 % para un solapamiento de tres anotadores estratificado por dominio, activa un refuerzo adaptativo con umbral de 0,5, define dos niveles de experiencia y enruta los ítems con poco acuerdo al arbitraje: todo el diseño anterior, de principio a fin.
La forma de un buen plan de cobertura
En conjunto, el diseño te permite decidir adónde va tu presupuesto de anotación en lugar de repartirlo de manera uniforme. La mayoría de los ítems reciben una pasada. Una porción estratificada recibe tres, de modo que puedes informar de la fiabilidad en todo el corpus y no solo en un rincón. Los ítems que resultan ser genuinamente difíciles se escalan automáticamente, y los disputados se enrutan a un árbitro. Gastas lo máximo en los datos más inciertos y puedes defender cada decisión de cobertura en una sección de métodos.
Cuántos anotadores necesitas realmente para una tarea dada es una cuestión aparte; el artículo cuántos anotadores necesitas repasa las reglas prácticas. Esta versión trata de que cualquier respuesta a la que llegues sea fácil de expresar. La cobertura heterogénea se incluye en Potato 2.6; consulta la documentación de cobertura heterogénea y la referencia de asignación de tareas para todo lo que los bloques anteriores pueden hacer.