STATA TRAINING WORKSHOP
1. INTRODUCTION TO STATA
In Stata, the main windows you typically see (by default) are:
Command Window – where you type and submit commands.
Results Window – shows the output/results of your commands.
History Window – records and displays a list of previously entered commands.
Variables Window – lists all variables in the currently loaded dataset.
Properties Window – shows details about the dataset, variables, and other objects.
You can resize, move, or hide these windows depending on your workflow. Later, we'll also look
at the Data Editor, which opens in a separate tab so you can view or edit your dataset like a
spreadsheet.
1
How the display command outputs in the results window.
display "Hello everyone, my name is Mehdi"
display 5
display 5+2
display "5+2"
Set the current working directory to the specified folder location.
cd "\\[Link]\home\User064\mehdik\Documents\STATA workshop\data"
Load the sample auto dataset and clear any data already in memory.
sysuse auto, clear
OR:
webuse auto, clear
Note: Both commands load the same dataset auto. However, sysuse and webuse are
often used when working offline and working with Internet access, respectively.
The auto dataset is a built-in Stata sample dataset that contains information on 74
automobiles sold in the United States in 1978. The dataset includes both quantitative and
qualitative variables describing car characteristics such as price, mileage, engine size,
weight, length, and origin.
Key variables include:
price – the car’s price (in U.S. dollars)
mpg – miles per gallon (fuel efficiency)
weight – vehicle weight (in pounds)
length – vehicle length (in inches)
foreign – indicator for car origin (0 = domestic, 1 = foreign)
Overview of the dataset structure (describe), view the raw data in a spreadsheet format
(browse), and summarize variable details, including distribution and coding (codebook).
browse
describe
codebook
Open the Stata Do-file Editor to write, edit, and run commands.
doedit
2
Produce detailed summaries (sum, detail), frequency tables (tab), and cross-tabulations
of variables (tab).
sum price weight, detail
tab foreign
tab make
tab make foreign
Drop or keep variables (drop, keep), rename them (rename), and add descriptive labels
(label).
drop mpg
keep make price
rename price car_price
rename make make_price
label var car_price "Car Price in US dollars"
sysuse auto, clear
label list
Create a variable (gen, egen)
* create a continuous variable
gen price_thou = price/1000
replace price_thou = . if price_thou > 13
* create a dummy variable
gen expensive = 0
replace expensive = 1 if price > 10000
tab expensive
* create a summary variable
egen avg_price = mean(price)
egen max_price = max(price)
egen median_mpg = median(mpg)
Drop variables, generate group-wise summaries by category (by: egen), and create
indicators comparing values to group averages (gen).
drop avg_price max_price median_mpg
by foreign: egen avg_price = mean(price)
by foreign: egen max_price = max(price)
by foreign: egen median_mpg = median(mpg)
gen high_price=(price>avg_price)
gen high_mpg=(mpg>median_mpg)
3
Open the Stata help file for information on data types
help data type
clear
Manually enter data into Stata (input), view it in spreadsheet format (browse), and save
it (export)
input id str30 staffname
1 "Mehdi"
2 "John"
3 "Nguen"
end
browse
cd "\\[Link]\home\User064\mehdik\Documents\STATA workshop\data"
export excel using [Link], replace firstrow(variables)
Import and export datasets between Stata, Excel, CSV, and text formats.
sysuse auto, clear
browse
export excel using [Link], replace firstrow(variables)
import excel using [Link], clear firstrow
export delimited using [Link], replace
import delimited using [Link], clear
export delimited using [Link], replace
import delimited using [Link], clear
Exercise (10 mins)
Load the dataset: auto
Identify which variables are numeric and which are string
Create a variable for price in thousands
Drop all the variables except price and the variable you created
Export your dataset into Excel/CSV/TXT files
Import them back to STATA
4
List all or selected observations with conditions (list) and keep only a subset of the data
(keep).
Note:
_n and _N are system variables used by Stata to identify observation numbers within a
dataset.
_n refers to the current observation position (for example, _n == 1 is the first
observation, _n == 2 the second, and so on).
_N refers to the total number of observations in the dataset (for example, _N == 100 if
there are 100 observations).
sysuse auto, clear
list
list in 1/10
list in -10/l
list if price>5000
list if foreign==1
list if foreign==1 & price>5000
list if foreign==1 | price>5000
keep in 1/10
list
sysuse auto, clear
keep if _n<5 | _n>10
list if _n == _N
keep if _n > _N-5
list
Display the value of a variable for a specific observation (variable[index]).
display weight[5]
Sort data in ascending/descending order (sort, gsort) and compare groups using
summary statistics (by: sum) and mean tests (ttest).
sysuse auto, clear
browse
5
sort price
sort foreign price
gsort -price
gsort -foreign -price
gsort foreign -price
by foreign: sum price
ttest price, by(foreign)
Produce detailed descriptive statistics (sum, detail) and export formatted summary
tables to a CSV file (estpost/esttab).
sum price, detail
estpost sum price mpg rep78 weight length turn displacement gear_ratio, detail
esttab using [Link], replace cells("count mean(fmt(2)) sd(fmt(2)) p50(fmt(2))
p25(fmt(2)) p75(fmt(2)) min(fmt(2)) max(fmt(2))")
Correlation metrics
* Pearson
pwcorr price length turn displacement
asdoc pwcorr price length turn displacement, dec(3) setstars(***@.01, **@.05, *@.1)
star(all) title(Pearson correlations) reset replace
* Spearman
spearman price length turn displacement
asdoc spearman price length turn displacement, dec(3) setstars(***@.01, **@.05, *@.1)
star(all) title(Spearman correlations) reset replace
* reports both Pearson and Spearman
corr2docx price length turn displacement using [Link], replace star
How to install asdoc and corr2docx, if needed:
ssc install asdoc
ssc install corr2docx
Univariate tests
ttest price, by(foreign)
sum price if foreign==1, detail
6
sum price if foreign==0, detail
* OR
tabstat price, by(foreign) stat(median)
ranksum price, by(foreign)
asdoc ttest price, by(foreign) replace save(ttest_results.doc)
asdoc ranksum price, by(foreign) replace save(ttest_results.doc)
Cleaning workspace (resets Stata’s memory)
clear all
Cleaning the Results window
cls
Exercise (15 mins)
Import the auto dataset
Produce and compare the Pearson or Spearman correlation matrices, summary
(descriptive) statistics,
univariate analysis based on foreign vs. domestic, compare mean and median values;
export the results into Word/Excel; then copy and paste the tables into one Word file
2. VARIABLES
Create indicators & categories
cd "\\[Link]\home\User064\mehdik\Documents\STATA workshop\data"
webuse grunfeld, clear
browse
The Grunfeld dataset is a classic panel dataset that contains information on 10 U.S.
manufacturing companies observed over 20 years (1935–1954). The data shows the
relationship between a firm’s investment and its market value and capital stock.
Key variables include:
company – firm identifier (1–10)
year – observation year (1935–1954)
invest – firm’s gross investment (in millions of dollars)
mvalue – market value of the firm (in millions of dollars)
7
kstock – capital stock (in millions of dollars)
time – time variable (useful for panel setup)
gen hi_invest = (invest>200)
order hi_invest, last
tab hi_invest
gen invest_cat=0 if invest<=100
replace invest_cat=1 if invest>100 & invest<=200
replace invest_cat=2 if invest>200
order invest_cat, last
label define investlabel 0 "low" 1 "mid" 2 "high"
label values invest_cat investlabel
label list
gen sqrt_capital = sqrt(kstock)
gen invest_mvalue = invest / mvalue
gen invest_cap = invest * kstock
gen exp_capital = exp(kstock/1000)
help math functions
Exercise (10 mins)
Play with the commands: generate 5 new variables
using math functions not shown above (e.g., logit(), exp(), round(), mod(),
min(), max()). Create a new 3-level category for ‘mvalue’ variable with labels.
Create and manipulate text variables using string functions
clear
input id str50 firmname
1 "General Motors"
2 "US Steel"
3 "American Can"
4 "Allied Chemical"
5 "Union Carbide"
end
browse
gen nchar = length(firmname)
8
gen pos_space = strpos(firmname, " ")
gen first3 = substr(firmname, 1, 3)
gen before_sp = substr(firmname, 1, pos_space-1)
gen after_sp = substr(firmname, pos_space+1, .) /* The last parameter suggests the
number of characters to extract. Here, ‘.’ means “to the end of the string. */
gen proper = proper(firmname)
gen caps = upper(firmname)
gen lows = lower(firmname)
gen swapped = subinstr(firmname, " ", " of ", 1)
split firmname, p(" ") // Very useful command
gen firm_concat = firmname1 + firmname2
gen firm_titled = firmname1 + " of " + firmname2
gen fixed_all = subinstr(firmname, " ", "_", .) /* The last parameter suggests the number
of substitutions to make. Here, ‘.’ means all occurrences of the substring, not just the first
one. */
Exercise (10 mins)
Convert firmname to the format "Model of Manufacturer" style (e.g., "General Motors" →
"Motors of General").
keep names with one word unchanged.
Generate overall and running summaries
* Row means
webuse grunfeld, clear
egen invest_mean = mean(invest)
egen invest_sum = total(invest)
gen invest_runsum = sum(invest)
order invest_sum invest_runsum invest
gen avg3 = (invest + mvalue + kstock)/3
egen avg3_egen = rmean(invest mvalue kstock)
order invest mvalue kstock avg3 avg3_egen
* Group summaries by firm
sort company
by company: egen firm_mean_inv = mean(invest)
by company: egen firm_sd_inv = sd(invest)
9
by company: egen firm_min_inv = min(invest)
by company: egen firm_max_inv = max(invest)
Daily market data (S&P 500 dataset) with real date variable
sysuse sp500, clear
The SP500 dataset is a built-in Stata time-series dataset that contains daily stock market
data for the Standard & Poor’s 500 Index (S&P 500).
Key variables include:
date – trading date
open – opening price of the index
high – highest price of the day
low – lowest price of the day
close – closing price of the index
volume – trading volume (number of shares traded)
browse
describe date
list date close in 1/5
format date %td
Time-series data and generate lagged values
tsset date
gen d_close = [Link] // first difference of price
gen L1close = [Link] // 1-day lag
gen ret = (close - [Link]) / [Link]
label var ret "Daily simple return"
drop L1close d_close
Extract date components (dow, month, year) and create indicators such as weekdays
(inrange)
gen dow = dow(date) // 0=Sunday ... 6=Saturday
gen isweekday = inrange(dow,1,5)
gen month = month(date)
gen year = year(date)
Count trading days by month
by year month: egen n_trading = total(isweekday)
10
First/last trading day of each month
by year month (date): gen is_first = _n==1
by year month (date): gen is_last = _n==_N
help time_functions
Convert daily dates to monthly dates (mofd) and apply a monthly display format (%tm).
* mof returns the number of months elapsed since January 1960 (Stata's base date)
gen m = mofd(date)
format m %tm
Exercise (10 mins)
Keep the last close price in each month (end-of-month level) and calculate monthly
return.
Type conversion (numeric ↔ string)
webuse grunfeld, clear
browse
tostring time, replace
destring time, replace
3. DATA MANAGEMENT
Combine datasets by stacking observations with append.
cd "\\[Link]\home\User064\mehdik\Documents\STATA workshop"
webuse nlswork, clear
The NLSWORK dataset comes from the U.S. National Longitudinal Survey of Young
Women (NLSY). The data track the employment histories and earnings of young women
in the United States over several years.
Key variables include:
idcode – individual identifier (each woman)
year – survey year
11
age – respondent’s age
race – race of the respondent
union – 1 if the job is unionized, 0 otherwise
grade – years of education completed
hours – usual weekly working hours
wage – hourly wage rate
tenure – years with the current employer
describe
tab year
* Split the sample
keep if year <= 75
save nls1, replace
webuse nlswork, clear
keep if year > 75
save nls2, replace
* Append back
use nls1, clear
append using nls2
describe
Merge datasets by matching observations on key variables with merge
* 1) 1:1 (one to one)
webuse nlswork, clear
keep idcode year ln_wage
save master, replace
webuse nlswork, clear
keep idcode year hours
save master2, replace
use master1, clear
merge 1:1 idcode year using master2
* 2) 1:m (one to many)
webuse nlswork, clear
12
collapse (mean) ln_wage, by(year)
rename ln_wage avgln_wage
save avgwage, replace
webuse nlswork, clear
save panel, replace
use avgwage, clear
merge 1:m year using panel
order avgln_wage, last
drop _merge
* 3) m:1 (many to one)
webuse nlswork, clear
save panel, replace
collapse (mean) ln_wage, by(year)
rename ln_wage avgln_wage
save avgwage, replace
use panel, clear
merge m:1 year using avgwage
* 4) m:m (many to many): Not recommended!!!
clear
input str2 state str10 city byte city_id
"CA" "SanDiego" 1
"CA" "LosAngeles" 2
"NY" "NewYork" 3
"NY" "Buffalo" 4
end
save master_cities, replace
browse
clear
input str2 state str8 program byte prog_id
"CA" "ProgA" 10
"CA" "ProgB" 11
"NY" "ProgA" 12
"NY" "ProgC" 13
end
save using_programs, replace
13
use master_cities, clear
merge m:m state using using_programs /* the results depend on the sort order in both
datasets. */
list state city city_id program prog_id _merge, sepby(state) noobs
* correct way
use master_cities, clear
joinby state using using_programs
browse
How to remove duplicates
* Let's introduce duplicates
sysuse auto, clear
describe
count
save auto_orig, replace
append using auto_orig
describe
count
duplicates report
* 1) Drop exact duplicates (all variables identical)
duplicates drop
count
* 2) Remove duplicates by combination of keys (e.g., foreign and rep78)
duplicates report foreign rep78
* Option 1: keep one arbitrary row per (foreign, rep78) - Quick & dirty
duplicates drop foreign rep78, force // Fast, but you don't control which row is kept
within each (foreign, rep78)
browse
* Option 2: Keep one per combo based on a rule (recommended)
sysuse auto, clear
append using auto_orig
drop if missing(foreign, rep78)
14
bysort foreign rep78 (mpg): keep if _n==_N // e.g, Keep the highest mpg within each
(foreign, rep78)
browse
isid foreign rep78
* Option 3: Tag, review, then keep (transparent)
sysuse auto, clear
append using auto_orig
egen tag = tag(foreign rep78) // tag==1 on the first row of each combo
* Browse duplicates only:
list foreign rep78 if tag==0, sepby(foreign rep78)
keep if tag
drop tag
isid foreign rep78
browse
Exercise (10 mins)
Load the auto dataset, and save as cars.
Create a small "thresholds" file with MPG cutoffs by foreign (domestic = 0: 20, 25,
30; foreign = 1: 25, 30, 35) and save as badges.
Reopen cars and expand with joinby foreign using badges; flag eligibility with gen
qualifies = mpg >= threshold and keep only qualifying rows (keep if qualifies).
Finally, De-duplicate back to one row per car by keeping the highest threshold
met.
4. REGRESSIONS AND BASIC ECONOMETRICS
Winsorizing
cd "\\[Link]\home\User064\mehdik\Documents\STATA workshop\data"
webuse nlswork, clear
browse
sum ln_wage age hour, detail
winsor2 ln_wage age, cuts(1 99) replace
15
sum ln_wage age hour, detail
help winsor2 // 'trim' option
winsor2 ln_wage, cuts(1 99) replace trim
sum ln_wage age hour, detail
webuse nlswork, clear
winsor2 ln_wage age hour grade tenure, cuts(1 99) replace by(year)
Check for multicollinearity and heteroskedasticity
reg ln_wage age hour grade tenure msp ttl_exp
estat vif
estat hettest
Estimate OLS models and export formatted tables
help reg
reg ln_wage age hour grade tenure msp ttl_exp
How to install outreg2, if needed:
ssc install outreg2
outreg2 using [Link], replace
outreg2 using [Link], replace stats(coef tstat)
Add Adjusted R-squared
outreg2 using [Link], replace stats(coef tstat) e(r2_a)
Note: How to set the decimals for coeff and tstat
bdec: 3 decimals for coefficients
tdec: 2 decimals for t-stat
outreg2 using [Link], replace stats(coef tstat) e(r2_a) bdec(3) tdec(2)
Estimate OLS models (with and without fixed effects) and export formatted tables
16
reg ln_wage age hour grade tenure msp ttl_exp
outreg2 using [Link], replace stats(coef tstat) e(r2_a) bdec(3) tdec(2)
reg ln_wage age hour grade tenure msp ttl_exp
outreg2 using [Link], append stats(coef tstat) e(r2_a) bdec(3) tdec(2) keep (hour)
reg ln_wage age hour grade tenure msp ttl_exp [Link]
reg ln_wage age hour grade tenure msp ttl_exp [Link] i.ind_code
outreg2 using [Link], replace stats(coef tstat) e(r2_a) bdec(3) tdec(2) drop ([Link]
i.ind_code)
Estimate models with industry and year fixed effects using factor variables, areg
(absorb), and panel fixed effects via xtset/xtreg, fe.
webuse nlswork, clear
reg ln_wage age hour grade tenure msp ttl_exp i.ind_code [Link]
areg ln_wage age hour grade tenure msp ttl_exp [Link], absorb(ind_code)
xtset ind_code
xtreg ln_wage age hour grade tenure msp ttl_exp [Link], fe
Standard error clustered by year
reg ln_wage age hour grade tenure msp ttl_exp i.ind_code [Link], cluster(year)
Robust standard error
reg ln_wage age hour grade tenure msp ttl_exp i.ind_code [Link], robust
Note: How to install reghdfe
ssc install reghdfe
Regression using reghdfe
reghdfe ln_w age hour grade tenure msp ttl_exp, absorb(ind_code year)
Compare the coefficients on two variables
reg ln_wage age hour grade tenure msp ttl_exp [Link] i.ind_code
test age==hour
Run the regression within two subsamples and compare the coefficients
17
reg ln_wage age hour grade tenure msp ttl_exp [Link] i.ind_code if union==1
reg ln_wage age hour grade tenure msp ttl_exp [Link] i.ind_code if union==0
reg ln_wage age hour grade tenure msp ttl_exp [Link] i.ind_code if union==1
est store out1
reg ln_wage age hour grade tenure msp ttl_exp [Link] i.ind_code if union==0
est store out2
suest out1 out2
test [out1_mean]age=[out2_mean]age
Interaction term
gen age_union = age*union
reg ln_wage age union age_union hour grade tenure msp ttl_exp [Link] i.ind_code
* OR, you can run as below:
reg ln_wage [Link]##[Link] hour grade tenure msp ttl_exp [Link] i.ind_code
help regression
Logit regression
browse
sort year
by year: egen median_ln_wage = median(ln_wage)
gen high_salary=(ln_wage >= median_ln_w)
logit high_salary age hour grade tenure msp ttl_exp
margins, dydx(*) /* calculate the marginal effects */
probit high_salary age hour grade tenure msp ttl_exp
Poisson regression
poisson wks_ue age hour grade tenure msp ttl_exp [Link] i.ind_code
Tobit regression
tobit hour age grade tenure msp ttl_exp [Link] i.ind_code
18
Two-stage least squares regression
webuse nlswork, clear
reg ln_wage tenure union not_smsa
ivregress 2sls ln_wage (tenure = age south) union not_smsa, first
estat firststage
estat overid
Create Log files for future reference (Very important)
log using [Link], replace
reg ln_wage age hour grade tenure msp ttl_exp [Link] i.ind_code
test age==hour
log close
log using [Link], append
reg ln_wage age hour grade tenure msp ttl_exp [Link] i.ind_code if union==1
est store out1
reg ln_wage age hour grade tenure msp ttl_exp [Link] i.ind_code if union==0
est store out2
suest out1 out2
test [out1_mean]age=[out2_mean]age
log close
5. DATA VISUALISATION
Basic twoway plots
cd "\\[Link]\home\User064\mehdik\Documents\STATA workshop\data"
webuse nlsw88, clear
The NLSW88 is a cross-sectional dataset drawn from the U.S. National Longitudinal
Survey of Young Women (NLSY), focusing on data collected in 1988. It contains
information on wages, education, employment, occupation, industry, marital status, and
union membership for a sample of women in the labor force.
Key variables include:
19
wage – hourly wage (in U.S. dollars)
hours – usual weekly hours worked
ttl_exp – total years of work experience
grade – years of education completed
union – 1 if the job is unionized, 0 otherwise
south – 1 if living in the southern U.S., 0 otherwise
occupation / industry – job category and sector
race – race of the respondent
browse
describe wage grade tenure
Explore data visualization with twoway
help twoway
twoway scatter wage grade
twoway line wage grade
twoway lfit wage grade
Two-layer
twoway (scatter wage tenure) (lfit wage tenure)
Overlay three plottypes
twoway (scatter wage grade) ///
(line wage grade) ///
(lfit wage grade)
Save the graphs (STATA's native graph format and external image file)
sysuse uslifeexp, clear
The USLIFEEXP dataset is a simple time-series dataset that reports average life
expectancy in the United States from 1900 to 1999.
Key variables include:
year – calendar year (1900–1999)
le – average life expectancy (in years)
le_female – average life expectancy of all females in the U.S.
le_male – average life expectancy of all males in the U.S.
le_w – average life expectancy of all white Americans (both genders).
le_wfemale – average life expectancy of white females.
le_wmale – average life expectancy of white males.
20
le_b – average life expectancy of all Black Americans (both genders).
le_bfemale – average life expectancy of Black females.
le_bmale – average life expectancy of Black males.
browse
twoway scatter le year
graph save le_scatter.gph, replace
graph export le_scatter.png, replace as(png)
twoway line le year
graph save le_line.gph, replace
graph export le_line.png, replace as(png)
twoway lfit le year
graph save le_lfit.gph, replace
graph export le_lfit.png, replace as(png)
Combine .gph (graph) files
clear
graph combine le_scatter.gph le_line.gph le_lfit.gph
Combine by stored names (current session)
sysuse uslifeexp, clear
twoway scatter le year, name(G1, replace)
twoway line le year, name(G2, replace)
twoway lfit le year, name(G3, replace)
graph combine G1 G2 G3, title("Life Expectancy (US)")
Histograms based on density, frequency, bin and width
webuse nlsw88, clear
browse
histogram wage
histogram wage, frequency
histogram wage, percent normal
histogram wage, frequency bin(12)
histogram wage, frequency width(2)
By-groups; and add x- and y-axis titles
histogram wage, frequency by(union) ///
title("Wage Distribution by Union Status")
xtitle("Hourly wage")
21
ytitle("frequency")
Exercise (10 mins)
Choose at least three plottypes (e.g., scatter, lfit, qfit, lowess, lpoly, line, connected, rcap)
and draw graphs for any pair you like from nlsw88 dataset.
You may combine them in ONE graph.
Excellent free resources:
UCLA website:
[Link]
Extract textbooks from this website:
[Link]
Specially, the following textbook with sample data and code:
Wooldridge, J. M. (2010). Econometric analysis of cross section and panel data (2nd ed.).
MIT Press. Available at: [Link]
22