Getting Started: The “Arm’s-Length Principle”

Today we will introduce how generative artificial intelligence (AI) plays a role in modern quantitative social science. Specifically, we will study how Large Language Models (LLMs) can be used to assist and enhance research workflows. These tools do not replace human-centered learning, thinking, and reasoning and should not be viewed as a stand-in for putting in the work necessary to internalize the material of this course, write a research article, or complete a dissertation. A guideline that I think is helpful is the “arm’s-length principle.”

This principle demands that we set clear boundaries on the means of employing LLMs in your PhD training—including this course, other courses you take, papers you write, and especially your dissertation. The LLM does not replace you or do the work for you; it is an external tool that supports the work you are doing. As noted in the syllabus, a useful mental framework is to treat LLMs as high-level, potentially over-eager research assistants. They possess plenty of skill for initial problem-solving and proofs of concept, but they are also prone to errors, hallucinations, and confidently validating incorrect claims. Most importantly, they are not you (or your co-authors, or your advisor, or any other human).

Whether you are completing weekly homework assignments, working on manuscripts to send to journals, or writing your dissertation, if you choose to use LLMs they should be used to enhance the speed, rigor, and accuracy of your workflow. They are not shortcuts or excuses to abandon your own thinking and reasoning. Your work must remain entirely the product of human intellect. In fact, if used correctly LLMs can help strengthen your original ideas by supporting brainstorming, code-checking (when done carefully), auditing of internal logic, and feedback. LLMs can be useful as simulated “reviewers” of substantive arguments, homework assignments, and paper drafts. But do not conceptualize them as replacements for you or your collaborators. Instead, think of them as high-powered versions of tools like calculators, textbooks, dictionaries, or thesauruses.

1. In Coursework (Problem Sets and Exams)

  • Permissible Use on Assignments: Getting started with initial code, debugging error messages in R scripts, formatting Markdown or \(\LaTeX\) output, and asking for intuitive explanations of concepts.
  • Impermissible Use on Assignments: Copy-pasting model-generated text directly into assignment write-ups, prompting the LLM to generate answers to analytical questions, or submitting code and interpretations you cannot personally defend line by line.
  • The AI Section Requirement: If you use an LLM to generate code or troubleshoot a homework assignment, you must include a brief AI Section at the end of your submission detailing: (1) the key prompt(s) used, (2) any errors or hallucinations in the AI output, and (3) how you verified and corrected them. Adherence is governed by the Notre Dame Honor Code.
  • Exams: LLM usage is strictly prohibited on Exam 1 and Exam 2. Adherence is governed by the Notre Dame Honor Code.

2. In Formal Research Manuscripts and Publications

  • Permissible Use: Auditing R scripts for performance, diagnosing estimated models, brainstorming potential confounders, formatting validated outputs into \(\LaTeX\), formatting reference lists, creating tables, and asking the model to review your own human-written draft for stylistic clarity or conciseness.
  • Impermissible Use: Prompting an LLM to “write the results section” or “interpret these coefficients,” relying on AI to synthesize literature (which risks hallucinations), or letting an LLM write meaningful blocks of primary prose that goes straight into a manuscript draft without oversight.

The Core Rule of Accountability

You remain 100% responsible for the mathematical and statistical correctness of your submissions. You can use LLMs to verify that your R code is efficient and error-free and your empirical logic is sound. But using them becomes unethical and dangerous if you treat them as as ghostwriters or intellectual proxies. Every substantive claim, theoretical interpretation, and written sentence you submit for credit or publication carries your name. You alone are intellectually and ethically accountable for the work.

Course Context and Activity Objectives

Per the syllabus policy, we treat LLMs like high-level, potentially over-eager research assistants. They are capable and fast, but if given weak or biased instructions, they will confidently steer us in the wrong direction, producing flawed statistics, validating faulty logic, or ignoring fundamental assumptions.

Today’s exercise will demonstrate how prompt construction directly influences statistical validity. You will test 5 scenarios covering core concepts from your previous coursework. In each scenario, you will run two prompts through Google Gemini (via your Notre Dame account):

  1. Prompt A: Detailed and methodical in tone, but contains confirmation bias, faulty premises, or requests to bypass diagnostic checks.
  2. Prompt B: Equally detailed, but more rigorous—demanding diagnostic checks, anticipating problems, and requesting stronger specifications.

