Showing posts with label Allbus. Show all posts
Showing posts with label Allbus. Show all posts

Feb 27, 2020

Random graphs (143): Scatterplot

// Open Allbus 1980-2016:
use id03 eastwest year using "allbus\ZA4586_v1-0-0.dta", clear

recode id03 (-1 -7 -8 -9 -13 = .), gen(topbot)
recode eastwest (2 = 1) (1 = 0), gen(east)

table year, c(mean topbot)

collapse topbot, by(year east)

twoway (scatter topbot year if east == 0, connect(L)) ///
       (scatter topbot year if east == 1, connect(L)) ///
      , ylabel(4 (.5) 7, format(%6.1f)) ///
        xlabel(1980 1982 1986 1988 1990 1991 1992 2000 (2) 2016, alt) ///
        xtitle("Survey year") ///
        ytitle("Average ladder ranking") ///
        legend(order(1 "West Germany" 2 "East Germany") pos(11) ring(0)) ///
        note("{it: Source:} German General Social Survey 1980-2016, doi:10.4232/1.13029", justification(left) bexpand span)

Oct 26, 2019

Inverse probability of treatment weighting

// Allbus 2018
use xr19 sex age isced97 eastwest german pt09 pt10 wghtpew bik using "ZA5272_v1-0-0.dta", clear

// Outcome: Trust in media
recode pt09 pt10 (-9 = .)
alpha pt09 pt10 
scores trust = mean(pt09 pt10), nv(1)
label var trust "Trust in media"
drop pt09 pt10 

// Treatment: Internet use
gen internet = (xr19 == 1) if !inlist(xr19, -9, -8)
label define internet 1 "Internet user" 0 "Internet non-user"
label val internet internet
drop xr19

// Gender
gen female = (sex == 2)
label var female "Female sex"
drop sex

// Age
recode age (-32 = .)
label var age "Age"

// Education
recode isced97 (-32 = .)
label define isced97 1 "Basic" 2 "Lower secondary" 3 "Upper secondary" 4 "Post-secondary" 5 "Tertiary first" 6 "Tertiary second", modify
label var isced97 "Education"

// East
generate east = (eastwest == 2)
label var east "Eastern Germany"
drop eastwest

// German
recode german (1 = 0) (2 = 0) (3 = 1) (-50 = 1), gen(foreign)
label var foreign "Foreign citizen"
drop german

// Region
recode bik (-34 = .)
label define bik  1 "-1,999 inh." ///
                  2 "2,000-4,999 inh." ///
                  3 "5,000-19,999 inh." ///
                  4 "Zone 1-4, -50,000 inh." ///
                  5 "Zone 2-4, -100,000 inh." ///
                  6 "Zone 1, -100,000 inh." ///
                  7 "Zone 2-4, -500,000 inh." ///
                  8 "Zone 1, -500,000 inh." ///
                  9 "Zone 2-4, 499,999+ inh." ///
                 10 "Zone 1, 499,999+ inh.", modify
label var bik "Commuting zone"

// Keep only complete cases
keep if !missing(trust, internet, female, age, isced97, east, foreign, bik)

// See how imbalanced covariates are
  // Generate dummies for first table
foreach x of varlist isced97 bik {               // Plug in categorical variables here
  qui tab `x', gen(`x'x)                         // Create dummy variables
  foreach var of varlist `x'x* {
   local lab `: var label `var''
   *di "`lab'"                                   // Display label
   *di strpos("`lab'", "==") 
   local i = strpos("`lab'", "==") + 2
   local lab `: di substr("`lab'",  `i', .)'
   di "`lab'"
   label var `var' "  `lab'"                // Add space to label
  }
}
  // Calculate means
eststo clear
estpost tabstat trust female isced97x* age foreign east bikx*, by(internet) ///
                                                       statistics(mean sd) ///
                                                       columns(statistics) ///
                                                       casewise
   // Look at table
esttab, unstack cells(mean(fmt(2)) sd(fmt(2) par keep(trust age))) nonumber ///
        label collabels("Mean (SD)/Prop.") modelwidth(25) varwidth(25) ///
        refcat(isced97x1 "Education:" bikx1 "Communting zone:", nol) 
drop isced97x* bikx* // Drop variables created for table
eststo clear

// Alternative approach
  // Run desired model first
