This tutorial follows the quantitative part of Methods of Social Research week by week, in the order of the lectures. Each section takes the logic of one lecture and turns it into a short, runnable analysis in DAX, the browser-based environment Luiss uses for this course. You type Stata-style commands; DAX translates them into R behind the scenes and returns formatted output.
Every section has the same structure:
The best way to use this page. Keep it open next to DAX. Copy one block, run it, and read the output before moving on. Do not run the whole section at once: the point is to understand each step, not to collect output. For the midterm, the sections on Weeks 5 and 6 are also a good way to practise reading DAX output.
use and the full web address. Nothing needs to be
uploaded:use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/worldcup_democracy.dta", clear
describe
DAX is not desktop Stata. It understands a large subset of Stata syntax, but not all of it, and a few commands behave differently. Everything on this page has been written to work in DAX. If you try other commands, check the DAX survival kit at the end first.
All datasets are in the course data repository and load with
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/<file>", clear.
You never need to download them.
| Week | File | What one row is |
|---|---|---|
| 1 | worldcup_democracy.dta |
a national team in one World Cup edition (537 rows) |
| 2 | chile1988.dta, turnout.dta |
a Chilean voter in 1988 (2,700); a US election (14) |
| 3 | vignettes.dta, battery.dta |
a respondent (vignettes, a Likert battery) |
| 3 | chile_samples.dta, afghan_village.dta |
one simulated sample (500); an Afghan village (1,864) |
| 4 | resume.dta, social.dta |
a fictitious CV (4,870); a Michigan voter (305,866) |
| 4 | minwage.dta, gini_polarization.dta |
a fast-food restaurant (358); a US Congress (33) |
| 5 | face.dta |
a US Senate race, 2000–2006 (119) |
| 5 | gss2021_lab.dta, ches2024_lab.dta |
the in-class lab (Lecture 5.2): a US adult; a European party |
| 5 | gss2021_marital.dta |
a US adult in the 2021 General Social Survey (3,624) |
| 6 | gss2021_lab.dta |
a US adult in the 2021 General Social Survey (3,500) |
| 6 | msr_survey.dta |
a student in our class survey (41) |
Science is a method, not a body of facts: a loop that runs from question to theory, hypotheses, observation and evaluation, and then back again. A hypothesis is useful only if it is falsifiable: you must be able to say in advance what evidence would count against it.
Our running question: does a country’s political regime affect its chances of playing in, and winning, the football World Cup? Two rival theories give opposite predictions. Sportswashing says autocracies invest more in sporting prestige (H1a: less democracy, more success). Democratic capacity says sustained success needs institutions that democracies build better (H1b: more democracy, more success).
Software enters only at step 4, and the reason is not speed: it is reproducibility. An analysis that cannot be re-run by someone else is an assertion, not a result.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/worldcup_democracy.dta", clear
describe
summarize goals polyarchy
tab1 year
tab1 winner finalist host
What you should see. 537 observations: one row is
one national team in one World Cup edition, 23 editions from 1930 to
2026. tab1 year shows 13 teams in 1930 and 48 in 2026.
Read it.
describe is always your first command. It tells you
what you actually opened.summarize, read the min and
max first: that is where coding errors hide.summarize polyarchy winner
* DAX draws one bar per distinct value: group polyarchy into bands of 0.05 first
generate poly_band = round(polyarchy * 20) / 20
histogram poly_band
tab1 winner
Read it. polyarchy (the V-Dem electoral
democracy index, 0 to 1) has two humps: many very
autocratic and many very democratic teams, fewer in between. The mean
hides this; the histogram shows it. For a 0/1 variable like
winner, the mean is the proportion of
ones: 23 champions out of 537 team-editions gives 0.043, so
4.3% of appearances end with the trophy. Rare outcomes are hard to
explain statistically.
A concept (democracy) becomes a variable through explicit decisions. Here we turn the Polity5 score (−10 to +10) into three regime types, using the conventional cut-offs:
recode polity2 (-10/-6 = 0) (-5/5 = 1) (6/10 = 2), generate(regime)
label define reglbl 0 "Autocracy" 1 "Anocracy" 2 "Democracy"
label values regime reglbl
tab1 regime
* every champion is also a finalist, so this gives 0 / 1 / 2
generate outcome = winner + finalist
tab2 winner finalist
Always check a variable you just built.
tab2 winner finalist confirms that outcome
means what you think it means. recode leaves missing values
missing, which is what you want. In DAX, build categories and dummies
with recode, never with comparisons such as
generate dem = (polity2 >= 6): the result is TRUE/FALSE
rather than 0/1, value labels do not apply, and in desktop Stata a
missing value would even count as larger than any number.
scatter polyarchy year
ttest polyarchy, by(winner)
ttest polyarchy, by(finalist)
tab2 regime winner, column
Read it.
scatter polyarchy year shows World Cup participants
becoming more democratic over time, but that is because the
world became more democratic. Two variables that both trend
over time will correlate, whether or not they are related. A
research-design problem appeared before any statistics.ttest prints the mean of each group
and then tests whether they differ by more than chance would produce.
Read the means first and the p-value second. Week 6 explains exactly
what the p-value means.Evaluation (step 5). H1a, the sportswashing prediction, finds no support. H1b survives, but only for reaching the final. A theory that survives a test is corroborated, not proved. And “not significant” does not mean “no effect”: it means the evidence is too thin to tell the groups apart.
polyarchy
and polity2) agree?polity2. Does the
conclusion change?ttest goals, by(host)
correlate polyarchy polity2
scatter polyarchy polity2
ttest polity2, by(finalist)
Hosts do score more, but hosts are not a random draw of countries
(they are richer and often strong football nations), and they play at
home. The two democracy measures correlate strongly (r = 0.93) but not
perfectly: every measure is a decision, and different decisions place
some countries differently. And the conclusion does
change: with polity2 the finalists are still more
democratic on average (5.89 vs 4.26), but the difference is no longer
statistically significant (p ≈ 0.12). A finding that depends on which
indicator you pick is a fragile finding.
A concept is a mental construct; it exists only if it draws a boundary between cases that are A and cases that are not-A. To study it empirically we go from concept → property of a unit of analysis → operational definition (the question, the coding rule, the unit of measurement) → variable.
The level of measurement decides which operations make sense:
| Level | Example | Legitimate operations |
|---|---|---|
| Nominal | vote intention | equal / different |
| Ordinal | education level | also greater / less than |
| Interval / ratio | age, income | also differences, means |
The software does not know the level of measurement of your variables. You do.
The chile1988 data come from a survey of 2,700 Chilean
adults interviewed a few months before the 1988 plebiscite on Pinochet’s
rule.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/chile1988.dta", clear
describe
tab1 vote
summarize vote
What you should see. tab1 vote: 889
respondents will vote No, 35.11% of the 2,532 valid answers.
summarize vote returns a mean of 2.844.
Read it.
tab1 computes
percentages on valid answers only: 168 are missing. Out
of all respondents, the No share is 889 / 2,700 = 32.9%. Always
ask: percent of what?vote is arithmetically correct and
substantively meaningless: vote is nominal (1 abstain,
2 No, 3 undecided, 4 Yes). A Yes voter is not “more” of anything than a
No voter.tab1 educ_raw
recode educ_raw (1=1) (3=2) (2=3), generate(educ)
label define edlbl 1 "Primary" 2 "Secondary" 3 "Post-secondary"
label values educ edlbl
tab2 educ_raw educ
tab1 educ
Read it. The original file coded education
alphabetically (Primary, Post-secondary, Secondary), so
post-secondary sat between the other two and the cumulative percentages
mixed apples and oranges. An ordinal variable is only ordinal if its
codes are in the right order. After the recode, 82.82% of respondents
have at most a secondary education: a cumulative percentage that finally
means something. tab2 educ_raw educ checks that every old
value lands in exactly one new value.
summarize income, detail
histogram income
recode age (18/29=1) (30/49=2) (50/70=3), generate(agegrp)
tab1 agegrp
* a dummy: 1 = woman (sex is coded 1 female, 2 male)
recode sex (1=1) (2=0), generate(female)
label define femlbl 0 "Man" 1 "Woman"
label values female femlbl
summarize female
What you should see. Income: mean 33,876, median
15,000. Age groups: 929, 1,103 and 667 respondents. female
has a mean of 0.511.
Read it.
recode copies the labels of the original variable onto
the new one. Without the new label define,
female = 1 would still read “Female” and
female = 0 would have no label at all: always define the
labels again.Observed value = true value + systematic error +
random error. turnout.dta compares the
turnout reported in the American National Election Studies (ANES) with
official turnout in 14 US elections.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/turnout.dta", clear
generate vep_rate = total / vep * 100
generate bias = anes - vep_rate
summarize bias
What you should see. bias: mean 16.84,
minimum 8.58, maximum 22.49.
Read it. The minimum is positive: the survey overestimates turnout in all 14 elections. The error is systematic, not random. The instrument is reliable (stable) but not valid (stably wrong in the same direction). Repeating the survey would never reveal this, because the bias is reproduced every time. The usual suspects are social desirability and non-response.
In chile1988.dta, statusquo is an index of
support for the regime. If it is a valid measure, people who say they
will vote Yes (for Pinochet) should score much higher than people who
will vote No. This is known-groups validity.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/chile1988.dta", clear
by vote: summarize statusquo
No voters average about −0.91 and Yes voters about +0.94. The measure separates the known groups very clearly. But both measures come from the same survey: if fear biased both answers in the same way, they would agree with each other and both be wrong.
A survey turns concepts into questions, answers into response categories, several answers into scales, and a few hundred respondents into statements about populations. Each step can go wrong in its own way.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/vignettes.dta", clear
describe
* how much say do YOU have in getting the government to address
* issues that interest you? (1 = no say at all ... 5 = unlimited say)
ttest self, by(china)
Read it. On the same 1–5 scale, Chinese respondents report more political say (2.62) than Mexican respondents (1.83), in a year when Mexico had just had its first change of governing party in 71 years and China had no competitive elections. Either Chinese citizens really have more say, or the categories mean something different in Beijing and in Mexico City. Anchoring vignettes exist to tell these two stories apart.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/battery.dta", clear
summarize a1 a2 a3 a4 a5
correlate a1 a2 a3 a4 a5
What you should see. 2,709 respondents. Items a2–a5 have means between 4.55 and 4.80 and correlate positively with each other (0.31 to 0.51). Item a1 has a mean of 2.41 and correlates negatively with all the others.
Read it. a1 (“Am indifferent to the feelings of others”) measures the same trait in the opposite direction. It has to be reversed before the items are added up: reversed = (min + max) − original = 7 − a1.
generate a1r = 7 - a1
tab2 a1 a1r
correlate a1r a2 a3 a4 a5
alpha a1r a2 a3 a4 a5
generate agree = a1r + a2 + a3 + a4 + a5
summarize agree, detail
histogram agree
What you should see. After reversing, all ten
correlations are positive, with a mean of 0.33. alpha gives
about 0.70. The scale runs from 5 to 30, with mean 23.2
and median 24.
Read it. Cronbach’s alpha is about 0.70, right at the conventional threshold: the five items hang together, but not strongly. (By hand, from the average correlation: α = n·r̄ / [1 + r̄(n − 1)] = 5 × 0.3325 / (1 + 0.3325 × 4) = 0.714, the standardised version of the same idea.) The mean (23.2) below the median (24) signals a long left tail: most people describe themselves as agreeable, a few do not (social desirability may help). Remember that alpha measures reliability: it says nothing about validity or unidimensionality.
chile_samples.dta contains 500 random
samples drawn from the same 2,531 Chilean voters, at three
sample sizes. In that population the true share of No voters is
35.12%.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/chile_samples.dta", clear
* DAX shows two decimals: express the estimates in percentage points first
generate pp50 = pno50 * 100
generate pp200 = pno200 * 100
generate pp1000 = pno1000 * 100
summarize pp50 pp200 pp1000
* round to whole points to draw the histograms
generate pct50 = round(pp50)
generate pct1000 = round(pp1000)
histogram pct50
histogram pct1000
What you should see (in percentage points).
| Sample size | Mean of the 500 estimates | Std. dev. (= sampling error) | Min | Max |
|---|---|---|---|---|
| 50 | 35.10 | 6.67 | 16.0 | 56.0 |
| 200 | 35.26 | 3.24 | 27.0 | 46.0 |
| 1,000 | 35.01 | 1.21 | 31.8 | 40.5 |
Read it. All three averages land on the true 35.1%: random sampling is unbiased. What changes with n is the spread: 6.7, then 3.2, then 1.2 points. One sample of 50 said 16%, another 56%. Every single sample is a little wrong; larger samples are wrong by less. The spread of the estimates across samples has a name, the standard error, and it comes back in Week 6.
Size does not fix bias. In 1936 the Literary Digest collected 2.4 million answers and missed Roosevelt’s landslide by about 20 points: its sampling frame (telephone directories, car registrations) and its 24% response rate selected wealthier, better-educated respondents. Twice the ballots would have reproduced the same bias twice as precisely.
There is no list of Afghan civilians. A survey in a war zone
therefore samples in stages: districts, then villages, then households
(multistage cluster sampling).
afghan_village.dta lists 1,864 villages and whether each
one was surveyed.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/afghan_village.dta", clear
tab1 surveyed
ttest altitude, by(surveyed)
generate logpop = log(population)
ttest logpop, by(surveyed)
What you should see. 204 of the 1,864 villages were surveyed. Mean altitude: 1,544 metres in both groups (p = 0.99). Log population: 6.05 vs 6.08 (p = 0.72).
Read it. On what we can observe, the surveyed villages look like the others: a sign that the selection of clusters did not favour easy, low-lying or large villages. We can only check what is in the list; unobserved differences (insecurity, access) may remain. Population is logged because a few very large villages would dominate the mean.
chile_samples.dta also contains the mean
age in each sample (age50,
age200, age1000). Does the spread of the
estimates shrink in the same way as for the No share?
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/chile_samples.dta", clear
summarize age50 age200 age1000
The standard deviations are 2.03, 1.03 and 0.36 years: the same pattern. Larger samples give estimates that scatter less around the true mean age. (Going further, optional: the standard error of a mean is about s/√n, where s = 14.76 is the standard deviation of age in the population. That gives 2.09 and 1.04 for the first two sizes; with 1,000 people out of 2,531 the sample is a large share of the population, so the spread is smaller still.)
Saying that X causes Y says more than “X and Y go together”. It says that changing X would change Y. Empirically we need three things: covariation, the right causal direction, and control of other causes. The third is the hard one.
Every unit has two potential outcomes: what happens with the treatment, Y(1), and without it, Y(0). We only ever observe one of them; the other is the counterfactual. Random assignment solves the problem on average: if units are assigned to treatment by chance, the two groups are equal on everything, measured or not, and the difference in mean outcomes estimates the average causal effect.
Bertrand and Mullainathan (2004) sent about 5,000 fictitious CVs in response to real job ads in Boston and Chicago. The first name on each CV was randomly assigned: stereotypically African-American or stereotypically white. The outcome: did the employer call back?
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/resume.dta", clear
describe
tab1 black
tab2 black call, row
ttest call, by(black)
What you should see. White names: 235 callbacks out
of 2,435 CVs (9.65%). Black names: 157 out of 2,435
(6.45%). In ttest: means 0.0965 and
0.0645, t ≈ 4.11, p < 0.001.
Read it.
ttest
compares two callback rates.* 0 = white man, 1 = Black man, 2 = white woman, 3 = Black woman
generate group = black + 2*female
label define grouplab 0 "white man" 1 "Black man" 2 "white woman" 3 "Black woman"
label values group grouplab
tab2 group call, row
Read it. Women: 9.89% vs 6.63% (3.3 points). Men: 8.87% vs 5.83% (3.0 points). Discrimination is almost identical for both sexes. But only 1,124 CVs carry a male name against 3,746 female ones: smaller subgroups mean less precise estimates.
Gerber, Green and Larimer (2008) randomly assigned 305,866 Michigan voters to four groups before the August 2006 primary: no letter (control), a Civic Duty letter, a Hawthorne letter (“you are being studied”), and a Neighbors letter listing the household’s and its neighbours’ past turnout.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/social.dta", clear
tab1 message
tab2 message primary2006, row
What you should see. Turnout: Control 29.7%, Civic Duty 31.5%, Hawthorne 32.2%, Neighbors 37.8%.
Read it. Being reminded of a duty: +1.8 points. Being watched: +2.6. Being watched by your neighbours: +8.1 points, from a single letter.
by message: summarize primary2004 yearofbirth hhsize
Read it. In all four groups the share who voted in 2004 is 0.40 or 0.41, the mean year of birth is between 1956.15 and 1956.34, and the mean household size is 2.18 or 2.19. The groups were balanced before the letters were sent. We check only pre-treatment variables: a letter sent in 2006 cannot change the past, while anything measured afterwards could be an effect of the letter.
In resume.dta, which of the four sex × race groups is
called back least? In social.dta, why would it make no
sense to add primary2006 to the balance check?
Black men are called back least (5.83%). primary2006 is
the outcome: differences in it are what we want to
explain, not a check on whether the groups were comparable
beforehand.
Most causes we care about (a law, a religion, a regime) cannot be assigned at random. In an observational study the researcher observes who is exposed to X; nobody assigns it. Realism improves, but internal validity is no longer guaranteed: it must be argued. Every comparison builds a counterfactual on an assumption, so name the assumption.
In April 1992 New Jersey raised its minimum wage from $4.25 to $5.05; neighbouring Pennsylvania did not. Card and Krueger (1994) surveyed fast-food restaurants on both sides of the border before (February) and after (November) the increase. Nobody assigned the law at random: the New Jersey legislature decided it.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/minwage.dta", clear
describe
tab1 nj
by nj: summarize wageBefore wageAfter
What you should see. 291 restaurants in New Jersey, 67 in Pennsylvania. Average starting wage in New Jersey: $4.61 before, $5.08 after. In Pennsylvania: $4.65 before, $4.61 after.
The law did change wages in New Jersey. Did it reduce jobs? Economic theory predicts that employers would shift from full-time to part-time workers. Compute the share of full-time employees:
generate fullshare_before = fullBefore / (fullBefore + partBefore)
generate fullshare_after = fullAfter / (fullAfter + partAfter)
by nj: summarize fullshare_before fullshare_after
* comparison 1: New Jersey vs Pennsylvania, after the law
ttest fullshare_after, by(nj)
What you should see. Full-time share after the law:
0.27 in Pennsylvania, 0.32 in New Jersey (ttest: means
0.2723 and 0.3204, t ≈ −1.43, p ≈ 0.16). In New Jersey before the law:
0.30.
Read it. Two different counterfactuals:
Neither comparison suggests that the higher minimum wage destroyed full-time jobs. Neither is as clean as a randomised experiment, and the cross-section difference is not statistically significant.
tab2 chain nj, column
Read it. Burger King is 46% of Pennsylvania restaurants and 41% of New Jersey ones; KFC is 15% and 22%. The groups are similar but not identical on what we can observe, and we cannot check what we do not observe. This is the price of not randomising.
For two categorical variables we use a contingency
table (tab2), with percentages computed within the
categories of the independent variable. For two interval variables we
use a scatterplot and the correlation
coefficient r, which runs from −1 to +1 and measures
how closely the points cluster around a straight line.
gini_polarization.dta has one row per US Congress,
1948–2012: income inequality (the Gini coefficient) and polarization
(the distance between the median Republican and the median Democrat in
Congress, on the DW-NOMINATE ideological scale).
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/gini_polarization.dta", clear
scatter polarization gini
correlate gini polarization year
scatter polarization year
scatter gini year
What you should see. r(gini, polarization) = 0.94. But also r(polarization, year) = 0.94 and r(gini, year) = 0.87.
Read it. A correlation of 0.94 is very high. But both variables rise steadily over time, and two variables that trend together will correlate whether or not one causes the other. This is the trap you met in Week 1 with the World Cup. A strong correlation is the start of a causal argument, not its end.
Is the correlation between polarization and
gini the same in the first and in the second half of the
period? What would you conclude if it were much weaker within each
half?
correlate gini polarization if year < 1980
correlate gini polarization if year >= 1980
scatter polarization gini if year < 1980
scatter polarization gini if year >= 1980
Before 1980 (16 Congresses) the correlation is negative, about −0.68; from 1980 onwards (17 Congresses) it is about +0.97. The overall 0.94 is driven by the period in which both series climb together. A relationship that changes sign across periods is a warning that a third factor, here the passage of time and everything that changed with it, may be doing the work.
Correlation tells us how closely two variables move together. Regression tells us by how much Y is expected to change when X changes by one unit, and lets us predict Y from X:
Y = α + βX + ε
Ordinary least squares (OLS) chooses α and β so that the squared residuals are as small as possible.
Todorov et al. (2005) showed people the faces of the two main
candidates in US Senate races, for one second, and asked which one
looked more competent. They had no other information.
face.dta covers 119 races from 2000 to 2006.
d_comp is the share of participants who rated the
Democrat as more competent.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/face.dta", clear
describe
generate d_share = d_votes / (d_votes + r_votes)
generate r_share = r_votes / (d_votes + r_votes)
generate diff_share = d_share - r_share
summarize diff_share d_comp
Read it. diff_share is the Democrat’s
two-party margin: positive when the Democrat won, negative when the
Republican won. It ranges from −0.77 to +0.70, with a mean close to zero
(0.01).
scatter diff_share d_comp
correlate diff_share d_comp
regress diff_share d_comp
What you should see. r = 0.433. In
regress:
| Coefficient | (Std. error) | |
|---|---|---|
| d_comp | 0.660*** | (0.127) |
| Constant | −0.312*** | (0.066) |
Observations 119, R² = 0.187.
Read it.
d_comp = 0.The regression line is a prediction machine. With α = −0.312 and β = 0.660:
| d_comp | Predicted margin = −0.312 + 0.660 × d_comp |
|---|---|
| 0.3 | −0.114 (Republican ahead by 11 points) |
| 0.5 | +0.018 (almost a tie) |
| 0.7 | +0.150 (Democrat ahead by 15 points) |
generate pred = -0.312 + 0.660 * d_comp
generate resid = diff_share - pred
summarize pred resid
scatter resid d_comp
What you should see. The residuals average zero (that is how least squares works) and run from about −0.68 to +0.74.
Read it. The two biggest misses are Alaska 2002 (the Republican Stevens won by 77 points; the faces predicted a Republican lead of about 9) and Massachusetts 2000 (the Democrat Kennedy won by 70 points; the faces predicted a narrow Republican lead). Both were long-serving incumbents in safe states: everything the faces do not see ends up in the residual.
Prediction is not explanation. Competence ratings predict election results, but nobody randomised the faces. Incumbents, for example, may look more confident in their photographs and win more often for other reasons. A regression coefficient describes an association; whether it is a causal effect depends on the design, not on the software.
The in-class lab (Lecture 5.2) used the same
commands on two other files: gss2021_lab.dta (the 2021
General Social Survey) and ches2024_lab.dta (party
positions from the 2024 Chapel Hill Expert Survey). Both load with
use like every other dataset on this page.
d_comp as the
causal effect of looking competent? Name one confounder and say in which
direction it would bias the estimate.With more than one predictor, each coefficient is the expected change in Y for a one-unit change in that X, holding the other predictors constant:
Y = α + β₁X₁ + β₂X₂ + … + ε
A coefficient changes when we add a new predictor only if the new X is related both to the old X and to Y. A nominal predictor (marital status, sex) enters the model as a set of 0/1 dummies, one per category except a reference category. And R² tells us how much of the variation in Y the model accounts for.
gss2021_marital.dta has 3,624 respondents of the 2021
General Social Survey: polviews (1 extremely liberal … 7
extremely conservative), years of schooling (educ),
age, family income when they were 16 compared with others
(finrela, 1-5), sex and marital
status.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/gss2021_marital.dta", clear
describe
summarize polviews educ age finrela
tab1 polviews
regress polviews educ
regress polviews finrela
correlate polviews educ age finrela
What you should see. polviews: mean
3.95, standard deviation 1.54; about one respondent in three is in the
middle (4 = moderate). regress polviews educ: −0.089***
(0.009), constant 5.257, R² = 0.026.
regress polviews finrela: −0.107*** (0.026). The
correlation between finrela and educ is
0.36.
Read it. One more year of schooling goes with 0.09 points more liberal, on average. People from richer families also look more liberal. But richer families also give their children more schooling (r = 0.36): is it income or education? The simple regression cannot tell the two apart.
regress polviews educ age finrela
What you should see.
| Alone (simple regression) | With the other two | |
|---|---|---|
| educ | −0.089 | −0.088*** (0.010) |
| age | +0.014 | +0.014*** (0.001) |
| finrela | −0.107 | −0.017 (0.028) |
| Constant | 4.568*** (0.157) |
R² = 0.050.
Read it.
finrela drops almost to zero and
loses its stars: the simple coefficient was largely
education.educ does not move when we add
age, because age and education are almost unrelated here (r
= 0.01).Which controls? Control for variables that come before X and affect Y (confounders). Do not control for variables that are consequences of X, or another version of Y: you would remove part of what you want to measure.
tab1 marital
* wrong: treats 1 married ... 5 never married as equal steps
regress polviews marital
* right: one dummy per category, married (1) as the reference
regress polviews i.marital
What you should see.
regress polviews marital: −0.154***, a number with no
meaning. regress polviews i.marital: constant 4.114 (the
mean of married respondents); never married −0.654*** (0.062), divorced
−0.104 (0.071), widowed +0.137 (0.100), separated −0.031 (0.169). In DAX
the dummies are labelled like as.factor(marital)5.
Read it. marital is nominal: “never
married” (5) is not five times “married” (1). The first regression runs
anyway, because DAX does not know the level of measurement. With
i.marital, each coefficient is the difference from the
reference group: respondents who never married are, on average, 0.65
points more liberal than married ones. With k categories,
i. creates k − 1 dummies.
regress polviews educ age finrela i.sex i.marital
What you should see. Women −0.202*** (reference:
men); never married −0.599***; divorced −0.211**; educ
−0.090***; age +0.008***; finrela −0.065*;
constant 5.358. R² = 0.074.
Read it. Every coefficient depends on which other
predictors are in the model: “never married” goes from −0.654 to −0.599,
age from +0.014 to +0.008 (never-married respondents are
younger, so part of the age gap was marital status).
R² = 1 − (sum of squared residuals) / (total sum of squares): the share of the variation in Y the model accounts for, from 0 (no better than predicting the mean for everyone) to 1 (every point on the line). With one predictor, R² = r²: (−0.16)² ≈ 0.026 for education.
Here R² grows from 0.026 (education alone) to 0.050 (three predictors) to 0.074 (all of them). Political views are hard to predict from demographics: a low R² is normal in survey data, and it does not make the coefficients wrong. R² is about prediction, not about importance or causation.
Use the model of Block 4. Respondent C is a woman, 40 years old, 16
years of schooling, finrela = 3, never married. Respondent
D is a man with the same age, schooling and income, married. Predict
their polviews. Where does the difference come from?
D is in both reference groups (man, married), so all the dummies are
0: 5.358 − 0.090 × 16 + 0.008 × 40 − 0.065 × 3 = 4.04.
C has female = 1 and never married = 1: 4.04 − 0.202 − 0.599 =
3.24. Same age, education and income: the gap of 0.80
points is the sum of the two dummies, about half a standard deviation of
polviews.
A difference in a sample is not automatically a difference in the population: every sample is a little wrong (Week 3). A hypothesis test is a rule for deciding when a sample result is good evidence about the population, with a known risk of being wrong.
gss2021_lab.dta is the file of the in-class lab: 3,500
American adults from the 2021 General Social Survey, a probability
sample.
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/gss2021_lab.dta", clear
describe
by sex: summarize polviews
ttest polviews, by(sex)
What you should see. Men 4.06, women 3.87 on the 1-7
scale. In ttest: means 4.0573 (1 male) and 3.8741 (2
female), t = 3.4983 (3325), p = 0.0005.
Read it. DAX prints the two means, t with its degrees of freedom (Welch test: unequal variances allowed) and the two-sided p-value. It does not print the difference, the standard error or the confidence interval, so compute them yourself:
p = 0.0005 < 0.05: we reject H0. In the US adult population, women place themselves slightly to the left of men. “Slightly” matters: 0.18 points is 3% of the scale, and sex explains 0.4% of the variance in ideology.
ttest polviews = 4
What you should see. Mean 3.9563, test value 4, t = −1.6791 (3499), p = 0.0932.
Read it. p = 0.093 > 0.05: we fail to reject H0 (μ = 4). Have we shown that the mean is 4? No. The 95% interval, 3.956 ± 2 × 0.026, runs from 3.91 to 4.01: 4 is in it, but so is 3.92. Failing to reject is not proving. At α = 0.10 we would reject: thresholds are conventions, not laws of nature.
regress polviews attend
recode sex (1=0) (2=1), generate(female)
label define femlbl 0 "Man" 1 "Woman"
label values female femlbl
regress polviews female
What you should see.
regress polviews attend: 0.155*** (0.009), constant 3.520,
R² = 0.075. regress polviews female: −0.183*** (0.052),
constant 4.057, R² = 0.004.
Read it.
regress prints
the coefficient, the standard error in parentheses and stars: * p <
0.05, ** p < 0.01, *** p < 0.001, no star p ≥ 0.05. It prints
neither t nor the exact p, so compute t by hand: 0.155 / 0.009 ≈
17.regress polviews age
generate age10 = age / 10
regress polviews age10
What you should see. age: 0.014***
(0.001). age10: 0.141*** (0.015).
Read it. From the first output, t by hand would be 0.014 / 0.001 = 14; the true t is 9.4. DAX rounds to three decimals, and a standard error of 0.0015 is printed as 0.001. Rescale the variable (decades instead of years) so that coefficients and standard errors have at least two significant digits. The test does not change; the units do.
What a p-value is not.
cappun: 1 favor, 2 oppose) differ in ideology? Do
supporters and opponents of gun permits (gunlaw) differ in
religious attendance?ttest polviews, by(cappun)
ttest attend, by(gunlaw)
Death penalty: 4.44 vs 3.34, a difference of 1.09 points; t = 22.2, p printed as 0 (read: p < 0.0001). A large difference. Gun permits: 2.76 vs 2.95, a difference of −0.18; t = −1.82, p = 0.069. We fail to reject at 5%, but the interval (about −0.38 to 0.01) is compatible both with no difference and with a small one.
“In the 2021 GSS (n = 3,500), supporters of the death penalty placed themselves 1.09 points to the right of opponents on the 7-point scale (95% CI about 1.0 to 1.2; Welch t = 22.2, p < 0.001). It is a descriptive difference: opinions on the death penalty were not assigned at random.”
The whole cycle of the course in one study, with our own data. Question: do students who listen to rap and trap explain success and inequality differently, and can the story told in a song change how they explain them? The class survey contains two designs:
The hypotheses were written before the data were collected: H1, rap listening is associated with how students explain success; H2, right-wing students explain success more individually and support redistribution less; H3, the H1 association shrinks once ideology, gender and country are held constant (selection); H4, the primary hypothesis of the experiment, reading the self-made version leads to more individual explanations.
msr_survey.dta has the anonymous answers of the 41
students analysed (42 questionnaires, 1 excluded for failing the
attention check).
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/msr_survey.dta", clear
describe
tab1 g_rap
tab1 selfmade
summarize lr
tab1 italy
What you should see. 10 of 41 students (24%) listen to rap or trap “often” or “very often”. 18 read version A, 23 version B. Left-right: mean 3.1 on 0-10 (n = 40, one “don’t know”). 22 of 41 grew up in Italy.
generate indiv = imp_work + imp_ambition + imp_talent
generate struct = imp_family + imp_people + imp_place
generate attrib = indiv - struct
summarize attrib
alpha imp_work imp_ambition imp_talent
alpha imp_family imp_people imp_place
correlate merit birth
recode g_rap (1/3 = 0) (4/5 = 1), generate(rapfan)
label define fan_l 0 "Less often" 1 "Often or very often"
label values rapfan fan_l
tab1 rapfan
What you should see. attrib (individual
minus structural causes, −12 to +12): mean −0.59, standard deviation
2.9. Alpha: 0.70 for the individual items, 0.55 for the structural ones.
merit and birth: r = −0.43.
Read it. On average the class explains success
slightly more by structure than by individual effort. The two sub-scales
are weak (Week 3): three items each, not designed as a scale.
merit and birth correlate negatively because
they point in opposite directions: birth must be reversed
(6 − birth) before adding them. And remember: recode copies
the old labels, so rapfan needs new ones.
ttest attrib, by(rapfan)
regress attrib g_rap
regress attrib lr
regress redist lr
regress attrib g_rap lr female italy
What you should see.
| Test | Estimate (SE) | Verdict |
|---|---|---|
H1 · ttest attrib, by(rapfan) |
−0.55 (others) vs −0.70 (fans); t = 0.12, p = 0.91 | not supported |
H1 · regress attrib g_rap |
−0.201 (0.417), n = 41 | not supported |
H2 · regress attrib lr |
+0.578* (0.275), n = 40 | supported |
H2 · regress redist lr |
−0.303** (0.087), R² = 0.24 | supported |
H3 · g_rap with lr female italy |
−0.302 (0.365); italy −2.464** (0.827), n = 40 |
nothing to explain away |
Read it. Read in this order: sign, size,
uncertainty, test. Rap listening is not associated with explanations of
success, but with only 10 fans the interval for g_rap
(about −1.0 to +0.6) is compatible with both rival stories. Ideology
matters: one point to the right goes with 0.58 points more individual
explanations, and from 2 to 6 on the left-right scale support for
redistribution falls by about 1.2 points (1-5). The surprise, not
predicted, is italy: students who grew up in Italy score
about 2.5 points more “structural”. Different people, or different
countries in their minds? A new hypothesis for another study, not a
finding.
* (a) balance: only variables measured before the song
ttest g_rap, by(selfmade)
ttest lr, by(selfmade)
tab2 selfmade italy, row
* (b) did the message get through?
tab2 selfmade manip, row
* (c) the effect on the primary outcome
ttest attrib, by(selfmade)
regress attrib selfmade
What you should see. Balance: rap listening 2.83 (B)
vs 2.72 (A), p = 0.77; left-right 2.64 vs 3.67, p = 0.056. Manipulation
check: 50% of A readers answer “own effort”, only 39% of B readers
“unfair conditions”; 18 of 41 recalled the message of their version.
Effect: B −0.78, A −0.33 (ttest: t = −0.50, p = 0.62);
regress attrib selfmade: 0.449 (0.937).
Read it.
attrib by +0.45 points (about 0.15 standard deviations), in
the predicted direction but far from significant. In ttest,
DAX subtracts group 1 from group 0 (B − A), so t is negative.Selection or persuasion? The survey alone cannot tell whether trap fans think differently because of the music or because of who chooses the music; the experiment alone cannot speak for real listeners. Together they narrow the range of explanations, if each part has enough power. Ours did not: few fans, a text instead of a song, one class.
Do students who grew up in Italy explain success differently from international students? Write one sentence with the five elements of Lecture 6.1. Is it an association or an effect?
ttest attrib, by(italy)
International students 0.63, students who grew up in Italy −1.64: a difference of 2.3 points, t = 2.62, p = 0.013. “In our class (n = 41), students who grew up in Italy scored 2.3 points lower (more structural) on the attribution index than international students (t = 2.62, p = 0.013). Where you grew up was not assigned at random, and the hypothesis was not written in advance: it is an exploratory association.”
If you want one script that touches the core of each week, start from this. Run it in the Script Editor, then go back to each section to interpret the output.
* Week 1 - a first test
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/worldcup_democracy.dta", clear
describe
summarize polyarchy winner
generate poly_band = round(polyarchy * 20) / 20
histogram poly_band
ttest polyarchy, by(finalist)
* Week 2 - levels of measurement
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/chile1988.dta", clear
tab1 vote
recode educ_raw (1=1) (3=2) (2=3), generate(educ)
tab2 educ_raw educ
summarize income, detail
* Week 3 - scales and samples
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/battery.dta", clear
generate a1r = 7 - a1
correlate a1r a2 a3 a4 a5
alpha a1r a2 a3 a4 a5
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/chile_samples.dta", clear
summarize pno50 pno200 pno1000
* Week 4 - experiments
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/resume.dta", clear
tab2 black call, row
ttest call, by(black)
* Week 4 - observational data and correlation
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/gini_polarization.dta", clear
correlate gini polarization year
* Week 5 - regression and prediction
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/face.dta", clear
generate diff_share = (d_votes - r_votes) / (d_votes + r_votes)
scatter diff_share d_comp
regress diff_share d_comp
* Week 5 - multiple regression and categorical predictors
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/gss2021_marital.dta", clear
regress polviews educ age finrela
regress polviews educ age finrela i.sex i.marital
* Week 6 - hypothesis tests
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/gss2021_lab.dta", clear
ttest polviews, by(sex)
regress polviews attend
* Week 6 - our class survey
use "https://raw.githubusercontent.com/francescovisconti/MSR-data/main/msr_survey.dta", clear
generate attrib = imp_work + imp_ambition + imp_talent - imp_family - imp_people - imp_place
regress redist lr
ttest attrib, by(selfmade)
DAX translates Stata-style commands into R. Most of what you need in this course works, but a few things do not, and some outputs look different from desktop Stata.
| Works | Notes |
|---|---|
use "https://…/file.dta", clear |
load data from a web address; only .dta or
.sav files |
describe, browse |
|
summarize x y z, summarize x, detail |
always list the variables; shows the median, not the full percentiles |
by g: summarize x |
summary statistics within groups |
tab1 x, tab2 x y, row column |
frequency and contingency tables |
generate |
arithmetic and functions: x / 10, a + b,
log(), round() |
recode x (…), generate(y) |
categories and dummies; copies the old labels, so define new ones |
label define, label values |
|
ttest y, by(g), ttest y = 4 |
Welch test; prints the two means, t (df) and the two-sided p only |
correlate x y z, scatter y x |
correlate … if and scatter … if work |
alpha x1 x2 x3 |
Cronbach’s alpha |
histogram x |
draws one bar per distinct value; for continuous variables, group them first (see below) |
regress y x1 x2, regress y i.g |
coefficient, (SE) and stars; i. creates one dummy per
category |
regress y a##b |
interactions without prefixes work; c. and
i. inside interactions do not |
eststo, esttab |
side-by-side models; stars differ: * p < 0.1, ** p < 0.05, *** p < 0.01 |
| Does not work (yet) | Do this instead |
|---|---|
generate … if … |
build the variable for everyone with recode,
e.g. recode x (1/2 = 0) (3 = 1) (4/5 = 0), generate(d) |
dummies with comparisons,
e.g. generate d = (x > 10) |
gives TRUE/FALSE and labels do not apply: use
recode |
recode x (… = .) (recoding to missing) |
compare groups with by g: summarize |
ttest … if …, regress … if … |
by g: summarize; or a dummy plus
ttest y, by(dummy) |
comparisons with text, e.g. (state == "PA") |
use the numeric version of the variable |
tabstat, codebook, collapse,
preserve, bysort, egen |
summarize, by g: summarize,
tab1 |
histogram x, bin(20) |
bin() is ignored: build bands with
generate xb = round(x * 10) / 10 |
round(x, 0.1) (rounding to a unit) |
round(x * 10) / 10 |
regress on very large datasets
(e.g. social.dta, 305,866 rows) |
fails with “offset is out of range”: use tab2 and
by g: summarize on large files |
drop if, keep if |
drop and keep work on variables only |
log, cd, pwd,
clear all |
not needed: load data from the web |
Reading DAX output.
summarize rounds to two decimals: if you need more
precision, rescale the variable first (e.g. multiply a proportion by
100).ttest y, by(g) computes group 0 − group
1 (the lower code minus the higher one): check which group is
which before you write the sign. It does not print the difference, the
standard error or the interval: difference = mean 1 − mean 2, SE =
difference / t, 95% CI ≈ difference ± 2 × SE. A p-value printed as
0 means p < 0.0001.regress prints neither t nor the exact p: t =
coefficient / SE, and the stars give the p (* < 0.05, ** < 0.01,
*** < 0.001). Coefficients are rounded to three decimals: if a
standard error reads 0.001 or 0.000, rescale the variable
(e.g. age / 10) before computing t by hand.i.x, the dummies are labelled like
as.factor(x)3: category 3 compared with the lowest
category.When a command fails, DAX shows an error from its R
engine and does not add the command to your history. Read the message,
check the table above, and simplify. If DAX starts returning odd errors
after a failed command, reload the data with
use …, clear.
The point of this part of the course is not to learn a software package. It is to learn how to move from a research question to a defensible empirical analysis. The commands are the easy part. The habits are what matter:
Textbooks
Studies used in the examples
Data sources
gss2021_lab and
gss2021_marital are teaching extracts (complete cases,
unweighted).resume, social,
minwage, face, vignettes,
turnout and afghan_village come from Imai
& Bougher (2021); gini_polarization is derived from
their congress and USGini files.
msr_survey is the anonymous class survey of MSR 2026/27,
with variables that could identify a student removed.