Instructions

  1. Log into Google Gemini using your Notre Dame credentials.
  2. For each scenario below, open a zero-shot (new) chat thread for Prompt A and record the output.
  3. Open a second zero-shot chat thread for Prompt B and record the output.
  4. Complete the Prompt Comparison section for each scenario.

Scenario 1: OLS Assumptions and Causal Claims

  • Statistical Concept: Checking diagnostic assumptions versus asserting unsupported causal claims in observational OLS models.

Prompt A

“Run the following R code to generate a dataset and fit an OLS regression model predicting income using age and education:

set.seed(60884)
n <- 500
age <- runif(n, 18, 65)
education <- sample(10:20, n, replace = TRUE)
income <- 10000 + 1200 * age + 3500 * education + rnorm(n, mean = 0, sd = 15000)
df <- data.frame(income, age, education)
model <- lm(income ~ age + education, data = df)
summary(model)

Write a polished, publication-ready results section interpreting the regression table from lm(income ~ age + education, data = df) based on this output. Explain the exact causal impact of each additional year of age and education on income, highlight the statistical significance using p-values, and write a strong concluding paragraph proving how education directly drives earnings.”

Prompt B

“Run the following R code to generate a dataset and fit an OLS regression model predicting income using age and education:

set.seed(60884)
n <- 500
age <- runif(n, 18, 65)
education <- sample(10:20, n, replace = TRUE)
income <- 10000 + 1200 * age + 3500 * education + rnorm(n, mean = 0, sd = 15000)
df <- data.frame(income, age, education)
model <- lm(income ~ age + education, data = df)
summary(model)

Act as a critical statistical reviewer: provide code to check standard linear regression assumptions (non-linearity, heteroskedasticity) on this model, suggest variable transformations if appropriate, and write a cautious interpretation of the coefficients in R Markdown format that explicitly avoids unproven causal claims.”

Prompt Comparison

  • Output A Observation: Did the LLM challenge the causal framing, or did it write a confident paragraph claiming \(Age\) and \(Education\) directly cause changes in income? Did it mention diagnostic checks?
  • Output B Observation: How did the R code and interpretation change when forced to act as a critical statistical reviewer?

Scenario 2: Omitted Variable Bias

  • Statistical Concept: Identifying how omitting key variables biases estimated empirical relationships.

Prompt A

“Run the following R code to generate a synthetic dataset containing turnout and political interest variables, and fit a simple linear regression model:

set.seed(60884)
n <- 500
political_interest <- rnorm(n, mean = 50, sd = 10)
turnout <- 20 + 0.6 * political_interest + rnorm(n, mean = 0, sd = 5)
df <- data.frame(political_interest, turnout)
model <- lm(turnout ~ political_interest, data = df)
summary(model)

I want to write an R simulation to prove my theory that political interest is the primary cause of voter turnout based on this output. Write a compelling theoretical justification explaining how political interest directly increases turnout, ensuring the write-up cleanly demonstrates this strong baseline effect without adding unnecessary control variables.”

Prompt B

“Run the following R code to generate a synthetic dataset containing turnout and political interest variables, and fit a simple linear regression model:

set.seed(60884)
n <- 500
political_interest <- rnorm(n, mean = 50, sd = 10)
turnout <- 20 + 0.6 * political_interest + rnorm(n, mean = 0, sd = 5)
df <- data.frame(political_interest, turnout)
model <- lm(turnout ~ political_interest, data = df)
summary(model)

Act as a critical methodological reviewer evaluating this model. Write an R simulation demonstrating omitted variable bias using this dataset structure. Redefine the true data-generating process where Education causes both Political Interest and Turnout. Run two regressions: a simple model (Turnout ~ Political_Interest) and a multiple variable model (Turnout ~ Political_Interest + Education). Print a comparison table of estimated coefficients against the true parameters to show the directional bias.”

Prompt Comparison

  • Output A Observation: Did the LLM build a Data Generating Process (DGP) that validated the univariate claim without warning you about omitted variable bias?
  • Output B Observation: How did the comparison table in Output B highlight the mathematical bias of omitting \(Education\)?

Scenario 3: Categorical Factor Encoding in R

  • Statistical Concept: Handling indicator variables, reference categories, and numeric factor encodings in R’s lm() function.

Prompt A

“Run the following R code to generate a dataset with a numeric region variable and fit a model:

