| Theme | Count |
|:------------|--------:|
| Supervision | 68 |
| Workload | 45 |
| Isolation | 31 |
| Health | 20 |
| Finances | 14 |
| Family | 14 |
| Other | 8 |
Using AI with Python
Using AI with Python
Draft with AI, check everything, and stay responsible
Chapter 18
Polla Fattah
By the end of today you can
- explain how the reliability of coding is measured, and why chance matters;
- explain how large language models work, and why they make confident mistakes;
- use an AI assistant to write, explain, and debug Python code, and check its answers;
- call a language model from Python (via Ollama or APIs) with structured schemas;
- validate AI coding against human coding with accuracy and Cohen’s kappa;
- use AI responsibly: protect participant data, keep work reproducible, and disclose tools.
Text as research data
“What has been your biggest challenge during your studies?”
536 students answered in their own words (RQ11).
200 answers were coded by hand into themes, which took most of two weeks. Could an AI tool code the rest reliably?
Qualitative coding
Reading each text and assigning it to a theme defined in a codebook.
Coding is judgement, and judgements differ.
Whether the coder is a person, a keyword regex dictionary, or a machine learning model, the question is the same: does it code reliably?
Raw agreement can mislead
coder_a = ["Workload"] * 16 + ["Family"] * 4
coder_b = ["Workload"] * 14 + ["Family"] * 2 + ["Workload"] * 2 + ["Family"] * 2| Observed agreement | Chance agreement | Cohen’s kappa |
|---|---|---|
| 80% | 68% | 0.38 |
Each coder puts 80% under Workload, so random coders matching their class distributions would agree 68% of the time purely by chance!
Cohen’s kappa
\[ \kappa = \frac{\text{observed} - \text{chance}}{1 - \text{chance}} \]
| Kappa | Agreement |
|---|---|
| 0 | no better than chance |
| 0.41 to 0.60 | moderate |
| 0.61 to 0.80 | substantial |
| above 0.80 | almost perfect |
cohen_kappa_score() from scikit-learn. The standard measure of inter-rater reliability.
How large language models work
- a neural network (Chapter 15) with billions of parameters/weights;
- trained on vast corpora of text: books, research papers, websites, code;
- learns to predict the next token (a word or sub-word unit);
- answers by generating one likely token at a time;
- instruction-tuning (RLHF) shapes it into an assistant that follows prompts.
Why they make confident mistakes
| Strength or weakness | Because |
|---|---|
| fluent in Python | Python is widely represented in training datasets |
| hallucination: plausible inventions | it produces what is statistically probable, not fact-checked |
| out of date | knowledge cuts off at the training snapshot |
| knows nothing about your data | unless you explicitly provide schemas or sample rows |
Use AI to draft, and check everything it produces.
Asking good questions
| Include | Example |
|---|---|
| the goal | “Calculate the percentage of students in each faculty who considered dropping out” |
| the data | column names, dtypes, and sample rows (e.g. from .info()); never send identifiable data |
| the tools | pandas method-chaining, scikit-learn pipelines |
| for errors | the exact Python traceback and the minimal reproducing snippet |
A plausible answer that is wrong
students.groupby("faculty")["considering_dropout"].apply(
lambda x: 100 * (x == "Yes").sum() / len(students)
)It runs without errors, and the numbers look plausible.
But they add up to 21% across all faculties: len(students) divides by all 600 students, rather than the denominator of each faculty!
The corrected code
The mean of a boolean Series (x == 'Yes') gives the proportion True within each faculty (Chapter 6).
Not a hallucination, but a plausible misunderstanding: the most dangerous kind of bug, because nothing crashes.
Four checks
- run the code on a tiny synthetic example with a known ground truth;
- check a number by another route:
pd.crosstab(students['faculty'], students['considering_dropout'], normalize='index'); - inspect the documentation: does the argument or function actually do what you think?
- ask the assistant to explain each step line by line.
Assistants are superb tutors: “explain this line by line”, “why did this produce NaNs?”.
AI inside the editor
- GitHub Copilot in VS Code suggests code completions inline as you type;
- Claude / Cursor / Gemini can inspect workspace context and provide contextual edits.
Suggestions arrive instantly and look authoritative. Always read and verify each suggestion before accepting.
The answers to be coded
They vary in length and style, often mention multiple challenges simultaneously, and contain typos.
Seven themes. The 200 hand-coded responses serve as the benchmark test set (Chapter 11).
The hand-coded themes
Coding by keywords
keywords = {
"Supervision": r"\b(supervis|feedback|guidance|meeting)",
"Finances": r"\b(money|fee|scholarship|rent|afford|salary|income|funding)",
"Family": r"\b(famil|child|kid|son\b|daughter|baby|parent|husband|wife)"
} # plus Workload, Health, Isolation, and OtherA regular expression: | means “or”, \b asserts a word boundary.
Words are not meaning
One Family word, one Isolation phrase, two Finances words: Finances wins by count, even though a human reader might judge family or isolation paramount.
| Keywords against hand coding | Accuracy | Kappa |
|---|---|---|
| Rule-based Regex | 61.0% | 0.51 |
“My supervisor” mentioned in an answer about letting down one’s family is really about family.
Calling a language model from Python
| Deployment | Examples | Characteristics |
|---|---|---|
| online API | OpenAI, Anthropic, Google Gemini | API key required; small cost per request; cloud processing |
| local model | Ollama (gemma4:e4b, llama3) |
Free; offline; data never leaves your local workstation |
Store API keys in environment variables or .env files, never hardcoded in scripts or pushed to Git.
A local model via Ollama
import ollama
client = ollama.Client()
response = client.chat(
model="gemma4:e4b",
messages=[{"role": "user", "content": "In one sentence, what does Cohen's kappa measure?"}],
options={"temperature": 0.0}
)
print(response["message"]["content"])Always specify the exact model identifier and set temperature: 0.0 for deterministic reproducibility.
The codebook as a system prompt
codebook = """
You are helping a researcher code open-ended survey answers ...
Assign each answer to exactly ONE theme: the main challenge.
Themes:
- Supervision: the supervisor; feedback, guidance, meetings.
- Workload: too much work or too little time; deadlines, reading.
- Finances: money, fees, scholarships, living costs.
- Family: children, partners, parents, caring duties.
- Health: physical or mental health, sleep, stress, burnout.
- Isolation: loneliness, far from home, no colleagues.
- Other: anything else, such as ethics approval or statistics.
"""Consistent guidelines supplied to every evaluation call.
Structured outputs with Pydantic
from pydantic import BaseModel
from typing import Literal
ThemeLiteral = Literal["Supervision", "Workload", "Finances", "Family", "Health", "Isolation", "Other"]
class CodedAnswer(BaseModel):
theme: ThemeLiteral
confidence: floatStructured schemas force the model to output valid, strongly typed JSON fields rather than conversational chit-chat.
Checking replies in code
# Fallback parser for plain-text replies from compact local models:
def parse_theme(reply_text, valid_themes=themes):
cleaned = re.sub(r"[^A-Za-z]", "", reply_text).lower()
for t in valid_themes:
if cleaned == t.lower():
return t
return np.nanAny reply failing schema compliance produces NaN—which is audited and counted, rather than silently ignored.
Run once, save, analyse the file
The script records model checkpoint, execution timestamp, library versions, and elapsed runtime.
| Metric | Value |
|---|---|
| model | Gemma 4 (e4b) via Ollama |
| responses evaluated | 200 benchmark + 536 full dataset |
| runtime | ~18 minutes |
| schema failures | 0 |
The model against the hand coding
| Coder | Accuracy | Kappa | Interpretation |
|---|---|---|---|
| Regex Keywords | 61.0% | 0.510 | Moderate |
| Language Model | 90.0% | 0.874 | Almost Perfect |
The model achieves almost perfect agreement (\(\kappa = 0.874\)) with human ground truth, outperforming regex dictionaries by 29 percentage points.
Read the disagreements
| Answer | Hand Coded | Model |
|:---------------------------------------------------------------------|:-------------|:----------|
| Getting feedback on my draft took over a month, and by then I had... | Supervision | Isolation |
| Combining coursework, my job at a school and my thesis leaves me ... | Workload | Health |
| I stopped exercising and I can feel the difference. The doctor to... | Health | Other |
| Writing my literature review took far longer than I planned. And ... | Workload | Isolation |
Is the model wrong, the human coder inconsistent, or the text genuinely polysemous? Auditing disagreements clarifies codebook definitions.
Is the model repeatable?
Tested twice at temperature = 0.0, the model yielded 100% identical thematic classifications across all 200 responses.
Repeatability is essential for reproducible science: outputs are persisted to CSV and archived.
What the students said