qui teffects ipw (trust) (internet east##(c.age##c.age) female foreign ib3.isced97 i.bik, logit)
  // Table of covariates
tebalance summarize, baseline // Same table as created above
matrix before = r(table)
matrix list before
  // Table of covariates after weighting
tebalance summarize
matrix after = r(table)
matrix list after
  // Merge tables
matrix both = before, after
matrix list both

  // Look at table
esttab matrix(both, fmt(2)), ///
       label nomtitle ///
       coeflabel(1.east "Eastern Germany" ///
                 age "Age" ///
                 c.age#c.age "Age X age" ///
                 1.east#c.age "Eastern Germany X age" ///
                 1.east#c.age#c.age "Eastern Germany X age X age") ///
       refcat(1.isced97 "Education:" 2.bik "Commuting zone:", nol) ///
       varwidth(30) modelwidth(18) ///
       collabel("Control (mean)" "Treated (mean)" "Control (var.)" "Treated (var.)" "Std. diff." "Std. diff. weighted" "Var. ratio" "Var. ratio weighted")

// Omnibus test: tests hypothesis that treatment model balances the covariates
tebalance overid

// Check overlap
teffects overlap, xtitle(Propensity score Internet non-user) ///
                  ytitle(Density) ///
                  legend(order(1 "Internet non-user" 2 "Internet user") pos(2) ring(0)) 

// IPTW
eststo: teffects ipw (trust) (internet east##(c.age##c.age) female foreign ib3.isced97 i.bik, logit), ate
eststo: teffects ipw (trust) (internet east##(c.age##c.age) female foreign ib3.isced97 i.bik, logit), atet

// Doing things by hand:
// Calculate weight for IPTW, ATE
logit internet east##(c.age##c.age) female foreign ib3.isced97 i.bik
predict probab
generate wate = .
replace  wate = 1/probab       if internet == 1
replace  wate = 1/(1 - probab) if internet == 0

// Calculate weight for IPTW, ATT
generate watt = .
replace  watt = 1                   if internet == 1
replace  watt = probab/(1 - probab) if internet == 0

// IPTW by hand
eststo: regress trust i.internet [pw = wate]
eststo: regress trust i.internet [pw = watt]
esttab, b(2) se(2) keep(main:) drop(_cons) rename(r1vs0.internet 1.internet) ///
        nobaselevels mtitles("IPTW ATE" "IPTW ATT" "IPTW ATE" "IPTW ATT") ///
        mgroup("teffects" "regress", pattern(1 0 1 0))

// Doubly robust
eststo: teffects ipwra (trust          east##(c.age##c.age) female foreign ib3.isced97 i.bik) ///
                     (internet east##(c.age##c.age) female foreign ib3.isced97 i.bik, logit)
eststo: teffects ipwra (trust          east##(c.age##c.age) female foreign ib3.isced97 i.bik) ///
                     (internet east##(c.age##c.age) female foreign ib3.isced97 i.bik, logit), atet
esttab, b(2) se(2) keep(main:) drop(_cons) rename(r1vs0.internet 1.internet) ///
        nobaselevels mtitles("IPTW ATE" "IPTW ATT" "IPTW ATE" "IPTW ATT" "IPTW RA ATE" "IPTW RA ATT") ///
        mgroup("teffects ipw" "regress" "teffects ipwra", pattern(1 0 1 0 1 0))

// Doubly robust by hand
tempvar internet0a internet1a internet0b internet1b ate att

// ATE
regress trust east##(c.age##c.age) female foreign ib3.isced97 i.bik if !internet [pw = wate]
predict `internet0a'
regress trust east##(c.age##c.age) female foreign ib3.isced97 i.bik if internet [pw = wate]
predict `internet1a'
generate `ate' = (`internet1a' - `internet0a')
summarize `ate'

// ATT
regress trust east##(c.age##c.age) female foreign ib3.isced97 i.bik if !internet [pw = watt]
predict `internet0b'
regress trust east##(c.age##c.age) female foreign ib3.isced97 i.bik if internet [pw = watt]
predict `internet1b'
generate `att' = (`internet1b' - `internet0b')
summarize `att'

Specification curve analysis

use "ZA4612_v1-0-1.dta", clear
do "ZA4612_patch_v1-0-1.do" // Some patch from data provider

keep v399-v404 v933 v827 v301 v298 

// Outcomes
mvdecode v399-v404, mv(9 = .a )

generate stress  = 5 - v399
generate depress = 5 - v400
generate calm    = v401 - 1
generate energy  = v402 - 1
generate pain    = 5 - v403
generate lonely  = 5 - v404

// Predictors
  // Topbot
mvdecode v933 v827, mv(96 = .a \ 99 = .b) 
generate topbot = v933
replace  topbot = v827 if missing(topbot)
  // Age
mvdecode v301, mv(999 = .a)
rename v301 age
  // Female
generate female = (v298 == 2)

drop v399-v404 v933 v827 v298 // Drop unnecessary variables

// Post definition
tempname foo
postfile `foo' str50 spec k1 k2 k3 b se using deleteme.dta, replace

// Loop
forvalues k1 = 1/6 {
  if `k1' == 1 local y "stress"
  if `k1' == 2 local y "depress"
  if `k1' == 3 local y "pain"
  if `k1' == 4 local y "calm"
  if `k1' == 5 local y "energy"
  if `k1' == 6 local y "lonely"
    forvalues k2 = 1/4 {
      if `k2' == 1 local agecontrol "age"
      if `k2' == 2 local agecontrol "c.age##c.age"
      if `k2' == 3 local agecontrol "c.age##c.age##c.age"    
      if `k2' == 4 local agecontrol "c.age##c.age##c.age##c.age"
        forvalues k3 = 1/3 {
          if `k3' == 1 local ifs " "
          if `k3' == 2 local ifs "if female == 1"
          if `k3' == 3 local ifs "if female == 0"
 
        local spec regress `y' topbot `agecontrol' female `ifs'

        qui `spec'
        local  b =  _b[topbot]
        local se = _se[topbot]

        post `foo' ("`spec'") (`k1') (`k2') (`k3') (`b') (`se')
        }
    }
}
postclose `foo'

// Plot specification curve
use deleteme, clear

// Generate ranked analytical choice variable
sort b
generate sk = _n
label var sk "Specification (sorted by coefficient size)"

// Calculate CI's
generate ub = b + 1.96 * se
generate lb = b - 1.96 * se

// Remind yourself what the variables mean
label var k1 "Outcome"
label var k2 "Age control"
label var k3 "Subsample"

// Stack indicators
generate k3c = k3
generate k2c = k2 + 1 + 3 // 3 because K3 has 3 categories, 1 for title
generate k1c = k1 + 1 + 3 + 4 + 1  // K2 has 4 categories

// Calculate some things for size of second axis
qui summarize b
global brange = r(max) - r(min)
global bmin = r(min)
global bmax = r(max)
global from_y = $bmin - (4.5 * $brange)

// Plot
twoway (scatter k1c k2c k3c sk, msymbol(o o o) msize(vsmall vsmall vsmall) ///
        yscale(range(1 22)) ///        
        ylabel( 1 "Full sample" 2 "Females only" 3 "Males only" 4 "{bf:Subsample}" ///
                5 "Age" 6 "Age squared" 7 "Age cubed" 8 "Age quartic" 9 "{bf:Age control}" ///
               10 "Stress"   11 "Depression" 12 "Pain" ///
               13 "Calmness" 14 "Energy"     15 "Loneliness" 16 "{bf:Outcome}", tstyle(notick) axis(1)))  ///
       (rcap b b sk, yaxis(2) yscale(range($from_y $bmax) axis(2)) ///
                     ylab(, format(%2.1g) axis(2)) ///
                     ytitle("{bf:Coefficient size}", axis(2) placement(north)) ///
                     yline(0, axis(2))) ///
       (rspike ub lb sk, yaxis(2)), ///
        xlabel(none)  ///
        legend(off) name(curve, replace) 
 

Reference

Simonsohn, Uri, Joseph P. Simmons, and Leif D. Nelson. 2015. Specification Curve. Descriptive and Inferential Statistics on All Reasonable Specifications. University of Pennsylvania. doi: 10.2139/ssrn.2694998
 

Oct 18, 2019

Descriptive statistics table using -esttab-

// Open Allbus 1984-2016
use age iscd975 isei* sex using "ZA4586_v1-0-0.dta", clear

// Age
recode age (-32 = .)
label var age "Age"

// Education
recode iscd975 (-32 = .) ///
               (1 2 = 0 "Low") ///
               (3 4 = 1 "Medium") ///
               (5 = 2 "High"), gen(educ)
label var educ "Education"

// ISEI
generate isei = isei88  if inrange(isei88, 16, 90)
replace  isei = isei08  if missing(isei) & inrange(isei08, 16, 90)
replace  isei = isei68  if missing(isei) & inrange(isei68, 16, 90)
replace  isei = isei88a if missing(isei) & inrange(isei88a, 16, 90)
replace  isei = isei08a if missing(isei) & inrange(isei08a, 16, 90)
replace  isei = isei68a if missing(isei) & inrange(isei68a, 16, 90)
label var isei "ISEI" 

// Sex
recode sex (1 = 0 "Male") (2 = 1 "Female"), gen(female)
label var female "Sex"

// Listwise deletion
capture drop touse
mark touse
markout touse age educ sex isei

// Create dummies of categorical variables for descriptives table
foreach x of varlist educ female {               // Plug in categorical variables here
  qui tab `x', gen(`x'x)                         // Create dummy variables
  foreach var of varlist `x'x* {
   local lab `: var label `var''
   *di "`lab'"                                   // Display label
   *di strpos("`lab'", "==") 
   local i = strpos("`lab'", "==") + 2
   local lab `: di substr("`lab'",  `i', .)'
   label var `var' "\dumm `lab'"                // Add \dumm to label
  }
}

