text-as-data: teaching an LLM to read the news like a coder
A new open-source pipeline for LLM-assisted event/concept coding — and why validating it against human judgment is the whole point
Anyone who has done qualitative political science knows this routine: a newspaper article reports a statement, a protest, a land occupation — and someone has to turn that paragraph into a row of data. Date, location, actor, and then the column that actually requires judgment: is this a protest? Does this statement support or oppose the policy in question?
That routine has a name in computational political science — automated event coding, or more broadly text-as-data — and it has been an active research area for exactly the reason the manual version is slow: the hard part was never typing the spreadsheet. The hard part is making the coding match the theoretical concept you actually have in mind, not a flattened, generic version of it.
LLMs promise to automate that step: give the model a codebook — your definition of the concept, written the way you’d explain it to a human research assistant — and let it apply that categorization across thousands of texts. The catch is that a model can look like it is following your codebook while quietly falling back on the generic notion of the concept it picked up during training — a construct validity problem, not an accuracy problem (see Halterman & Keith, “Codebook LLMs: Evaluating LLMs as Measurement Tools for Political Science Concepts”, Political Analysis, 2025).
What text-as-data is
A small, honest pipeline about that trap. Unstructured text goes in, a structured table comes out, and validating the output against a human-coded sample is not a script nobody runs — it’s part of the pipeline from the first commit:
texts.csv (id, text)
│
▼
codebook — the construct: an output schema, instructions written the way
you'd brief a human coder, and a few worked examples that pin
down the edge cases
│
▼
extraction — calls an LLM, validates the response against the schema
│
▼
validation — compares against human labels: accuracy, Cohen's kappa, and
the list of disagreements, for inspection
codebook is deliberately kept separate from the extraction/validation engine: the codebook is what changes from project to project, the engine underneath shouldn’t have to.
Where it stands
Right now it’s a working MVP with a synthetic toy example — enough to prove the pipeline runs end to end, not a real research instrument yet. No real pilot domain is picked: land-occupation coding (in the spirit of DATALUTA), industrial-policy/antitrust stance coding, and public-safety event coding are all candidates on the table. Scraping is deliberately out of scope for now — the pipeline assumes text has already been collected.
Code and technical docs live at github.com/mancano-tales/text-as-data (in English, with a Portuguese README telling the longer version of this story). I’ll post an update here once a real pilot domain is picked and the toy example gets replaced by an actual validated codebook.
Quem já fez pesquisa qualitativa em ciência política conhece essa rotina: uma notícia de jornal relata uma declaração, um protesto, uma ocupação de terra — e alguém precisa transformar aquele parágrafo em uma linha de dados. Data, local, ator, e a coluna que exige julgamento de verdade: isso é um protesto? aquela fala é a favor ou contra a política em questão?
Essa rotina tem nome na ciência política computacional — automated event coding, ou de forma mais ampla, text-as-data — e é uma área de pesquisa ativa justamente porque a parte difícil nunca foi digitar a planilha. A parte difícil é fazer a categorização bater com o conceito teórico que você tem em mente, não com uma versão genérica e achatada dele.
Com LLMs, a promessa é automatizar essa etapa: dar ao modelo um codebook — a definição do seu conceito, do jeito que você explicaria para um assistente de pesquisa humano — e deixar que ele aplique essa categorização em milhares de textos. A armadilha é que o modelo pode parecer que está seguindo seu codebook e, na prática, aplicar silenciosamente o conceito genérico que aprendeu no treinamento — um problema de validade de construto, não de acurácia técnica (ver Halterman & Keith, “Codebook LLMs: Evaluating LLMs as Measurement Tools for Political Science Concepts”, Political Analysis, 2025).
O que é o text-as-data
Um pipeline pequeno e honesto sobre essa armadilha. Texto não-estruturado entra, tabela estruturada sai, e validar a saída contra uma amostra codificada por humano não é um script que ninguém roda — é parte do pipeline desde o primeiro commit:
textos.csv (id, texto)
│
▼
codebook — o construto: um schema de saída, instruções escritas do jeito
que você explicaria para um codificador humano, e alguns
exemplos que fecham os casos de borda
│
▼
extração — chama um LLM, valida a resposta contra o schema
│
▼
validação — compara contra rótulos humanos: acurácia, Cohen's kappa, e a
lista de discordâncias, para inspeção
O codebook fica separado de propósito do motor de extração/validação: é a peça que muda a cada projeto novo; o motor por baixo não deveria precisar mudar.
Onde o projeto está
Por enquanto é um MVP funcional com um exemplo sintético de teste — o suficiente para provar que o pipeline roda ponta a ponta, ainda não é um instrumento de pesquisa real. Nenhum domínio-piloto real foi escolhido ainda: codificação de ocupações de terra (na linha do DATALUTA), posicionamento em política industrial/antitruste, e eventos de segurança pública são candidatos na mesa. Scraping fica de fora de propósito por enquanto — o pipeline assume que o texto já foi coletado.
Código e documentação técnica estão em github.com/mancano-tales/text-as-data (em inglês, com um README em português contando a versão mais longa dessa história). Devo postar uma atualização aqui quando um domínio-piloto real for escolhido e o exemplo sintético for substituído por um codebook de verdade, validado.