Distribution of all 536 student responses, automated after kappa validation.
Text and numbers tell the same story
| Theme | Students | Mean Supervisor Support |
|:------------|-----------:|--------------------------:|
| Supervision | 177 | 2.82 |
| Isolation | 61 | 3.3 |
| Other | 23 | 3.31 |
| Health | 56 | 3.33 |
| Family | 47 | 3.43 |
| Finances | 49 | 3.45 |
| Workload | 122 | 3.46 |
Students classified under “Supervision” reported the lowest supervisor support scores on quantitative Likert items (RQ11 criterion validity).
Check, and stay responsible
- run generated code on synthetic validation cases;
- verify external citations: language models frequently fabricate non-existent DOI references;
- validate algorithmic coding against hand-coded benchmarks (\(\kappa \ge 0.80\)).
You remain personally and academically responsible for every claim, table, and analysis in your thesis.
Protect your data
- text transmitted to third-party APIs leaves your machine and may be logged or used for training;
- verify ethics committee approval and participant consent forms before any external processing;
- scrub names, emails, and identifying organizational details;
- for sensitive, confidential, or clinical data, deploy an offline local model (e.g. Ollama).
Keep it reproducible
| Parameter | Documentation Requirement |
|---|---|
| Provider & Model | Exact model tag, checkpoint hash, and inference date |
| Hyperparameters | Temperature, max tokens, top-p |
| System Prompts | Full codebook text and Pydantic validation schema |
| Raw Outputs | Commit raw prediction logs to project repository |
Disclose it
AI tools cannot be listed as co-authors because they cannot assume legal or ethical responsibility (COPE / ICMJE guidelines).
“Open-ended survey responses were coded into seven themes using a local large language model (Gemma 4 e4b via Ollama, temperature 0.0) following the codebook in Appendix X. Inter-coder reliability was validated against a random hand-coded sample of 200 responses using Cohen’s kappa (\(\kappa = 0.874\)). Prompts, schemas, and raw outputs are archived in the supplementary materials.”
Be aware of bias
Models inherit systematic biases from training data:
- skewed framing across demographic subgroups;
- disparate performance on non-standard dialects or second-language English phrasing;
- cultural assumptions embedded in pre-training corpora.
Evaluate validation accuracy across demographic subsets to detect performance disparities.
In your field: medicine and health data
from pydantic import BaseModel
class MedicationExtraction(BaseModel):
drug: str
dose_mg: float
frequency_per_day: intConvert unstructured clinical notes into validated, structured records. Always validate against clinician-reviewed gold standards, and never upload patient data to cloud services.
Practical lab: Chapter 18 playground
Complete the interactive exercises in your browser:
- checking assistant scripts for silent logical errors;
- dictionary regex matching vs. machine learning;
- computing observed agreement, chance agreement, and Cohen’s kappa;
- auditing confusion matrices and disagreement patterns.
Completion checklist
Misconceptions to leave behind
| Misconception | Better mental model |
|---|---|
| High raw agreement indicates reliable coding | Raw agreement is inflated by class imbalance; Cohen’s kappa is required |
| The AI “knows” facts and data structures | It generates statistically likely token sequences that require verification |
| Model outputs are unvarying | Changes in version, system prompt, or temperature alter predictions |
| AI assistance must be concealed | Academic integrity requires transparent disclosure of all computational tools |
The chapter in one sentence
Treat AI output as a draft: validate it against human judgement, protect participants, record what you did, and say so.
Next: Chapter 19
The capstone chapter brings every component together into a completed thesis:
- end-to-end data pipelines from raw exports to tidy data;
- answering each research question systematically;
- building polished tables and figures;
- connecting findings into a coherent academic discussion.
Questions
Which part of your own analysis would you trust an AI to draft?
How would you check it?