// Add this to Latex code to indent dummy variables
// % Indent for tables
// \newcommand*{\dumm}{\hspace*{0.5cm}}%

// Calculate descriptives and save them internally
eststo clear
estpost tabstat isei educx* age femalex* if touse, by(female) ///
                                                   statistics(mean sd min max) ///
                                                   columns(statistics)

// Format number of cases for table caption
local n: display %9.0gc e(N)
// Create table
esttab using "table1.tex", cells("mean(fmt(2) label(Prop./Mean)) sd(fmt(2) label(\emph{SD}) keep(isei age))") ///
                         refcat(educx1 "Education:" ///
                                femalex1 "Sex:", nolabel) ///
                         coeflabel(isei "Occupational status (ISEI)") ///
                         unstack ///
                         order(Total:* Male:* ) ///
                         nogap eqlabels(, span prefix(\multicolumn{@span}{c}{) suffix(}) erepeat(\cline{@span})) nonumber replace label ///
                         title("Descriptive statistics, \emph{N}~=~`n' \label{tab1}") ///
                         stats(N, fmt(%9.0gc) label(\emph{N})) ///
                         booktabs 
drop educx* femalex*  // Remove dummy variables created for table

Oct 11, 2019

Indent value labels of categorical variables for -esttab-

// Open Allbus cumulation
use hs01 iscd975 age sex ///
    using "ZA4586_v1-0-0.dta", clear

// Self-rated health
recode hs01 (4 5 = 1 "Poor health") ///
            (3 2 1 = 0 "Good health") ///
            (-1 -11 -9 = .) ///
            , gen(poorhealth)
label var poorhealth "Poor self-rated health"

// Education
recode iscd975 (5 = 5 "Tertiary") ///
               (4 = 4 "Post-secondary") ///
               (3 = 3 "Upper secondary") ///
               (2 = 2 "Lower secondary") ///
               (1 = 1 "Basic") (-32 = .) ///
               , gen(isced)
label var isced "Education"

// Age
recode age (-32 = .)
generate age10 = age/10
label var age10 "Age / 10"

// Sex
recode sex (1 = 0 "Male") ///
           (2 = 1 "Female") ///
           , gen(female)
label var female "Female sex"

// Indent value labels
labvalch3 female isced, prefix("\dumm ")