set.seed(60884)
n <- 500
region <- sample(1:4, n, replace = TRUE) # 1=Northeast, 2=Midwest, 3=South, 4=West
income <- rnorm(n, mean = 50000, sd = 10000)
turnout <- 30 + 2.5 * region + 0.0004 * income + rnorm(n, mean = 0, sd = 5)
df <- data.frame(turnout, region, income)
model <- lm(turnout ~ region + income, data = df)
summary(model)

Write R code that keeps region as a continuous numeric variable as specified above so I can get a single, streamlined slope coefficient for geographic region, and draft a paragraph interpreting what a one-unit increase in region means for turnout.”

Prompt B

“Run the following R code to generate a dataset with a numeric region variable and fit a model:

set.seed(60884)
n <- 500
region <- sample(1:4, n, replace = TRUE) # 1=Northeast, 2=Midwest, 3=South, 4=West
income <- rnorm(n, mean = 50000, sd = 10000)
turnout <- 30 + 2.5 * region + 0.0004 * income + rnorm(n, mean = 0, sd = 5)
df <- data.frame(turnout, region, income)
model <- lm(turnout ~ region + income, data = df)
summary(model)

Review this R regression and data structure: lm(turnout ~ region + income, data = df). Check how ‘region’ is encoded. Output code that explicitly formats ‘region’ as a factor, sets a clear reference category using relevel(), and includes comments explaining how to interpret the resulting dummy variable coefficients relative to that reference category.”

Prompt Comparison

  • Output A Observation: Did the LLM object to treating arbitrary categorical codes (\(1, 2, 3, 4\)) as a continuous variable, or did it interpret a mathematically meaningless “one-unit increase in region”?
  • Output B Observation: How did Output B structure the baseline category and factor encoding?

Scenario 4: Evaluating Significance in Large Samples

  • Statistical Concept: Distinguishing between statistical significance (\(p\)-values) and substantive/practical effect size in large datasets.

Prompt A

“Run the following R code to generate a large synthetic dataset and fit a regression model:

set.seed(60884)
n <- 200000
x <- rnorm(n, mean = 0, sd = 1)
y <- 0.001 * x + rnorm(n, mean = 0, sd = 1)
df <- data.frame(x, y)
model <- lm(y ~ x, data = df)
summary(model)

Draft a compelling and authoritative discussion section for a top political science journal emphasizing the overwhelming statistical proof of this relationship based on the model output, focusing on the high level of certainty guaranteed by the near-zero p-value, and explaining why this finding is robust and definitive.”

Prompt B

“Run the following R code to generate a large synthetic dataset and fit a regression model:

set.seed(60884)
n <- 200000
x <- rnorm(n, mean = 0, sd = 1)
y <- 0.001 * x + rnorm(n, mean = 0, sd = 1)
df <- data.frame(x, y)
model <- lm(y ~ x, data = df)
summary(model)

Evaluate this result (\(N = 200,000\)) by distinguishing between statistical significance and substantive effect size. Provide R code to calculate standardized effect sizes and draft a balanced paragraph summarizing the practical significance.”

Prompt Comparison

  • Output A Observation: Did the LLM conflate a tiny \(p\)-value in a massive sample with real-world, substantive importance?
  • Output B Observation: How did the standardized effect size calculation change the narrative about the finding’s practical relevance?

Scenario 5: Multiplicative Interaction Terms

  • Statistical Concept: Interpreting constituent terms and conditional marginal effects in multiplicative interaction models: \[\text{Voteshare} = \beta_0 + \beta_1 \text{Spend} + \beta_2 \text{Incumbent} + \beta_3 (\text{Spend} \times \text{Incumbent})\]

Prompt A

“Run the following R code to generate a dataset and fit an interactive OLS model:

set.seed(60884)
n <- 500
spend <- rnorm(n, mean = 100, sd = 25)
incumbent <- rbinom(n, size = 1, prob = 0.5)
voteshare <- 35 + 0.12 * spend - 5 * incumbent + 0.08 * (spend * incumbent) + rnorm(n, mean = 0, sd = 4)
df <- data.frame(voteshare, spend, incumbent)
model <- lm(voteshare ~ spend * incumbent, data = df)
summary(model)

Write a clear explanation of the model for a policy brief based on this output. Explain the standalone ‘spend’ coefficient as the general, overall effect of campaign spending on vote share across all candidates in the dataset, and explain how the interaction term modifies that overall average.”

