[1] "export trade vol 407"
QTA principles, cleaning, tokens, and document-feature matrices
2026-09-18Fall 2026 (115-1) · National Taiwan University (GIND)
NTLDEV 7191 · Fri. 16:30–18:20 · 國發 204
Last compiled: 2026-09-20 04:58:27 (Asia/Taipei)
Week 2: Text Preparation in R and Python: Collaborative Workflow
Week 4 content introduced today: Text preprocessing and document-feature matrices (DFMs). Week 4 builds on these with dictionaries, sentiment analysis, and validation.
Schoonvelde (2026); Welbers et al. (2017)
Schoonvelde (2026); Grimmer et al. (2022)
Classroom example: measuring expressed preference for coffee.
| Design choice | Example |
|---|---|
| Target population | Thai-language public posts about coffee in a specified month |
| Quantity of interest | Share of those posts expressing positive preference for coffee |
| Observed corpus | Posts returned by one platform API and a specified keyword search |
Found data: document how the texts were produced, preserved and retrieved.
The next step is to examine what the collection process leaves out.
Grimmer et al. (2022)
| Source of bias | Example | Research consequence |
|---|---|---|
| Resources | Well-funded groups archive more documents | Available texts overrepresent some actors |
| Incentives | Politicians publish strategically | Public statements differ from private beliefs |
| Medium | A platform limits length or visibility | The medium shapes expression |
| Retrieval | Searching only for “economy” | Relevant texts with other words disappear |
Schoonvelde (2026); Grimmer et al. (2022)
| Decision | Example | What to record |
|---|---|---|
| Population | Parliamentary speech contributions | Chamber, actors, dates |
| Inclusion | All contributions in selected debates | Rule and exclusions |
| Document unit | One contribution per row | How segments were defined |
| Identifier | A persistent doc_id |
Links to source and metadata |
Changing the unit to speaker-day or party-year changes the comparison.
Schoonvelde (2026); Welbers et al. (2017)
| Source | Typical route | First check |
|---|---|---|
| Existing corpus | Download plus codebook | Coverage and sampling |
| TXT, CSV, TSV | readr, data.table, base R |
Encoding and columns |
| JSON or API | jsonlite, httr2 |
Pagination and identifiers |
| HTML or XML | rvest, xml2 |
Boilerplate and structure |
| PDF or DOCX | pdftools, readtext |
Reading order and document boundaries |
Scanned PDFs may need OCR before they contain usable text.
Schoonvelde (2026); Welbers et al. (2017)
Historical package overview (2017). Package responsibilities and APIs have since changed.
Welbers et al. (2017)
| Tool / access from R | Model type | Output and use |
|---|---|---|
UDPipe 1: R udpipe |
Supervised annotation pipeline trained on a treebank | Tokens, lemmas, POS, dependency labels |
| UDPipe 2: R + REST API | Neural annotation with contextual embeddings | Linguistic annotations; current models use BERT-based representations |
Flair: R reticulate + Python( flaiR; Liao et al., 2023) |
Contextual string embeddings or Transformer embeddings | Word/document vectors; models for NER, tagging and classification |
FlairEmbeddings uses character language models; TransformerWordEmbeddings uses models such as BERT.
R can prepare text, call these tools, and analyze the returned annotations or vectors.
Straka & Straková (2017); Straka (2018); Akbik et al. (2018, 2019); Liao et al. (2023)
| Tool / access | Main emphasis | Typical output |
|---|---|---|
| quanteda (R) | Corpus management and feature analysis | Corpus, tokens, DFM; KWIC and TF-IDF |
| UDPipe (R / API) | Linguistic annotation using trained models | Tokens, lemmas, POS, UD dependency labels |
| spaCy (Python) | Configurable NLP pipelines | Tokens, POS, dependencies, named entities |
| Flair (Python) flaiR: R wrapper for Python Flair |
Embeddings and neural task models | Vectors; entity labels, POS, text categories |
The tools can work together: lemmas or selected annotations can become features in a quanteda DFM.
Capabilities overlap and depend on the language, model, and task.
Benoit et al. (2018); Straka & Straková (2017); Explosion (n.d.); Akbik et al. (2019); Liao et al. (2023)
One possible application: compare the meanings of policy statements.
| Stage | Example tools | Contribution |
|---|---|---|
| Prepare in R | stringr, quanteda |
Clean text and preserve document IDs |
| Represent in Python | sentence-transformers |
Encode texts as semantic vectors |
| Evaluate in R | Statistical models and plots | Validate similarities and interpret patterns |
The languages can share a project. Each stage follows the research question.
Sentence Transformers contributors (n.d.); Ushey et al. (2026)
An IDE organizes the work. Object or file exchange connects the languages.
Ushey et al. (2026); Posit (n.d.)
In 2022, RStudio the company became Posit, reflecting its broader support for data science across languages.
Our classroom examples use R.
Posit (2022, n.d.); Altman (2025)
The branch matters: analysis can use a matrix, token positions, or other representations.
Welbers et al. (2017)
| Object | Contents | Use |
|---|---|---|
| Data frame | Text, identifiers, metadata | Import checks and joins |
corpus |
Text with document variables | Subsets and metadata access |
tokens |
Sequences of tokens | Phrase matching and context inspection |
dfm |
Documents × features | Counts and weighted representations |
stringr handles strings. quanteda provides the corpus, tokens, and DFM workflow.
Welbers et al. (2017); Schoonvelde (2026)
A UTF-8 argument does not repair a wrongly identified source encoding.
Schoonvelde (2026); Welbers et al. (2017)
| Field | Value in the source slide |
|---|---|
| Date | 1997-01-20 |
| Speaker | William Hague |
| Party | Conservative |
| Agenda | Public Expenditure [Oral Answers To Questions > Wales] |
Text includes [Interruption.], DRAMATICALLY, and !!!.
Which elements are metadata, meaningful language, or recording conventions?
Schoonvelde (2026)
| Element | Possible treatment | Information at stake |
|---|---|---|
| Speaker and party | Store as metadata | Who speaks |
[Interruption.] |
Remove or extract into an indicator | Parliamentary interaction |
| Capitalization | Preserve or lowercase | Names and emphasis |
| Numbers | Keep, normalize, or remove | Years, budgets, percentages |
| Repeated punctuation | Preserve or simplify | Rhetorical emphasis |
Keep an untouched copy of the raw text.
Schoonvelde (2026); Welbers et al. (2017)
| Function | Purpose | Example use |
|---|---|---|
str_detect() |
Test whether a pattern appears | Flag bracketed annotations |
str_extract() |
Retrieve the first match | Extract a year |
str_remove_all() |
Remove all matches | Delete selected annotations |
str_replace_all() |
Replace matches | Standardize separators |
str_squish() |
Normalize whitespace | Remove repeated spaces |
str_to_lower() |
Change case | Merge case variants |
Schoonvelde (2026); Wickham (2025)
The first pattern spans from the first [ to the last ]. The second handles separate, non-nested bracket groups.
Schoonvelde (2026); Wickham (2025)
[1] "export trade vol 407"
This rule preserves numbers and removes punctuation. Another task may need a different rule.
Schoonvelde (2026)
| ID | Synthetic text |
|---|---|
| d1 | Health workers need health services. |
| d2 | The government supports health services. |
| d3 | Workers do not support the policy. |
| d4 | The government supports the policy. |
These short texts let us inspect every token and verify every count.
Each row supplies one text. The remaining columns become document variables.
Welbers et al. (2017); Schoonvelde (2026)
Text: “Health services need health workers.”
| Representation | Tokens | Distinct types |
|---|---|---|
| Case and punctuation retained | 6 | 6 |
| Lowercase, punctuation removed | 5 | 4 |
After normalization: health, services, need, health, workers
A token is an occurrence. A type is a distinct form under the chosen representation.
Schoonvelde (2026); Welbers et al. (2017)
Both use tokens: units produced by tokenization for analysis or model processing.
| Comparison | Common R text-analysis workflow | Typical LLM workflow |
|---|---|---|
| Common units | Words; optionally characters or sentences | Often subwords; can include whole words, characters or byte units |
| Segmentation depends on | Package, tokenizer and your settings | The model’s tokenizer and vocabulary |
| Main use | Word counts, DFM, TF-IDF, topic models | Token IDs used for model input and text generation |
One word can become several LLM tokens. R can call either kind of tokenizer; the workflow determines the unit.
Benoit et al. (2018); Wolf et al. (2020)
[1] "health" "workers" "need" "health" "services"
Inspect the output when texts contain hyphens, URLs, abbreviations, or non-Latin scripts.
Schoonvelde (2026); Benoit et al. (2018)
| Choice | Possible benefit | Possible loss |
|---|---|---|
| Lowercase | Merge Health and health |
Proper-name distinctions |
| Remove stopwords | Reduce frequent function words | Negation or writing style |
| Stem or lemmatize | Merge some word forms | Differences in meaning |
| Trim rare features | Reduce vocabulary size | Rare but important concepts |
The relevant question is how the choice affects the intended measure.
Schoonvelde (2026); Welbers et al. (2017)
| Rule applied to document d3 | Remaining tokens |
|---|---|
| Standard English stopword list | workers support policy |
| List that retains negation | workers not support policy |
Retaining not preserves a clue. A unigram model still needs a way to use its scope.
Schoonvelde (2026); Welbers et al. (2017)
A DFM stores one row per document and one column per feature.
| ID | health | workers | government | policy | not |
|---|---|---|---|---|---|
| d1 | 2 | 1 | 0 | 0 | 0 |
| d2 | 1 | 0 | 1 | 0 | 0 |
| d3 | 0 | 1 | 0 | 1 | 1 |
| d4 | 0 | 0 | 1 | 1 | 0 |
Selected columns from our count DFM. Features can also represent phrases or other categories.
Schoonvelde (2026); Welbers et al. (2017)
“Workers support government.”
“Government support workers.”
The two sentences have the same lowercase unigram counts.
N-grams and syntax retain some additional information.
Schoonvelde (2026); Welbers et al. (2017)
armed_forces becomes a single feature. Detect phrases before removing words that belong inside them.
Schoonvelde (2026); Welbers et al. (2017)
workers_do, do_not, not_support, support_the, the_policy
Generate these before stopword removal if original adjacency matters. Deleting words first can create pairs that were never adjacent.
Schoonvelde (2026); Welbers et al. (2017)
| Feature strategy | Example | Required judgment |
|---|---|---|
| Known phrase | armed_forces |
Which phrases matter? |
| Statistical collocation | Candidate such as northern_ireland |
Is association substantively useful? |
| POS selection | Nouns, verbs, adjectives | Which grammatical roles fit the task? |
A frequent or associated word pair is a candidate feature. Inspect its uses before adding it to the measurement rule.
Schoonvelde (2026); Welbers et al. (2017)
| Method | Example | Limitation |
|---|---|---|
| Stemming | studies becomes studi |
Stems may not be dictionary words |
| Lemmatization | studies may become study |
Accuracy depends on language and context |
| Explicit replacement | Map forces to force |
Only the supplied mapping is handled |
Neither approach guarantees correct semantic grouping. A dictionary built from full words may fail to match stemmed features.
Schoonvelde (2026); Welbers et al. (2017)
A BoW preprocessing recipe should not automatically become an LLM input recipe.
Schoonvelde (2026); Welbers et al. (2017)
| Input language | Access from R | Model |
|---|---|---|
| Japanese | udpipe: local UDPipe 1 |
japanese-gsd (UD 2.5) |
| Traditional Chinese | udpipe: local UDPipe 1 |
chinese-gsd (UD 2.5) |
| Thai | httr2: UDPipe 2 API |
thai-tud (UD 2.17) |
token and predicted upos (POS).lemma is a predicted base form; this Thai model returns _ (unavailable).Instructor demonstration: interpret the prepared model outputs shown in these slides.
Wijffels & Straka (2026); Straka (2018); Universal Dependencies contributors (n.d.)
Chinese: chinese-gsd; English: english-ewt; Thai: R + UDPipe 2 API.
parser = "default" adds dependency parsing to tokens and POS.head_token_id identifies the head; dep_rel labels the relationship. Head 0 marks the sentence root.Wijffels & Straka (2026); Universal Dependencies contributors (n.d.)
Same meaning: “I like coffee.”
R: httr2 + UDPipe 2 API
ฉันชอบกาแฟ
Tokens (POS)
ฉัน (PRON)
ชอบ (VERB)
กาแฟ (NOUN)
3 tokens
The Thai model finds word boundaries.
R: udpipe (japanese-gsd)
私はコーヒーが好きです。
Tokens (POS)
私 (PRON) / は (ADP)
コーヒー (NOUN) / が (ADP)
好き (ADJ) / です (AUX)
6 tokens
Particles and auxiliaries remain separate tokens.
R: udpipe (chinese-gsd)
我喜歡咖啡。
Tokens (POS)
我 (PRON)
喜歡 (VERB)
咖啡 (NOUN)
3 tokens
Multi-character words can form single tokens.
POS = part of speech. Counts exclude punctuation.
Straka & Straková (2017); Straka (2018)
Same meaning: “I like coffee.”
R: udpipe (chinese-gsd)
我喜歡咖啡。
| Token (POS) | dep_rel |
|---|---|
| 1 我 (PRON) | nsubj |
| 2 喜歡 (VERB) | root |
| 3 咖啡 (NOUN) | obj |
Head IDs: 2 / 0 / 2
R: udpipe (english-ewt)
I like coffee.
| Token (POS) | dep_rel |
|---|---|
| 1 I (PRON) | nsubj |
| 2 like (VERB) | root |
| 3 coffee (NOUN) | obj |
Head IDs: 2 / 0 / 2
R: httr2 + UDPipe 2 API
ฉันชอบกาแฟ
| Token (POS) | dep_rel |
|---|---|
| 1 ฉัน (PRON) | nsubj |
| 2 ชอบ (VERB) | root |
| 3 กาแฟ (NOUN) | obj |
Head IDs: 2 / 0 / 2
nsubj = nominal subject; root = sentence root; obj = object.
Head 0 marks the root; other IDs point to a token in the same sentence.
Punctuation is omitted from this display.
Straka & Straková (2017); Straka (2018); Universal Dependencies contributors (n.d.)
政府は医療従事者を支援する。
| ID | token | lemma | upos | head | dep_rel |
|---|---|---|---|---|---|
| 1 | 政府 | 政府 | NOUN | 6 | nsubj |
| 2 | は | は | ADP | 1 | case |
| 3 | 医療 | 医療 | NOUN | 4 | compound |
| 4 | 従事者 | 従事者 | NOUN | 6 | obj |
| 5 | を | を | ADP | 4 | case |
| 6 | 支援 | 支援 | VERB | 0 | root |
| 7 | する | する | AUX | 6 | aux |
| 8 | 。 | 。 | PUNCT | 6 | punct |
Dependency parsing: head = head token ID (0 = root); dep_rel = relation.
Straka & Straková (2017)
政府支持醫療工作者。
| ID | token | lemma | upos | head | dep_rel |
|---|---|---|---|---|---|
| 1 | 政府 | 政府 | NOUN | 5 | nmod |
| 2 | 支持 | 支持 | NOUN | 5 | nmod |
| 3 | 醫療 | 醫療 | NOUN | 5 | nmod |
| 4 | 工作 | 工作 | VERB | 5 | compound |
| 5 | 者 | 者 | PART | 0 | root |
| 6 | 。 | 。 | PUNCT | 5 | punct |
Dependency parsing: head = head token ID (0 = root); dep_rel = relation.
Model errors: 支持 is tagged NOUN; 者 is predicted as root. Inspect the original sentence before interpreting these outputs.
Straka & Straková (2017); Universal Dependencies contributors (n.d.)
政府不支持刪減醫療預算。
| ID | token | lemma | upos | head | dep_rel |
|---|---|---|---|---|---|
| 1 | 政府 | 政府 | NOUN | 3 | nsubj |
| 2 | 不 | 不 | ADV | 3 | advmod |
| 3 | 支持 | 支持 | VERB | 0 | root |
| 4 | 刪減 | 刪減 | VERB | 3 | xcomp |
| 5 | 醫療 | 醫療 | NOUN | 6 | nmod |
| 6 | 預算 | 預算 | NOUN | 4 | obj |
| 7 | 。 | 。 | PUNCT | 3 | punct |
Dependency parsing: head = head token ID (0 = root); dep_rel = relation.
Keeping only NOUN and VERB removes 不 (ADV), attached to 支持 (ID 3) by advmod. The feature list loses negation.
Straka & Straková (2017)
ฉันชอบกาแฟ “I like coffee.”
Arrows run from head to dependent.
Corpus measure: share of documents mentioning a target that express positive preference.
Straka (2018); Universal Dependencies contributors (n.d.)
Use as.tokens() to preserve the existing segmentation. Build the Chinese DFM from the Chinese documents in the same way.
Code illustration: annotations → tokens → DFM.
Benoit et al. (2018); Wijffels & Straka (2026)
Benoit et al. (2018)
[1] 4 9
health workers services government supports policy
3 2 2 2 2 2
Rows retain the document IDs. The full DFM includes features beyond the selected columns shown earlier.
Schoonvelde (2026); Welbers et al. (2017)
| Feature | Total occurrences | Documents containing it |
|---|---|---|
health |
3 | 2 |
workers |
2 | 2 |
not |
1 | 1 |
This threshold removes not. A rare feature can still carry essential meaning.
Schoonvelde (2026); Welbers et al. (2017)
| Representation | Meaning of a cell | Possible use |
|---|---|---|
| Count | Number of occurrences | Frequency-based measurement |
| Binary | Whether the feature appears | Presence-based comparison |
| TF-IDF | Count adjusted for corpus prevalence | Document retrieval or comparison |
The choice changes what repeated words contribute. Model requirements may constrain which representation is appropriate.
Schoonvelde (2026); Welbers et al. (2017)
For this lesson, use raw counts and a base-10 logarithm:
TF-IDF(d, t) = count(d, t) × log₁₀(N / df(t))
Different normalizations and smoothing rules produce different weights.
Schoonvelde (2026); Benoit et al. (2018)
For health, N = 4, df = 2, so IDF = log₁₀(2) ≈ 0.3010.
| Document | Count of health |
TF-IDF |
|---|---|---|
| d1 | 2 | 0.6021 |
| d2 | 1 | 0.3010 |
| d3 | 0 | 0 |
| d4 | 0 | 0 |
Benoit et al. (2018)
| docname | pre | keyword | post |
|---|---|---|---|
| d2 | the government | supports | health services |
| d3 | workers do not | support | the policy |
| d4 | the government | supports | the policy |
Read the context around a matched term before treating its count as support for a policy.
Welbers et al. (2017); Benoit et al. (2018)
| Tool | What it lets you do |
|---|---|
| DFM | Represent document features for comparison and modeling. |
| KWIC | Read terms in context and check what feature counts mean. |
| TF-IDF | Emphasize distinctive terms for retrieval and similarity. |
Wordfish is an unsupervised method for scaling texts on one dimension.
Word-count DFM → e.g., Wordfish → relative document positions
Use: compare party manifestos or speeches. Input: counts, not TF-IDF weights.
Interpret and validate the scale before calling it ideology.
Benoit et al. (2018); Slapin & Proksch (2008); Lowe & Benoit (2013)
| Research goal | Method | Output |
|---|---|---|
| Estimate positions | Wordfish / Wordscores | Relative document positions |
| Predict a category | Supervised classifiers | Issue or stance labels |
| Study issue attention | LDA / STM / keyATM | Topics and topic shares |
| Measure a concept | Dictionaries | Category counts or proportions |
| Compare documents | Cosine similarity / clustering | Similarities or document groups |
Inputs matter: Wordfish and these topic models use counts. Classification needs training labels; Wordscores needs reference scores. Similarity can use TF-IDF.
Benoit et al. (2018); Slapin & Proksch (2008); Laver et al. (2003); Blei et al. (2003); Roberts et al. (2019)
Slapin & Proksch (2008)
Reading the axis: Higher values indicate the left; the sign is conventional.
Slapin & Proksch (2008), Figure 1A, p. 714
3 reference speeches (+1 / −1) → scores for 55 other speeches.
Higher scores indicate greater support for the government.
Laver et al. (2003), Figure 3, p. 328
Stance classification Bestvater & Monroe (2023)
Use TF-IDF with an SVM to classify political support or opposition.
TF-IDF supplies weighted features. The analysis determines what we measure.
| Compare | Inspect | Explain |
|---|---|---|
| With / without stopwords | Negation and grammatical context | Which distinctions vanish? |
| Unigrams / phrases | Compound concepts | Which matches change? |
| Full / trimmed vocabulary | Removed features and empty rows | Which documents lose evidence? |
| Counts / TF-IDF | Relative feature contributions | Does the result depend on weighting? |
Keep the corpus and research question fixed while comparing a chosen rule.
Schoonvelde (2026); Welbers et al. (2017)
Download and install: R and Python 3, then RStudio Desktop and Positron.
Try the consoles: 1 + 1 in R; print(1 + 1) in Python. Both return 2.
Open Lab_Session_W2.R in lab/. In the R console, install:
Set the working directory to W2/lab/. Keep its Data/ folder alongside the script. Use the lab section by section for self-study at home.
Take-home skill: Open an .R file in RStudio or Positron and run the lab independently.
R Core Team (n.d.); Python Software Foundation (n.d.); Posit (n.d.)
Self-study practice: ungraded; no submission required. Use the supplied sample of 5,000 House of Commons speech contributions (1945–2025).
stringr.quanteda corpus.Folder: lab/
Open Lab_Session_W2.qmd or its .R companion. Data are included.
Schoonvelde (2026)
Be ready to explain what your code changes and how that affects the evidence.
Explore one application paper introduced earlier. Start with its research question and a main figure.
What is the research question, and what counts as a document?
How could word removal, document aggregation, or weighting affect the measure?
What evidence supports the authors’ interpretation beyond successful preprocessing?
Topic models: Roberts et al. (2014); Eshima et al. (2024)
Text scaling: Slapin & Proksch (2008); Laver et al. (2003)
TF-IDF applications: Blumenau (2021); Bestvater & Monroe (2023)
Primary lecture source
Schoonvelde, M. (2026). Quantitative text analysis – Essex Summer School: Principles of QTA, cleaning text, and preprocessing text. Supplied slides, 38 pages.
Reading and reproduced figure/table
Welbers, K., Van Atteveldt, W., & Benoit, K. (2017). Text Analysis in R. Communication Methods and Measures, 11(4), 245–265. doi:10.1080/19312458.2017.1387238.
Corpus selection reading
Grimmer, J., Roberts, M. E., & Stewart, B. M. (2022). Text as Data: A New Framework for Machine Learning and the Social Sciences. Princeton University Press. Chapter 4: “Selecting Documents.” Book.
Software documentation
quanteda: tokens, TF-IDF, KWIC, stringr: pattern removal.
UDPipe guide, Japanese GSD, Chinese GSD.
The English, Thai, Japanese, and Chinese texts are synthetic teaching examples.