// Add this to Latex code
// % Indent for tables
// \newcommand*{\dumm}{\hspace*{0.5cm}}%
eststo clear eststo: regress poorhealth ib3.isced age10 i.female, robust esttab using table.tex, b(2) se(2) booktabs replace /// label nobaselevels nonumber /// modelwidth(25) varwidth(33) /// stats(N, fmt(%8.0gc)) /// refcat(1.isced "Education (ref. Upper secondary)" /// 1.female "Sex (ref. Male)", nol) /// title("Poor self-rated health regressed on education, age, and sex, linear probability model") // Alternative approach (that also works for .rtf tables) labvalch3 female isced, subst("\dumm " "") *ssc install elabel elabel define female isced (= #) (= " " + @) , modify // Note that the leading sapce don't seem to show up in a frequency table with -fre- esttab using table.rtf, b(2) se(2) replace /// label nobaselevels nonumber /// modelwidth(25) varwidth(33) /// stats(N, fmt(%8.0gc)) /// refcat(1.isced "Education (ref. Upper secondary)" /// 1.female "Sex (ref. Male)", nol) /// title("Poor self-rated health regressed on education, age, and sex, linear probability model")

Sep 18, 2019

Random graphs (142): Boxplot using twoway commands with overlaid data

use v358 v392 v585 v829 if inrange(v829, 1, 5) using "data allbus\ZA4612_v1-0-1.dta", clear

// Subjective social mobility
recode v829 (5 = 1 "Much lower status") ///
            (4 = 2 "Lower status") ///
            (3 = 3 "About equal") ///
            (2 = 4 "Higher status") ///
            (1 = 5 "Much higher status") ///
            (95 96 98 99 = .), gen(ssm)
label var ssm "Status of own job compared to father's"

// Respondent's social status ISEI
clonevar isei = v358
replace  isei =    . if inlist(isei, 0, 99)
replace  isei = v392 if missing(isei)
replace  isei =    . if inlist(isei, 0, 99)
label var isei "Respondent's ISEI"

// Father's social status ISEI
clonevar fisei = v585 
replace  fisei =    . if inlist(fisei, 0, 99)
label var fisei "Father's ISEI"

// Objective status mobility
gen osm = isei - fisei
label var osm "Objective status mobility"


// Boxplot using -graph- command graph box osm, over(ssm, descending) horizontal /// yline(0) l1title("Status of own job compared to father's" "(self-assessment)") /// name(figure1, replace)


// Boxplot using -twoway- command

// Calculate stuff for boxplot
qui bys ssm: sum osm, detail
qui bys ssm: egen min = pctile(osm), p(25) // Interquartile range
qui bys ssm: egen max = pctile(osm), p(75) // Interquartile range
qui bys ssm: egen med = median(osm)

// Plot
twoway (scatter ssm osm, msymb(o) jitter(2) mcolor(red%10)) ///
       (scatter ssm med, msymb(oh) mcolor(black)) ///
       (rspike  min max ssm, horizontal lcolor(black)), ///
        ylabel(1/5, valuelabel) xline(0) ///
        ytitle("Status of own job compared to father's" "(self-assessment)") ///
        legend(order(2 "Median" 3 "Interquartile range") ring(0) pos(11)) ///
        xtitle(Objective social mobility) name(figure2, replace)
drop min max med // Drop stuff for boxplot

Sep 4, 2018

Making tables for logit models using -esttab-

// Open Allbus 2016
use "ZA5250_v2-0-0.dta", clear

// Prepare variables
recode hs01 (4 5 = 1 "Poor health") (3 2 1 = 0 "Good health") (-9 = .), gen(poorhealth)
label var poorhealth "Poor self-rated health"
recode sex  (2 = 1 "  Female") (1 = 0 "  Male"), gen(female)
label var female "Female sex"
recode age (-32 = .)
label var age "Age"
recode isced97 (1 2 = 0 "  Low") (3 4 = 1 "  Medium") (5 6 = 2 "  High") (-32 = .), gen(education)
label var education "Education"

// Fit model 1
eststo clear
eststo: qui logit poorhealth i.female i.education age
estadd expb
qui sum poorhealth
estadd scalar avg = r(mean) * 100

// Long table

 
esttab, cells(b(star fmt(2) label("B")) ///
              se(par fmt(2) label("(SE B)")) ///
              expb(par([ ]) label("[OR]"))) ///
        stats(N avg chi2 df_m, fmt(%8.0gc %8.1f %8.1gc 0) ///
                     label("Observations" ///
                           "% poor health" ///
                           "Chi-squared" ///
                           "df")) ///
        label varwidth(30) modelwidth(25) nonumber nomtitle varlabel(_cons "Intercept") ///
        eqlabel(" ") ///
        nobaselevel ///
        refcat(1.female "Sex (ref. male)" 1.education "Education (ref. low)", nol) ///
        addnote("* p<0.05, ** p<0.01, *** p<0.001") ///
        title("Poor self-rated health regressed on sex, education, and age. Logistic model")

// Fit models 2
eststo clear
eststo: qui logit poorhealth  i.education age if female == 0
qui estadd expb
qui sum poorhealth if female == 0
qui estadd scalar avg = r(mean) * 100
eststo: qui logit poorhealth age i.education if female == 1
qui estadd expb
qui sum poorhealth if female == 1
qui estadd scalar avg = r(mean) * 100
  
// Wide table
 
esttab, cell("b(fmt(2) label(B)) se(fmt(2) label(SE B)) expb(fmt(2) label(OR) star)") ///
        stats(N avg chi2 df_m, fmt(%8.0gc %8.1f %8.1gc 0) ///
                     label("Observations" ///
                           "% poor health" ///
                           "Chi-squared" ///
                           "df")) ///
        label varwidth(30) modelwidth(8) nonumber mtitle("Men" "Women") varlabel(_cons "Intercept") ///
        eqlabel(" ") nobaselevels ///
        refcat(1.education "Education (ref. low)", nol) ///
        addnote("* p<0.05, ** p<0.01, *** p<0.001") ///
        title("Poor self-rated health regressed on education and age, stratified by sex. Logistic model")