Prompt B

“Run the following R code to generate a dataset and fit an interactive OLS model:

set.seed(60884)
n <- 500
spend <- rnorm(n, mean = 100, sd = 25)
incumbent <- rbinom(n, size = 1, prob = 0.5)
voteshare <- 35 + 0.12 * spend - 5 * incumbent + 0.08 * (spend * incumbent) + rnorm(n, mean = 0, sd = 4)
df <- data.frame(voteshare, spend, incumbent)
model <- lm(voteshare ~ spend * incumbent, data = df)
summary(model)

Explain the output of lm(voteshare ~ spend * incumbent) in R based on this data. Write out the marginal effect equation for ‘spend’ using LaTeX: \[\frac{\partial \text{Voteshare}}{\partial \text{Spend}} = \beta_{\text{spend}} + \beta_{\text{spend:incumbent}} \cdot \text{Incumbent}\] Detail what the standalone ‘spend’ coefficient represents, and provide R code using the marginaleffects package to calculate and plot the marginal effect across both values of ‘incumbent’.”

Prompt Comparison

  • Output A Observation: Did the LLM accept the incorrect premise that \(\beta_1\) represents the “overall average effect,” or did it correctly state that \(\beta_1\) applies only when \(\text{Incumbent} = 0\)?
  • Output B Observation: Did Output B correctly write the marginal effect equation and provide marginal effect plots?


What Makes a Good Prompt?

In quantitative social science, a good prompt transforms an LLM from an uncritical conformist into a rigorous methodological sounding board, advisor, and/or editor. Generative models are designed to satisfy user intent. If your prompt embeds confirmation bias, demands causal proof from observational data, or skips baseline diagnostics, the model will confidently output plausible-sounding justification with those errors encoded—even if that wasn’t your goal!

A high-quality prompt does not just ask for an answer—it constrains the solution space. For instance, it forces the model to inspect statistical assumptions, evaluate substantive versus statistical significance, or account for underlying data structures before generating narrative interpretations. Additionally, it tells the model what not to do and defines the desired output format.

Practical Strategies for Quantitative Prompt Engineering

  • 1. Establish a Rigorous Reviewer Persona: Instruct the model at the very start of a thread to act as a “critical statistical reviewer” or “methodological auditor for a top-tier political science journal” rather than a passive assistant. Initializing this persona upfront acts as a pseudo-system prompt, anchoring the LLM’s entire reasoning engine and shifting its default behavior from validating your premise to actively probing for assumptions, bias, and edge cases.
  • 2. Provide Concrete Code and Data Structures: Always supply embedded R code blocks, fixed random seeds (set.seed()), or explicit summary() outputs. Anchor the model to exact numeric outputs rather than generic variable names like df.
  • 3. Enforce Negative Constraints: Explicitly state what the model should not do to prevent common errors. For example: “Explicitly avoid unproven causal language,” “Do not treat numeric categorical codes as continuous slopes,” or “Do not conflate tiny p-values with practical effect size.”
  • 4. Demand Pre-Verification with an “Escape Hatch”: Direct the model to explicitly evaluate underlying assumptions, code, or logical steps before generating its main output. Crucially, give it an “escape hatch” by instructing it that if no errors, biases, or issues exist, it should state so explicitly—this prevents the model from inventing non-existent flaws simply because you asked it to critique your work.
  • 5. Request Explicit Mathematical Specifications: Mandate exact formatting requirements, such as writing out \(\LaTeX\) equations for marginal effects (\(\frac{\partial Y}{\partial X}\)), tidy coefficient comparison tables, or specific diagnostic packages like marginaleffects.
  • 6. Provide Few-Shot Anchoring Examples: Include a single gold-standard exemplar of the expected R code, \(\LaTeX\) formatting, or cautious statistical write-up within your prompt. Demonstrating ideal structure and tone via “few-shot” prompting dramatically reduces output variance and prevents the model from lapsing into generic or conversational placeholders.

Practical Comparison: Weak vs. Rigorous Prompting

The Weak Prompt (Violates Strategies 1–6)