Mar 23, 2018

Random graphs (129): Offsetting markers

// Open Allbus 2016
use eastwest hs01 id02 using ZA5250_v2-0-0.dta, clear

// Region
recode eastwest (1 = 0 "West Germany") (2 = 1 "East Germany"), gen(east)
label var east "East Germany"

// Subjective social class
recode id02 (-50/-7 = .) ///
            (     1 = 0 "Lower class") ///
            (     2 = 1 "Working class") ///
            (     3 = 2 "Middle class") ///
            (   4 5 = 3 `" "Upper" "(middle)" "class" "'), gen(class)
label var class "Subjective social class"

// Health
recode hs01 (-9 = .) (5 = 0 "Bad") (4 = 1 "Less good") (3 = 2 "Satisfactory") ///
            (2 = 3 "Good") (1 = 4 "Very good"), gen(health)
label var health "Self-rated health"

// Model
regress health i.class##i.east //[pw = wghtpew]

// Plot using marginsplot
margins class#east, saving(myfile, replace) 
 
marginsplot, legend(pos(4) ring(0)) name(marginsplot, replace) title("") ///
             ytitle("Predicted self-rated health") ylabel(, format(%6.1f))

// Plot using twoway with overlay
use myfile, clear

// Create offset
clonevar _mx = _m1
replace _mx = cond(_m2 == 2, _mx - 0.1, _mx + 0.1)

// Plot using marginsplot
 
twoway (rcap _ci_lb _ci_ub _m1 if _m2==0, sort) ///
       (rcap _ci_lb _ci_ub _mx if _m2==1, sort) ///
       (connected _margin _m1 if _m2==0, msymbol(oh)) ///
       (connected _margin _mx if _m2==1, msymbol(o)) ///
       , title("") ///
        ytitle("Predicted self-rated health") xla(, valuelabel) ///
  legend(pos(4) ring(0) col(1) order(3 "West Germany" 4 "East Germany")) ///
  name(twoway, replace) ylabel(, format(%6.1f))

Mar 22, 2018

Random graphs (128): Comparing distributions

// Open cumulated Allbus 1980-2014
use ost_west v152 year using ZA4584_v1-0-0.dta, clear

// West Germany only
keep if ost_west == 1

// Subjective SES
recode v152 (0 = .) (97 98 99 = .), gen(topbot)
label var topbot "Subjective SES"

// Drop years with missing data
drop if inlist(year, 1984, 1994, 1996, 1998)
// Drop early years
drop if year < 1998
label drop year // Drop label

// Generate average subjective SES per year
bysort year: egen avg = mean(topbot)

// Figure
tabplot topbot year, yasis xasis horizontal percent barw(1) bfcolor(none) //
                     xtitle("") subtitle("") note("") //
                     addplot(connect avg year, sort msymbol(O) mcolor(black) msize(large)) 

Dec 28, 2017

Random graphs (123): Descriptive statistics

// Open Allbus 2010
use v11 v13 v15 v17 v19 using ZA4612_v1-0-1.dta, clear

// Prepare variables
recode v11 v13 v15 v17 v19 (99 = .)
label define x 1 `""1" "Unimportant""' 7 `""7 Very" "important"'

label var v11 "v11: Job security"
label var v13 "v13: High income"
label var v15 "v15: Opportunities for promotion"
label var v17 "v17: Respectable occupation"
label var v19 "v19: Lots of leisure time"

// Plot histograms
foreach x of varlist v11 v13 v15 v17 v19 {
  label val `x' x
  histogram `x', frequency ///
                 xlabel(1 (1) 7, val) ///
                 ylabel(0 (500) 1500) ///
                 ytick(0 (250) 1750) ///
                 name(`x', replace) nodraw
}

// Calculate correlation matrix
cor v11-v19
matrix correlations = r(C)

// Plot correlation matrix
plotmatrix, mat(correlations) split(-1(0.10)1) color(sienna) ///
            freq formatcells(%6.2f) nodiag legend(title(Pearson's {it:r}) col(1)) ///
            name(cormatrix, replace) nodraw 

// Combine plots
graph combine v11 v13 v15 v17 v19 cormatrix, col(2) ysize(8) xsize(6) altshrink

Dec 3, 2017

Random graphs (121): Overlaid prediction plots

// Open cumulated Allbus 2004-2014
use if year >= 2004 using "ZA4584_v1-0-0.dta", clear

// Select data
keep if inrange(v729, 25, 65)  // Only those between 25 and 65
drop if v495 == 0 // Health split

// Poor self-rated health
generate poorhealth = inlist(v495, 4, 5) if !inlist(v495, 0, 9)

// Top-bottom
recode v152 (0 99 = .), gen(sss)
label define sss 1 `""1" "Bottom""' 2 "2" 3 "3" 4 "4" 5 "5" 6 "6" 7 "7" 8 "8" 9 "9" 10 `""10" "Top""'
label val sss sss
label var sss "Subjective SES"

// Education
recode v767 (94 99 = .), gen(educ)
label define educ 1 "Basic" 2 "Lower secondary" 3 "Upper secondary" 4 "Post-secondary" 5 "Tertiary"
label val educ educ
label var educ "Education"

// ISEI 1988
generate isei = v789 if !inlist(v789, 0, 99)
replace  isei = v825 if missing(isei) & !inlist(v825, 0, 99)
label var isei "Occupational status (ISEI)"

// EGP
recode v784 (0 = .a) (10004 = .b) (10009 = .c) (1 2 = .d) // ISCO-88
recode v820 (0 = .a) (10004 = .b) (10009 = .c) (1 2 = .d) // Last job ISCO-88
clonevar isco88 = v784
replace  isco88 = v820 if missing(isco88) & !missing(v820)
recode v804 (0 = .a "Not available") (9999 = .b "No answer"), gen(supervisor) // Number of people supervised
recode v773 (0 = .a "Not available") (99 = .b "No answer") ///
            (10/24 = 1 "Self-employed") (40/65 = 0 "Employed") ///
            (30 70/74 = .c "Not employed"), gen(selfemployed)  // Self-employed
iskoegp egp, isko(isco88) supvis(supervisor) sempl(selfemployed)

// Household income
generate income = v924+1 if !inlist(v924, 99996, 99997, 99999)
generate lninc  = log(income)
label var lninc "Household income (logged, equivalized)"

// Controls
generate state = v1374
generate female = (v731 == 2)
generate age = v729 if v729 != 999

// Macro for controls
local control i.female c.age##c.age i.state##i.year

// Fit some models
eststo clear
qui eststo: logit poorhealt sss                     `control', robust cluster(year) 
qui margins, over(sss) post
est store model1
eststo: logit poorhealt sss i.educ                  `control', robust cluster(year) 
qui margins, over(sss) post
est store model2
eststo: logit poorhealt sss i.educ isei             `control', robust cluster(year) 
qui margins, over(sss) post
est store model3
eststo: logit poorhealt sss i.educ isei i.egp       `control', robust cluster(year) 
qui margins, over(sss) post
est store model4
eststo: logit poorhealt sss i.educ isei i.egp lninc `control', robust cluster(year) 
qui margins, over(sss) post
est store model5

// Plot findings
coefplot model1 model2 model3 model4 model5, vertical ///
         legend(order(2 "Age, federal state, survey year" 4 "plus Education" ///
                      6 "plus occupational status (ISEI)" ///
                      8 "plus social class (EGP)" ///
                      10 "plus household income") pos(2) ring(0) col(1) ///
                title(Model accounting for)) ///
         scheme(plotplainblind) ///
         xtitle(Subjective socioeconomic status) ///
         ytitle(Predicted probability of poor health)

Aug 13, 2017

Random graphs (110): Correlation heatmap

// Open Allbus 2010 data
use "ZA4612_v1-0-1.dta", clear

// Men 25-64 only
keep if v298 == 1
keep if inrange(v301, 20, 64)

// Combine top bottom variables into one 
// (Seems pointless, though, as education in years
//  was only measured in one of the splits)
generate topbot = v933 if v933 <= 10
replace  topbot = v827 if missing(topbot)
replace  topbot =    . if topbot > 10

// Education, truncated to 5th-95th percentile
qui sum v917 if v917 < 94, detail 
generate education = v917 if v917 < 94
replace  education = r(p95) if education >=  r(p95) & !missing(education)
replace  education = r(p95) if education >=  r(p95) & !missing(education)
replace  education =  r(p5) if education <=   r(p5) & !missing(education)

// ISEI
generate isei88 = v358 if !inlist(v358, 0, 99)
replace  isei88 = v392 if !inlist(v392, 0, 99)

// Household income, logged
generate income = v674 if !inlist(v674, 99997, 99999)
generate lnincome = log(income)

// Generate correlation matrix
cor topbot education income isei
matrix correlations = r(C)

// Plot
plotmatrix, mat(correlations) split(-1(0.10)1) color(vermillion) ///
            freq formatcells(%6.2f) nodiag legend(title(Pearson's {it:r}) col(1))

Aug 9, 2017

Random graphs (108): Violin plot

// Open Allbus data
use V388 V151 using "ZA4602_v1-0-0.dta", clear

// Income
recode V388 (99997 = .a "Refused") (99999 = .b "No answer"), gen(personal_income)
label var personal_income "Personal net income"

// Sex
recode V151 (1 = 0 "Men") (2 = 1 "Women"), gen(sex)
label var sex "Gender"

vioplot personal_income, over(sex) ytitle("Personal net income in Euro per month")

Jul 27, 2017

Random graphs (106): Interaction plot with overlaid density

// Open Allbus 2008
use V154 V151 V156 V760 V754 V755 V5 V767 using ZA4602_v1-0-0.dta, clear

// Age
generate age = V154 if V154 != 999

// Sex
generate female = (V151 == 2)

// Migrant
generate migrant = (V156 == 2)

// Interviewer ID
rename V760 id

// Interviewer sex
generate femaleinterviewer = (V754 == 2)

// Interviewer age
generate interviewerage = V755

// Attractiveness rating by interviewer before and after interview
qui factor V5 V767, pcf
predict attractiveness

// Calculate Spearman-Brown for two-item scales according
// to Eisinga et al. (https://doi.org/10.1007/s00038-012-0416-3):
spearman V5 V767

// Fit model with respondents clustered in interviewers
mixed attractiveness c.age##i.female i.migrant i.femaleinterviewer##c.interviewerage || id: 

// Calculate margins and plot
qui margins, at(age = (18  (10) 98) female = (0 1))
marginsplot, recast(line) recastci(rarea) ciopt(color(gs14)) ///
             plot1opts(lpattern(dash)) ///
             legend(ring(0) pos(2)) ///
             title("Female beauty premium disappears with age", span) ///
             ytitle("Predicted attractiveness", axis(1)) ///
             xtitle("Age") ///
             xlabel(20 (10) 100) ///
             addplot(histogram age, discrete yaxis(2) ///
                                    lcolor(white) ///
                                    ylabel(0 0.01 0.02, format(%6.2f) axis(2)) ///
                                    yscale(alt range(0 0.1) axis(2)) ///
                                    ytitle("Age density", axis(2)) ///
                                    legend(order(3 "Men" 4 "Women"))) ///
             note(" " "{it:Source:} German General Social Survey Allbus 2008, doi:10.4232/1.12345", span) ///
             name(figure1, replace)

Jul 22, 2017

Random graphs (104): Sunflower plot

// Open Allbus data
use v614 v301 using  "C:\Users\User\Dropbox\methods and data\allbus\ZA4612_v1-0-1.dta", clear

// Prepare variables
recode v301 (999 = .), gen(age)
label var age "Age"
recode v614 (99997 99999 = .), gen(personal_income)
label var personal_income "Personal net income in Euro"

// Sunflower plot
sunflower personal_income age, legend(pos(11) ring(0) size(*.9)) ///
          note(" " "{it:Source:} German General Social Survey Allbus 2010, doi:10.4232/1.11782", span)

Random graphs (103): Dot plots


// Open Allbus data
use V388 V151 using "ZA4602_v1-0-0.dta", clear

// Income
recode V388 (99997 = .a "Refused") (99999 = .b "No answer"), gen(personal_income)
label var personal_income "Personal net income"

// Sex
recode V151 (1 = 0 "Men") (2 = 1 "Women"), gen(sex)
label var sex "Gender"

// Dotplot stratified by grouping variable
dotplot personal_income, over(sex) center msymbol(oh) ///
        ytitle("Personal net income in Euro") xtitle("") ///
        note(" " "{it:Source:} German General Social Survey Allbus 2008, doi:10.4232/1.12345", span) ///                         
        name(figure1, replace)

// Open EQLS data use Y11_Q40b Y11_Q40e Y11_Q40f Y11_Q40g Y11_Q30 using "7348_F1.dta", clear // Relabel variables label var Y11_Q40b "Job" label var Y11_Q40e "Family life" label var Y11_Q40f "Health" label var Y11_Q40g "Social life" label var Y11_Q30 "Life overall" // Dotplot for several variables dotplot Y11_Q40b Y11_Q40e Y11_Q40f Y11_Q40g Y11_Q30, /// ylabel(1 "Very dissatisfied 1" 2 3 4 5 6 7 8 9 10 "Very satisfied 10") /// xtitle("How satisfied with ...") /// note("{it:Source:} European Quality of Life Survey 2003-12", span) /// name(figure2, replace)

Jul 10, 2017

Random graphs (102): Sparklines


use v151 year ost_west if ost_west == 1 using ZA4582_v1-0-0.dta, clear

// Year
label drop year
label var year ""

// Subjective social class
recode v151 (9 = .a "No response") ///
            (8 = .b "Don't know") ///
            (7 = .c "Refused") ///
            (6 = .d "None of the strata") ///
            (5 =  5 "Upper class") ///
            (4 =  4 "Upper middle class") ///
            (3 =  3 "Middle class") ///
            (2 =  2 "Working class") ///
            (1 =  1 "Lower class") ///
           , gen(subjclass)
label var subjclass "Subjective social class"

qui tab subjclass, gen(subjx)

  // Change value labels in bulk
foreach var of varlist subjx* {
  local lab `: var label `var''
  local lab `: di subinstr("`lab'", "subjclass==", " ", 1)'
  label var `var' "`lab'"
}

// Collapse data set
  // Copy variable labels before collapse
  // Following:
  // http://www.stata.com/support/faqs/data-management/keeping-same-variable-with-collapse/
foreach var of var subjx* {
  local l`var' : variable label `var'
  if `"`l`var''"' == "" {
  local l`var' "`var'"
  }
}
  // Collapse 
collapse subjx*, by(year)
  // Restore value labels after collapse  
foreach var of var subjx* {
  label var `var' "`l`var''"
 }

 // Change to percentages
 foreach var of var subjx* {
   replace `var' = `var' * 100
 }
 
// Sparklines 
sparkline subjx* year, variablelabels xlabel(1980 (10) 2010) xmtick(1980 (2) 2014) ///
                       xtitle("") format(%6.1f) extremes ///
                       title("Subjective social class in Western Germany", span) ///
                       name(subjclass, replace)

Jun 6, 2017

Comparing AME's and the LPM

use doi hs01 age sex educ mstat using ZA5250_v2-0-0.dta, clear

// Poor health
recode hs01 (1 2 3 = 0 "Non-poor health") ///
            (  4 5 = 1 "Poor health") ///
            (-9 = .), gen(poorhealth)
label var poorhealth "Poor health"

// Female sex
recode sex (2 = 1 "Female") ///
           (1 = 0 "Male"), gen(female)
label var female "Female sex"

// Age
recode age (18/24 = 0 "18-24 y.") ///
           (25/34 = 1 "25-34 y.") ///
           (35/44 = 2 "35-44 y.") ///
           (45/54 = 3 "45-54 y.") ///
           (55/64 = 4 "55-64 y.") ///
           (65/74 = 5 "65-74 y.") ///
           (75/84 = 6 "75-84 y.") ///
           (85/97 = 7 "85-97 y.") ///
           (-32   = . ), gen(agecat)
label var agecat "Age"

// Education
recode educ (1 2 = 0 "Hauptschule or less") ///
            (  3 = 1 "Mittlere Reife") ///
            (4 5 = 2 "(Fach)Hochschulreife or more") ///
            (-41 -9 6 7 = .), gen(education)
label var education "Education"

// Marital status
recode mstat (1 6     = 2 "Married/cohabiting") ///
             (2 3 4 9 = 1 "Divorced, widowed etc.") ///
             (5       = 0 "Never married") ///
             (-9      = .), gen(married)
label var married "Marital status"

// Model 
eststo clear
  // AME
logit poorhealth i.female i.agecat i.education i.married 
margins, dydx(*) post
eststo
  // LPM
eststo: regress poorhealth i.female i.agecat i.education i.married, robust
esttab using amelpm.tex, drop(_cons) mtitle("AME" "LPM") label b(2) se(2) nonumbers booktabs ///
                         title("Predictors of poor self-rated health, Germany 2016 \label{tab1}") ///
                         addnote("\emph{Source}: Allbus 2016, doi: 10.4232/1.12754"  ///
                                 "AME: Average marginal effects, LPM: Linear probability model") ///
                         refcat(0.female "\emph{Sex}" ///
                                0.agecat "\emph{Age}" ///
                                0.education "\emph{Education}" ///
                                0.married "\emph{Marital status}", nolabel) ///
                         alignment(D{.}{.}{-1}) width(0.9\hsize) replace

May 24, 2017

Random graphs (95): Categorical variables

use "ZA4582_v1-0-0.dta", clear

recode v151 (9 = .a "No response") ///
            (8 = .b "Don't know") ///
            (7 = .c "Refused") ///
            (6 = .d "None of the strata") ///
            (5 =  1 "Upper class") ///
            (4 =  2 "Upper middle class") ///
            (3 =  3 "Middle class") ///
            (2 =  4 "Working class") ///
            (1 =  5 "Lower class") ///
           , gen(subjclass)
label var subjclass "Subjective social class"

generate nolabelyear = year     
label define ost_west 1 "Western Germany" 2 "Eastern Germany", modify
graph bar (count), over(subjclass, descending) /// over(nolabelyear, label(angle(vertical))) /// by(ost_west, note("{it:Source:} German General Social Survey (Allbus), doi: 10.4232/1.12439.", span) col(1)) /// percent stack asyvars ytitle(%) ysize(8) /// legend(rows(3) colfirst) name(figure1, replace)
tabplot subjclass nolabelyear, by(ost_west, /// note("{it:Source:} German General Social Survey (Allbus), doi: 10.4232/1.12439.", span)) /// percent(ost_west nolabelyear) /// showval(mlabsize(tiny)) xtitle("") /// xlabel(, angle(vertical)) name(figure2, replace)

May 28, 2016

Random graphs (87): Line plots



unzipfile ZA4582_v1-0-0.dta.zip
use ZA4582_v1-0-0.dta, clear

// Prepare some variables
recode v442  (0   = .a "Not asked") ///
             (1   =  3 "Daily") ///
             (2   =  2 "At least once per week") ///
             (3   =  1 "At least once per month") ///
             (4 5 =  0 "Less often/never") ///
             (9   = .b "No answer"), generate(internet_inc1998)
recode v462  (0   = .a "Not asked") ///
             (1   =  3 "Daily") ///
             (2   =  2 "At least once per week") ///
             (3   =  1 "At least once per month") ///
             (4 5 =  0 "Less often/never") ///
             (9   = .b "No answer"), generate(internet_inc2014)
recode v1910 (0   = .a "Not asked") ///
             (1   =  3 "Daily") ///
             (2   =  8 "Several times a week") ///
             (3   =  2 "At least once per week") ///
             (4   =  1 "At least once per month") ///
             (5   =  0 "Less than once per week") ///
             (9   = .b "No answer"), generate(internet_inc2006)
recode v1909 (0   = .a "Missing") ///
             (1   =  1 "Yes") ///
             (2   =  0 "No"), gen(internet_prev2006)

// Daily and weekly usage
clonevar internet_inc = internet_inc1998
replace  internet_inc = internet_inc2014 if year == 2014

preserve
qui tab internet_inc, gen(usage)
rename usage4 dailyusage
rename usage3 weeklyusage
collapse dailyusage weeklyusage, by(year)
replace dailyusage = dailyusage * 100
replace weeklyusage = weeklyusage * 100
drop if missing(dailyusage)

twoway (scatter weeklyusage year, connect(L)) ///
       (scatter dailyusage year, connect(L))  ///
      , legend(order(1 "At least once per week" ///
                     2 "Daily") title("Internet usage", size(*.8)) ring(0) pos(11)) ///
         xlabel(1998 2004 2014) xtitle("") ytitle(%) ylabel(0 (10) 60) ///
         note(" " "{it:Source:} German General Social Survey (Allbus), doi: 10.4232/1.12439" ///
              "{it:Note:} Based on recodings of v442 and v462.", span) name(internet1, replace)
restore         

// Daily internet usage based on different response formats
replace  internet_inc = internet_inc2006 if year == 2006 | year == 2008

preserve
qui tab internet_inc, gen(usage)
rename usage4 dailyusage
collapse dailyusage, by(year)
replace dailyusage = dailyusage * 100
drop if missing(dailyusage)

twoway (scatter dailyusage year, connect(L))  ///
      , xlabel(1998 2004 2006 2008 2014) xtitle("") ytitle("% of respondents reporting" "{bf:daily} internet usage") ylabel(0 (10) 60) ///
        note(" " "{it:Source:} German General Social Survey (Allbus), doi: 10.4232/1.12439" ///
             "{it:Note:} Based on recodings of v442, v462, and v1910.", span) name(internet2, replace)
restore         

// Yes/no question
preserve
collapse internet_prev, by(year)
drop if missing(internet_prev)
replace internet_prev = internet_prev * 100

twoway (scatter internet_prev year, connect(L))  ///
      , xlabel(2006 2008 2010 2012 2014) xtitle("") ytitle("% of respondents using the internet") ylabel(0 (10) 80) ///
        note(" " "{it:Source:} German General Social Survey (Allbus), doi: 10.4232/1.12439. {it:Note:} Based on v1909.", span) ///
        name(internet3, replace)
restore

erase ZA4582_v1-0-0.dta