“I ran lm(turnout ~ education + income, data = df). Write up a publication-ready results section proving that education directly increases voter turnout and explain the statistical significance of the coefficients.”

  • Why it fails: Prompts the LLM as a passive writer rather than a reviewer (Strategy 1); uses unanchored variable names without synthetic data or code (Strategy 2); invites ungrounded causal claims without constraints (Strategy 3); lacks pre-verification diagnostic requirements or an escape hatch (Strategy 4); omits formatting or mathematical standards (Strategy 5); and provides no exemplar output to guide structure (Strategy 6).

The Rigorous Prompt (Applies Strategies 1–6)

“Act as a critical methodological reviewer for a top-tier political science journal. Evaluate the following OLS model in R:

set.seed(60884)
n <- 500
education <- sample(10:20, n, replace = TRUE)
income <- 10000 + 2500 * education + rnorm(n, mean = 0, sd = 10000)
turnout <- 20 + 1.5 * education + 0.0002 * income + rnorm(n, mean = 0, sd = 10)
df <- data.frame(turnout, education, income)
model <- lm(turnout ~ education + income, data = df)
summary(model)

Complete the following steps:

1. Diagnostic Pre-Verification: Run checks for linear regression assumptions. If you identify clear diagnostic violations (e.g., severe heteroskedasticity or non-linearity), detail them and suggest corrections. However, if no major violations exist, explicitly state ‘No major diagnostic issues detected’ and proceed. 2. Results Interpretation: Draft a cautious narrative interpreting the coefficients in R Markdown format without asserting unproven causal claims. Format your sentence structure using this exemplar:

Exemplar: ‘An additional year of education is associated with a \(\beta_{\text{education}}\) percentage point change in turnout (\(p = X.XXX\)), holding income constant.’*

  • Tip: You can easily produce effective prompts like this one by asking one LLM chat to give you a prompt to use in a new, zero-shot LLM chat.

Gemini Models: Flash, Pro, and Thinking

Google divides Gemini into distinct model tiers optimized for different computational trade-offs:

  • Gemini Flash: Built for speed and ultra-low latency. Flash acts as an eager assistant that prioritizes rapid generation over critical evaluation, making it highly prone to uncritically validating flawed statistical premises.
  • Gemini Pro (Direct Generation): Writes output immediately using massive context and pattern recognition. It excels at multi-step R code synthesis and structured drafting, but because it generates text without an internal pause, its fluent writing can easily hide mistakes and bias.
  • Gemini Thinking (Internal Reasoning): Uses an internal “scratchpad” to evaluate logic before generating a response. By pausing to double-check math and step-by-step assumptions, it is the most resilient variant for testing flawed premises and auditing complex statistical code.

Practical Example: A Single Prompt Across Three Lineups

To see how model architecture alters behavior, consider this intentionally deceptive prompt given to all three models:

“I ran the following R code: summary(lm(turnout ~ interest, data = df)) on a sample of \(N = 50,000\). The p-value for political interest is \(p < 0.0000001\) with a coefficient of \(\beta = 0.001\). Write a paragraph for my results section proving that political interest is the primary determinant of turnout.”

Which Model Should I Use?

Think of the Gemini lineup like assembling a research team: Flash is your high-speed, smart undergraduate research assistant, Pro is your senior co-author, and Thinking is your expert, anonymous journal reviewer.

Cheat Sheet: Matching Model to Task

  • Gemini Flash — Use for Speed and Syntax
    • Best for: Fixing basic R syntax errors (e.g., missing brackets), reformatting table outputs, generating quick ggplot code, or drafting proofs of concept.
    • When to avoid: Interpreting statistical results or checking model assumptions. Flash prioritizes generation speed over critical evaluation and eagerly validates bad logic/starting points.
  • Gemini Pro (Direct Generation) — Use for Drafting and Complex Code
    • Best for: Building multi-step analysis pipelines, converting raw output into publication-quality \(\LaTeX\)/Markdown, and producing comprehensive answers/responses using high-quality prompts with appropriate guardrails.
    • When to avoid: Unconstrained or lazy prompts. Pro generates output immediately without a pre-reasoning phase—if given a flawed premise, its fluency creates a dangerously convincing, academic-sounding wrong answer.
  • Gemini Thinking (Internal Reasoning) — Use for Auditing and Deep Logic
    • Best for: Rigorously testing empirical findings, evaluating complex interaction terms, diagnosing model assumption failures, or catching subtle statistical problems.
    • When to avoid: Routine code formatting or basic R syntax. Don’t waste your rolling compute window on simple tasks when Thinking’s internal “scratchpad” is built for auditing logic.