************************************************************************************************ *********************************** PAYING NOT TO GO TO THE GYM ******************************* ************************* by Stefano DellaVigna and Ulrike Malmendier ************************* **************************** American Economic Review, June 2006 **************************** ************************************************************************************************ * Stata do file that: * 1. Generates the necessary variables for the empirical analysis; * 2. Reproduces the results in the Tables and Figures in the paper. ************************************************************************************************ clear set mem 200m set matsize 500 set more off cd c:/gym/data/AERFinalData cap log close log using AERdata.log, replace ******************************************************************** **** Create key variables (contract, price, ...) ******************************************************************** *** Load file use GymAERSourceData.dta, clear *** Generate measures of duration of spell sort id time gen dur=1 if (contract>0 & contract[_n-1]==0) replace dur=dur[_n-1]+1 if (contract>0 & id==id[_n-1] & dur~=1) label var dur "Duration of spell" sort id time gen durcont=1 if (contract>0 & contract[_n-1]==0) replace durcont=durcont[_n-1]+1 if (id==id[_n-1] & durcont[_n-1]~=.) label var durcont "Duration since first month of enrollment" *** Generate spellno sort id time gen spellno=1 if (contract>0 & contract[_n-1]==0 & contract~=14 & contract~=19 & contract~=24) replace spellno=3 if (contract>0 & contract[_n-1]==0 & (contract==14 | contract==19 | contract==24)) label var spellno "Spell code - 1 no attendances before spell, 2 - Second or later spell, 3 - attendances before spell, at beg. spell" *** Generate indicator of censoring at end of spell, endsp * notice that endsp2 is constructed so that some of the spells with ensp2==1 * will actually finish in OVERTIME. sort id time gen endsp2=1 if (contract[_n+1]==0 & contract>0 & contract~=. & time<=endcont) replace endsp2=2 if (contract[_n+1]==0 & contract>0 & contract~=. & time<=endcont & (contract==19 | contract==15 | contract==25)) replace endsp2=3 if (time==endcontp & contract>0 & contract~=.) replace endsp2=0 if endsp2==. label var endsp2 "1 if end of spell, 2 if censored, 3 if censored by end of data, at end of data" ******* Drop all month when member not enrolled ******************** * This eliminates all month when individual did not have a contract drop if contract==0 *** Generate a count of all spells by all people sort id time gen spell=1 replace spell=(spell[_n-1]+min(endsp2[_n-1],1)) if _n>1 label var spell "count of all spells by all people" *** Generate indicator of beginning of spell, begsp -- Do after dropping contract==0 sort id time replace spellno=2 if (spellno==1 & id==id[_n-1]) sort spell time egen begsp=max(spellno),by(spell) egen endsp=max(endsp2),by(spell) label var begsp "Spell code - 1 if no attendances before beginning of spell, 2 - Second or later spell, 3 - if attendances before beg. of sp., by spell" label var endsp "1 if end of spell, 2 if censored, 3 if censored by end of data, by spell" *** Generate simplified contract type gen contrac2=contract label var contrac2 "Simplified contract type" replace contrac2=1 if (contract==1|contract==11|contract==111|contract==14|contract==19|contract==15|contract==70) replace contrac2=2 if (contract==2|contract==20|contract==21|contract==24|contract==25|contract==27) *** Generate code for months that are used to compute average attendance and average price gen cnatt=(contract~=77 & contract~=7 & contract~=111 & contract~=70 & contract~=27) gen cnpr=(contract~=77 & contract~=7 & contract~=111 & contract~=70 & contract~=20) label var cnatt "Months in which attendances should be recorded" label var cnpr "Months in which price should be recorded" *** Initial contract type gen contrbeg=contract if (spellno>0 & spellno~=.) label var contrbeg "Contract type with which a spell began" sort id spell egen contrbg=max(contrbeg), by(spell) label var contrbg "Contract type with which a spell began, by spell" *** Generate simplified measure of contract at beginning gen contrbg2=1 if (contrbeg==1|contrbeg==11|contrbeg==111|contrbeg==14| /* */ contrbeg==19|contrbeg==15|contrbeg==70|contrbeg==7) replace contrbg2=2 if (contrbeg==2|contrbeg==21|contrbeg==24) label var contrbg2 "Simplified contract type with which a spell began" sort spell time egen contrbg3=max(contrbg2), by(spell) replace contrbg=contrbg3 drop contrbg3 * This variable we use for Probit regressions of renewal gen contrbgd=(contrbg==1) label var contrbgd "Monthly contract dummy" *** Prices * imprice is the price imputed from the correspondence table using the contract type. * trprice is the price recorded in the billing system -- this is used throughout corr imprice trprice * adjust prices for the yearly contract to take into account the interest rate (3.7%). * use in measure of price per expected attendance gen trpradj=trprice replace trpradj=trprice*(1.037) if contrac2==2 * Generate variable (adjusted) price equal to true (adjusted) price gen price=trprice gen priceadj=trpradj drop trpradj label var price "Price recorded in billing system" label var priceadj "Price adjusted for interest rate" *** Generating problem reminder at spell and id level egen spelprob=max(problem), by(spell) egen idprob=max(problem), by(id) egen grpmth=max(problem==10), by (spell) label var spelprob "Problems in spell, by spell" label var idprob "Problems in spell, by id" label var grpmth "GRP (not monthly nor annual) contract, by spell" *** Generate total money spent measures and drop if no money is spent sort spell time egen temp=sum(priceadj) if overtime==0, by (spell) egen totprice=max(temp),by(spell) egen totprid=max(temp),by(id) drop temp label var totprice "Total money spent, by spell" label var totprid "Total money spent, by id" * finish constructing total money spent measure using price adjusted gen totpr2=totprice if (spellno>0 & spellno~=.) label var totpr2 "Total money spent, at beginning spell" *** contrend and contren2 indicate the contract with which a spell ended gen contrend=contract if (endsp2>0 & endsp2~=.) gen contren2=1 if (contrend==1|contrend==11|contrend==111|contrend==14|contrend==70|contrend==7|contrend==77) replace contren2=15 if (contrend==19|contrend==15) replace contren2=2 if (contrend==2|contrend==20|contrend==21) replace contren2=25 if (contrend==25) label var contrend "Detailed contract type at the end of spell" label var contren2 "Simplified contract type at the end of spell" * Generate a tenure measure (includes censored spells) bys spell: egen tenure=max(dur) label var tenure "Total months in club, by Spell" *** generate total attendance measures egen totatt=sum(attend), by (spell) gen totatt2=totatt if (spellno>0 & spellno~=.) label var totatt "Total attendance for individuals, by spell" label var totatt2 "Total attendance for individuals, at beginning spell" *** Clean codes for type of membership -- Fill in code variable where missing (==0) sort id time gen codetmp=code replace codetmp=code[_n-1] if (code==0 & id==id[_n-1]) replace codetmp=code[_n+1] if (code==0 & id==id[_n+1]) replace code=codetmp drop codetmp ******************************************************************** **** Create Controls ******************************************************************** ************ TYPES OF MEMBERSHIP ********************************* * ** Health insurance * generate a code for people subsidized by HMO cited in paper * club 1 code -- section 5, point 9. gen hinsur=(code==61|code==268 |code==1 |code==42 |code==171) if club==11 * club 2 and 3 codes replace hinsur=(code== 5|code==108 |code==1 |code==66 |code==98) if (club==13|club==16) label var hinsur "Membership with HMO Subsidy" * ** Family membership * club 1 code gen family=(code==8 |code==114 |code==95 |code==210 |code==143 |code==235|code==249) if club==11 * club 2 and 3 codes replace family=(code==29 |code==154 |code==187 |code==69 |code==269 |code==9999 /* */ |code==281 |code==252 |code==253 ) if (club==13|club==16) egen familysp=max(family), by(spell) egen familyid=max(family), by(id) label var family "Family Membership" label var familysp "Family Membership, by spell" label var familyid "Family Membership, by id" * ** Student membership * club 1 code gen student=(code== 142|code==222 |code==168 |code==6) if club==11 * clubs 2 and 3 codes replace student=(code== 145|code==262 |code==122 |code==309) if (club==13|club==16) label var student "Student membership" * ** Corporate membership gen corpor=1 * club 1 code replace corpor=0 if (code==201 |code==48 |code==33|code==2 |code==58 /* */ |code==260 |code==73 |code==220 |code==142 |code==222 |code==168 /* */ |code==6 |code==1 |code==61 |code==268 |code==42 |code==171 |code==186 /* */ |code==134 |code==40 |code==14 |code==86 |code==74 |code==106 |code==123) & club==11 * clubs 2 and 3 code replace corpor=0 if (code==129 |code==13 |code==62|code==3 |code==107 /* */ |code==235 |code==82 |code==308 |code==145 |code==262 |code==122 /* */ |code==28 |code==1 |code==5 |code==108 |code==66 |code==98 |code==9999 /* */ |code==9999 |code==215 |code==112 |code==260 |code==140 |code==4 |code==149 /* */ |code==92 |code==307 |code==309) & (club==13|club==16) label var corpor "Corporate membership" ******* Demographic controls ********************************************************** gen agesq=(age)^2 label var agesq "Age square" ******* Initiation fee ************************************************* egen inittot=max(init), by (spell) label var inittot "Initiation fee" ******* Locker use ********************************************************** sort id spell egen dlockersp=max(dlocker),by(spell) label var dlocker "Measure of locker use" label var dlockersp "Measure of locker use, by spell" ******* Measure for freezing ********************************************************** egen frznot=sum(contract==7 | contract==27) if overtime==0, by (spell) egen frzno=max(frznot), by(spell) drop frznot replace frzno=. if spellno==. label var frzno "Months frozen" ******* Generates measure of ever switching from Annual to Monthly at any time, and vice versa *** bys spell: egen dswitch=max((contrac2==1 & contrbg==2) | (contrac2==2 & contrbg==1)) replace dswitch=. if spellno==. label var dswitch "Dummy for ever switching between annual and monthly" ******** generate a measure of total losses due to choice of month or year contract *********** * compute the losses relative to using the $100 coupon system -- the measure allows for gains gen totglos2=totpr2-100*int(1+.1*totatt2-.05) sort spell time egen totglos=max(totglos2), by(spell) label var totglos "Losses incurred in contract chosen compared to 10-visit pass (positive is loss)" * Cost of a 10-visit pass gen tenpass=100*int(1+.1*totatt2-.05) label var tenpass "Cost under a 10-visit pass" ******** Generate month and year dummies for beginning of contract ****************** gen monthbeg=time if spellno~=. sort spell time egen monthbg2=max(monthbeg), by(spell) gen mthbg1=(monthbg2==729756|monthbg2==729756+365|monthbg2==729756+730|monthbg2==729756+1096) gen mthbg2=(monthbg2==729787|monthbg2==729787+365|monthbg2==729787+730|monthbg2==729787+1096) gen mthbg3=(monthbg2==729815|monthbg2==729815+365|monthbg2==729815+731|monthbg2==729815+1096) gen mthbg4=(monthbg2==729481|monthbg2==729481+365|monthbg2==729481+730|monthbg2==729481+1096) gen mthbg5=(monthbg2==729511|monthbg2==729511+365|monthbg2==729511+730|monthbg2==729511+1096) gen mthbg6=(monthbg2==729542|monthbg2==729542+365|monthbg2==729542+730|monthbg2==729542+1096) gen mthbg7=(monthbg2==729572|monthbg2==729572+365|monthbg2==729572+730|monthbg2==729572+1096) gen mthbg8=(monthbg2==729603|monthbg2==729603+365|monthbg2==729603+730|monthbg2==729603+1096) gen mthbg9=(monthbg2==729634|monthbg2==729634+365|monthbg2==729634+730|monthbg2==729634+1096) gen mthbg10=(monthbg2==729664|monthbg2==729664+365|monthbg2==729664+730|monthbg2==729664+1096) gen mthbg11=(monthbg2==729695|monthbg2==729695+365|monthbg2==729695+730|monthbg2==729695+1096) gen mthbg12=(monthbg2==729725|monthbg2==729725+365|monthbg2==729725+730|monthbg2==729725+1096) gen yrbg97=(monthbg2<=729725) gen yrbg98=(monthbg2>729725 & monthbg2<=729725+365) gen yrbg99=(monthbg2>729725+365 & monthbg2<=729725+730) gen yrbg00=(monthbg2>729725+730 & monthbg2<=729725+1096) gen yrbg01=(monthbg2>729725+1096) * Set of controls global month = `"mthbg2-mthbg12 yrbg98 yrbg99 yrbg00 yrbg01"' ******************************************************************** **** Drop spells and individuals ******************************************************************** *** Drop: * 1. Individuals with never monthly or annual * 2. Serious inconsistency * 3. Family membership * 4. Free or seasonal membership before *** Check number of observations codebook id *** 1. Individuals with never monthly or annual -- These are out already drop if grpmth==1 drop grpmth ** Drop any spells with no money spent on annual or monthly drop if totprice==0 | totprice==. codebook id *** 2. drop individual if any spell of that individual has billing inconsistency ** Problem==600 -- billing inconsistencies drop if idprob==600 ** Drop if duplicate (DUP) since in this case the person was entered twice drop if duplicate==1 drop duplicate codebook id *** 3. Drop id's with family membership at some point count if familyid==1 & dur==1 drop if familyid==1 drop family* codebook id *** 4. Drop if free or seasonal mermbership before, or if not first spell drop if begsp==3 codebook id spell if spellno==1 codebook spell *** Deleting spells requires renumbering the spells sort id time drop spell gen spell=1 replace spell=(spell[_n-1]+min(endsp2[_n-1],1)) if _n>1 **************************************************************************************************** *** Measures of Gap between last attendance and contract termination in monthly *** GAPM -- Generate gap to last in monthly attendance -- do only for spells that end before OVERTIME * Used in Finding 4 and Finding 8 *** PR1-PR4 and ATT1-ATT4 * the measures pr1-pr4 and att1-att4 * Pr`n' (n=1,2,3,4) is price paid for the n months before the last attendance in monthly contract, excluding frozen months * (and requiring at least two months of enrollment before month -`n' -- this is technicality) * Similarly for att`n' referring to attendance * Used in Finding 8 * Initialize gen gapm=0 if (contren2==1 & overtime==0) gen gapcostm=0 if (contren2==1 & overtime==0) gen gapfrm=0 if (contren2==1 & overtime==0) gen stop=0 if (contren2==1 & overtime==0) foreach x in 1 2 3 4 { gen att`x'=0 if (contren2==1 & overtime==0) gen pr`x'=0 if (contren2==1 & overtime==0) } * Run program capture program drop gapprog program define gapprog local i=0 while `i' <35 { sort spell time * Build the gap measures replace gapm=gapm+1 if (gapm~=. & attend[_n-`i']==0 & contract[_n-`i']~=7 & contract[_n-`i']~=70 & contrac2[_n-`i']~=2 & stop==0 & spell[_n-`i']==spell) replace gapcostm=gapcostm+priceadj[_n-`i'] if (gapm~=. & attend[_n-`i']==0 & contract[_n-`i']~=7 & contract[_n-`i']~=70 & contrac2[_n-`i']~=2 & stop==0 & spell[_n-`i']==spell) replace gapfrm=gapfrm+1 if (gapfrm~=. & contract[_n-`i']==7 & stop==0 & spell[_n-`i']==spell) * Build the att and pr measures foreach n in 1 2 3 4 { replace att`n'=attend[_n-`i'-`n'+1] if (stop==0 & (attend[_n-`i']>0 & contract[_n-`i']~=7 & spell[_n-`i'-2-`n'+1]==spell)) replace pr`n'=priceadj[_n-`i'-`n'+1] if (stop==0 & (attend[_n-`i']>0 & contract[_n-`i']~=7 & spell[_n-`i'-2-`n'+1]==spell)) replace att`n'=. if (stop==0 & (attend[_n-`i']>0 & contract[_n-`i']~=7 & spell[_n-`i'-2-`n'+1]~=spell)) replace pr`n'=. if (stop==0 & (attend[_n-`i']>0 & contract[_n-`i']~=7 & spell[_n-`i'-2-`n'+1]~=spell)) } replace stop=1 if (stop~=. & ((attend[_n-`i']>0 & contract[_n-`i']~=7) | spell[_n-`i']~=spell)) local i=`i'+1 } end gapprog * Add up the variables att`n' and pr`n' foreach x in att pr { replace `x'4=`x'4+`x'3+`x'2+`x'1 replace `x'3=`x'3+`x'2+`x'1 replace `x'2=`x'2+`x'1 } * Labels label var gapm "Months elapsed between last attendance and termination of monthly contract" label var gapcostm "Cost of months elapsed between last attendance and termination of monthly contract" ** Generate variables related to gapm gen gapm4=(gapm>=4) if gapm~=. label var gapm4 "Dummy for gapm>=4" gen lgapm=log(1+gapm) label var lgapm "Log(1+gapm)" egen gapcost2=max(gapcostm), by(spell) label var gapcost2 "Cost of months elapsed between last attendance and termination of monthly contract, by spell" *** Generate measures of price per attendance excluding the last n (n=1,2,3,4) months before the last attendance * Used for Finding 8 foreach x in 1 2 3 4 { gen avprcor`x'=(totprice-gapcost2-pr`x')/(totatt-att`x') replace avprcor`x'=(totprice-gapcost2-pr`x') if ((totatt-att`x')==0 & (totprice-gapcost2-pr`x')>0) replace avprcor`x'=. if avprcor`x'==0 gen logcor`x'=log(1+avprcor`x') label var avprcor`x' "Average price per attendance up to `x' months before before the last attendance" label var logcor`x' "Log of 1 + Average price per attendance up to `x' months before before the last attendance" } ********************************** * Generate measures of renewal *********************************** *** Renewal measure. Presence in month i since enrollment for monthly and annual contract * Definition of renewal: * a. includes temporary quitters that come back by month i; * b. excludes spells censored before month i * c. excludes spells if there are not enough months left in the data to find month i sort id time forvalues i=13(1)27 { egen d`i'g=max(durcont==`i'+1), by(id) replace d`i'g=. if ((d`i'g==0 & (endsp==2|endsp==3)) | durcont>1 | time+`i'*30>endcont) } ********************************** * Number of months, average price, average attendance for Summary Statistic (Table 2) *********************************** * Monthly contract, corrected for overtime sort spell time egen mthno=sum(contrac2==1 & (cnatt==1|contract==111)) if overtime==0, by (spell) egen mthnotem=max(mthno), by(spell) replace mthno=mthnotem drop mthnotem egen mthavpr=mean(priceadj) if (contrac2==1 & cnpr==1 & overtime==0), by (spell) egen mthavte=max(mthavpr), by(spell) replace mthavpr=mthavte drop mthavte egen mthavat=mean(attend) if (contrac2==1 & cnatt==1 & overtime==0), by (spell) egen mthavtt=max(mthavat), by(spell) replace mthavat=mthavtt drop mthavtt * Yearly contract, corrected for overtime egen yrno=sum(contrac2==2 & cnatt==1) if overtime==0, by (spell) egen yrnotem=max(yrno), by(spell) replace yrno=yrnotem drop yrnotem egen yravpr=mean(priceadj) if (contrac2==2 & cnpr==1 & overtime==0), by (spell) egen yravtem=max(yravpr), by(spell) replace yravpr=yravtem drop yravtem egen yravat=mean(attend) if (contrac2==2 & cnatt==1 & overtime==0), by (spell) egen yravtt=max(yravat), by(spell) replace yravat=yravtt drop yravtt label var mthavpr "Monthly fee for monthly contracts" label var yravpr "Monthly fee for yearly contracts" label var mthavat "Attendance per month for monthly contracts" label var yravat "Attendance per month for yearly contracts" label var mthno "Months with monthly contract" label var yrno "Months with annual contract" *** Average price over whole spell -- Use later to determine sample with price>=$70 gen pricmth=totprice/(mthno+yrno) label var pricmth "Average monthly price paid" ********************************************************* * Generate average price per average attendance in first and second year for annual contract * used in Tables 3 and 7 and in Figure 2 ********************************************************** ******** MONTHLY *** Average attendance and price each 6 month foreach x in 0 1 2 3 { local lowerbound=1+6*`x' local upperbound=6+6*`x' * Attendance egen temp=mean(attend) if (tenure>=`lowerbound' & dur>=`lowerbound' & dur<=`upperbound' & overtime==0 & cnatt==1), by(spell) by spell: egen attmt`x'=max(temp) drop temp replace attmt`x'=. if dur~=`lowerbound' label var attmt`x' "Attendance for months `lowerbound'-`upperbound'" * Price egen temp=mean(priceadj) if (tenure>=`lowerbound' & dur>=`lowerbound' & dur<=`upperbound' & overtime==0 & cnpr==1), by(spell) by spell: egen pradjmt`x'=max(temp) drop temp replace pradjmt`x'=. if dur~=`lowerbound' label var pradjmt`x' "Adjusted monthly price for months `lowerbound'-`upperbound'" } * Generate a measure of price per attendance for the first 6 months gen prperatt0=pradjmt0/attmt0 * Count no attendances as one attendance to avoid dividing by infinity replace prperatt0=pradjmt0 if attmt0==0 ******** YEARLY *** Average attendance and price in year 1 and 2 * Measure for YEAR 1 egen t1=mean(attend) if (tenure>=12 & cnatt==1 & dur<=13 & contrbg==2 & overtime==0 & monthbg2<=endcont-14*30), by(spell) bys spell: egen attyr1=max(t1) drop t1 egen t1=mean(priceadj) if (tenure>=12 & cnpr==1 & dur<=13 & contrbg==2 & overtime==0 & monthbg2<=endcont-14*30), by(spell) bys spell: egen pradjyr1=max(t1) drop t1 replace attyr1=. if spellno==. replace pradjyr1=. if spellno==. gen pratyr1d=pradjyr1/attyr1 * If the individual did not attend at all, count it as one attendance to avoid downward bias replace pratyr1d=pradjyr1 if attyr1==0 label var attyr1 "Monthly attendance during first year of annual contract" label var pradjyr1 "Monthly price during first year of annual contract" label var pratyr1d "Price per attendance in first year of annual contract" * Measure for YEAR 2 that also includes monthly renewals if tenure>=12 plus duration of first year sort spell time egen t1=mean(attend) if (tenure>=25 & cnatt==1 & dur>13 & dur<=25 & contrbg==2 & overtime==0 & monthbg2<=endcont-26*30), by(spell) by spell: egen attyr2=max(t1) drop t1 egen t1=mean(priceadj) if (tenure>=25 & cnpr==1 & dur>13 & dur<=25 & contrbg==2 & overtime==0 & monthbg2<=endcont-26*30), by(spell) by spell: egen pradjyr2=max(t1) drop t1 replace attyr2=. if spellno==. replace pradjyr2=. if spellno==. label var attyr2 "Montly attendance during second year of annual contract" label var pradjyr2 "Monthly price during second year of annual contract" *** Do month-by-month price and attendance for Figures 2a and 2b forvalues i=1/25 { gen pric`i'=priceadj if (dur==`i' & overtime==0 & cnpr==1) gen atten`i'=attend if (dur==`i' & overtime==0 & cnatt==1) } ********************************************************* *** Save dataset with controls ********************************************************** codebook id sort id time compress save GymDataFinalAER,replace ********************************************************* *** Save smaller dataset to do ratio price per attendance *** Useful since Stata will then use the Delta method to compute *** the standard errors, and we do not have to do it ourselves ********************************************************** use GymDataFinalAER,clear keep id spell time dur overtime cn* contrbg begsp attmt* pradjmt* attyr* pradjyr* attend priceadj pricmth hinsur dlocker ** Define variables for monthly and annual contract that we use forvalues i=0/3 { * Monthly contracts: Assign name to 6-month by 6-month attendance and price gen varmth`i'yat=attmt`i' gen varmth`i'ypr=pradjmt`i' } foreach i in 1 2 { * Yearly contracts: Assign name to attendance and price in year 1 and 2 gen varyr`i'yat=attyr`i' gen varyr`i'ypr=pradjyr`i' } forvalues i=1/24 { * Monthly and annual contracts: Assign name to month-by-month attendance and price gen varmth`i'mat=attend if (dur==`i' & overtime==0 & cnatt==1) gen varmth`i'mpr=priceadj if (dur==`i' & overtime==0 & cnpr==1) } ** Do reshape into attendance and price data, this allows us later to compute correctly standard errors for ratio, * taking into account correlation between price and attendance reshape long varmth0y varmth1y varmth2y varmth3y varyr1y varyr2y varmth1m varmth2m varmth3m varmth4m varmth5m varmth6m /* */ varmth7m varmth8m varmth9m varmth10m varmth11m varmth12m varmth13m varmth14m varmth15m varmth16m varmth17m varmth18m /* */ varmth19m varmth20m varmth21m varmth22m varmth23m varmth24m, i(spell time) j(attpr) string ** Generate dummy variable to label if it's attendance or price data gen datt=(attpr=="at") gen dpr=(attpr=="pr") sort id time datt compress save GymDataFinalAERRatio,replace ********************************************************* * FIGURES ********************************************************* ********************************************************* *Figure 1 - Outfile data for kernel regressions ********************************************************* use GymDataFinalAER,clear *** Outfile a file with price and attendance in first 6 months for the kernel regressions outfile pradjmt0 attmt0 using c:/gym/data/kernel/kernall if (spellno==1 & contrbg==1), replace *Figure 1, club 1 outfile pradjmt0 attmt0 using c:/gym/data/kernel/kerncl1 if (spellno==1 & contrbg==1 & club==11), replace *Figure 1, club 2 outfile pradjmt0 attmt0 using c:/gym/data/kernel/kerncl2 if (spellno==1 & contrbg==1 & club==13), replace *Figure 1, club 3 outfile pradjmt0 attmt0 using c:/gym/data/kernel/kerncl3 if (spellno==1 & contrbg==1 & club==16), replace ********************************************************* *Figure 2 - Data for price per attendance over time, including confidence intervals ********************************************************* use GymDataFinalAERRatio,clear *** Generate month-by-month data for Figures 2a and 2b *** Use this to do confidence intervals * Figure 2a (Annual) forvalues i=1/24 { * Ratio: Price per attendance for monthly contract cap reg varmth`i'm datt dpr if (pricmth>=58 & begsp==1 & contrbg==2), robust nocons display "Price per average attendance in month `i', annual contract" nlcom _b[dpr]/_b[datt] } * Figure 2b (Monthly) forvalues i=1/24 { * Ratio: Price per attendance for monthly contract cap reg varmth`i'm datt dpr if (pricmth>=70 & begsp==1 & contrbg==1), robust nocons display "Price per average attendance in month `i', monthly contract" nlcom _b[dpr]/_b[datt] } ********************************************************* *Figure 3 - Simulation in Matlab, separate code ********************************************************* * Use Matlab program "SimulationCancellation.m", which also calls routines * fun_exp and fun_sop ********************************************************* * TABLES ********************************************************* ************************************************************** * Table 1: Empirical Findings and Explanations ********************************************************** use GymDataFinalAER,clear ************* Finding 1 - Price per average attendance -- Table 3 ************* Finding 2 - Sorting -- Table 5 ************* Finding 3 - Survey Data * See Excel file "HealthClubSurveyResultsSep02.xls" * Text of survey question is "Survey Questionnaire on Health Club Attendance Aug2002.doc" ************* Finding 4 - Gap: Interval between last attendance and termination sum gapm gapm4 gapcostm if (begsp==1 & monthbg2=58&contrbg==2)|(pricmth>=70&contrbg==1)) & inittot==0) ************* Finding 5 - Probit renewal -- Table 6 ************* Findings 6 and 7 - Average attendance over time -- Figures 2a-2b and Table 7 ************* Finding 8 - Correlation Price per Average Attendance and Gap in Monthly Contract* forvalues i=1/4 { corr lgapm logcor`i' } ************************************************************** * Table 2: Descriptive Statistics * Summary statistics on whole sample and on interesting subsamples ************************************************************** gen complspell=(endsp2) * by club: first spell (columns 1-3) bys club: count if endsp==1 & spellno==1 bys club: sum totprice inittot mthavpr yravpr mthavat yravat mthno yrno frzno female age corpor student if spellno==1 * All clubs - first spell (column 4) count if endsp==1 & spellno==1 sum totprice inittot mthavpr yravpr mthavat yravat mthno yrno frzno female age corpor student if spellno==1 * first spell and monthly contract (column 5) count if endsp==1 & spellno==1 & contrbg2==1 sum totprice inittot mthavpr yravpr mthavat yravat mthno yrno frzno female age corpor student if contrbg2==1 & spellno==1 * first spell and annual contract (column 6) count if endsp==1 & spellno==1 & contrbg2==2 sum totprice inittot mthavpr yravpr mthavat yravat mthno yrno frzno female age corpor student if contrbg2==2 & spellno==1 * first spell, monthly contract, and no subsidy (column 7) count if endsp==1 & spellno==1 & contrbg2==1 & pricmth>=70 sum totprice inittot mthavpr yravpr mthavat yravat mthno yrno frzno female age corpor student if contrbg2==1 & spellno==1 & pricmth>=70 * first spell, annual contract, and no subsidy (column 8) count if endsp==1 & spellno==1 & contrbg2==2 & pricmth>=58 sum totprice inittot mthavpr yravpr mthavat yravat mthno yrno frzno female age corpor student if contrbg2==2 & spellno==1 & pricmth>=58 ************************************************************** * Table 3: Price per Attendance in first 6 months (monthly) and first year (annual) ************************************************************** use GymDataFinalAERRatio,clear *** Monthly contract, unsubsidized users * Count observations su attmt0 if (pricmth>=70 & begsp==1 & contrbg==1 & datt==1) *** Generate month-by-month figures reg varmth1m datt dpr if (pricmth>=70 & begsp==1 & contrbg==1), robust nocons outreg using Table3, title(Table 3) ctitle(Disregard) se noaster bdec(4) replace forvalues i=1/6 { * Price and Attendance reg varmth`i'm datt dpr if (pricmth>=70 & begsp==1 & contrbg==1), robust nocons outreg datt dpr using Table3, ctitle(Month`i',uns) se noaster bdec(4) append } forvalues i=1/6 { * Ratio: Price per attendance cap reg varmth`i'm datt dpr if (pricmth>=70 & begsp==1 & contrbg==1), robust nocons display "Price per average attendance in month `i', monthly contract" nlcom _b[dpr]/_b[datt] } *** Generate summary for first 6 months foreach i in 0 { * Price and Attendance reg varmth`i'y datt dpr if (pricmth>=70 & begsp==1 & contrbg==1), robust nocons outreg datt dpr using Table3, ctitle(Mth0-6,uns) se noaster bdec(4) append } foreach i in 0 { * Ratio: Price per attendance cap reg varmth`i'y datt dpr if (pricmth>=70 & begsp==1 & contrbg==1), robust nocons display "Price per average attendance in 6-month period `i', monthly contract" nlcom _b[dpr]/_b[datt] } *** Annual contracts, unsubsidized users * Count observations su attyr1 if (pricmth>=58 & begsp==1 & contrbg==2 & datt==1) foreach i in 1 { * Price and Attendance reg varyr`i'y datt dpr if (pricmth>=58 & begsp==1 & contrbg==2), robust nocons outreg datt dpr using Table3, ctitle(Yr1,uns) se noaster bdec(4) append } foreach i in 1 { * Ratio: Price per attendance cap reg varyr`i'y datt dpr if (pricmth>=58 & begsp==1 & contrbg==2), robust nocons display "Price per average attendance in year `i', annual contract" nlcom _b[dpr]/_b[datt] } ************************************************************** * Table 4 - Distribution of Attendance and Price per Attendance over initial period. Unsubsidized Sample ************************************************************** use GymDataFinalAER,clear * Monthly contract -- Columns 1 and 2 centile attmt0 prperatt0 if (pricmth>=70 & begsp==1 & contrbg==1),centile(10 20 25 50 75 90 95) * Annual contract -- Columns 3 and 4 centile attyr1 pratyr1d if (pricmth>=58 & begsp==1 & contrbg==2),centile(10 20 25 50 75 90 95) ************************************************************** * Table 5 - Average Initial Attendance in Monthly and Annual Contracts * Document sorting ************************************************************** *** Monthly contract reg atten2 if begsp==1 & contrbg==1 outreg using Table5, title(Table 5) ctitle(m,att2) se noaster bdec(4) replace reg atten3 if begsp==1 & contrbg==1 outreg using Table5, ctitle(m,att3) se noaster bdec(4) append reg atten4 if begsp==1 & contrbg==1 outreg using Table5, ctitle(m,att4) se noaster bdec(4) append *** Annual contract reg atten2 if begsp==1 & contrbg==2 outreg using Table5, ctitle(y,att2) se noaster bdec(4) append reg atten3 if begsp==1 & contrbg==2 outreg using Table5, ctitle(y,att3) se noaster bdec(4) append reg atten4 if begsp==1 & contrbg==2 outreg using Table5, ctitle(y,att4) se noaster bdec(4) append ************************************************************** * Table 6 - Probit of renewal decision ************************************************************** use GymDataFinalAER,clear *column 1 dprobit d14g contrbgd if age~=.& female~=.& begsp==1, robust outreg contrbgd using Table6, title(Table 6: Probit of Renewal Decision) ctitle(no controls) se 3aster bdec(4) replace predict phat13 if contrbgd==0 *column 2 dprobit d14g contrbgd female age agesq corpor student $month if age~=.& female~=.& begsp==1, robust outreg contrbgd female age agesq corpor student using Table6, ctitle(controls + time dummies) se 3aster bdec(4) append predict phat14 if contrbgd==0 *column 3 dprobit d15g contrbgd if age~=.& female~=.& begsp==1, robust outreg contrbgd using Table6, ctitle(no controls) se 3aster bdec(4) append predict phat15 if contrbgd==0 *column 4 dprobit d15g contrbgd female age agesq corpor student $month if age~=.& female~=.& begsp==1, robust outreg contrbgd female age agesq corpor student using Table6, ctitle(controls + time dummies) se 3aster bdec(4) append predict phat16 if contrbgd==0 *column 5 dprobit d26g contrbgd if age~=.& female~=.& begsp==1, robust outreg contrbgd using Table6, ctitle(no controls) se 3aster bdec(4) append predict phat17 if contrbgd==0 *column 6 dprobit d26g contrbgd female age agesq corpor student $month if age~=.& female~=.& begsp==1, robust outreg contrbgd female age agesq corpor student using Table6, ctitle(controls + time dummies) se 3aster bdec(4) append predict phat18 if contrbgd==0 *column 7 dprobit d27g contrbgd if age~=.& female~=.& begsp==1, robust outreg contrbgd using Table6, ctitle(no controls) se 3aster bdec(4) append predict phat19 if contrbgd==0 *column 8 dprobit d27g contrbgd female age agesq corpor student $month if age~=.& female~=.& begsp==1, robust outreg contrbgd female age agesq corpor student using Table6, ctitle(controls + time dummies) se 3aster bdec(4) append predict phat20 if contrbgd==0 *column 9 dprobit d14g contrbgd if age~=. & female~=. & begsp==1 & ((pricmth>=70 & contrbg==1)|(pricmth>=58 & contrbg==2)), robust predict phat21 if contrbgd==0 outreg contrbgd using Table6, ctitle(no controls) se 3aster bdec(4) append *column 10 dprobit d14g contrbgd female age agesq corpor student $month if age~=.& female~=.& begsp==1& ((pricmth>=70 & contrbg==1)|(pricmth>=58 & contrbg==2)), robust outreg contrbgd female age agesq corpor student using Table6, ctitle(controls + time dummies) se 3aster bdec(4) append predict phat22 if contrbgd==0 *column 11 dprobit d14g contrbgd if age~=. & female~=. & begsp==1 & ((pricmth>=60 & contrbg==1)|(pricmth>=50 & contrbg==2)), robust predict phat23 if contrbgd==0 outreg contrbgd using Table6, ctitle(no controls) se 3aster bdec(4) append *column 12 dprobit d14g contrbgd female age agesq corpor student $month if age~=.& female~=.& begsp==1& ((pricmth>=60 & contrbg==1)|(pricmth>=50 & contrbg==2)), robust outreg contrbgd female age agesq corpor student using Table6, ctitle(controls + time dummies) se 3aster bdec(4) append predict phat24 if contrbgd==0 *renewal probability for monthly=0 sum phat* if age~=. & female~=. & begsp==1 & spellno~=., sep(0) ***************************************************************** * Table 7 - Attendance and Price per Average Attendance Over Time ***************************************************************** use GymDataFinalAERRatio,clear *** Monthly contract, unsubsidized users *** Generate 6 month-by-6 month figures * First spell of unsubsidized monthly users (columns 1-3) reg varmth0y datt dpr if (pricmth>=70 & begsp==1 & contrbg==1), robust nocons outreg using Table7, title(Table 7) ctitle(Disregard) se noaster bdec(4) replace forvalues i=0/3 { * Price and Attendance reg varmth`i'y datt dpr if (pricmth>=70 & begsp==1 & contrbg==1), robust nocons outreg datt dpr using Table7, ctitle(Mthly`i',uns) se noaster bdec(4) append } forvalues i=0/3 { * Ratio: Price per attendance cap reg varmth`i'y datt dpr if (pricmth>=70 & begsp==1 & contrbg==1), robust nocons display "Price per average attendance in 6-month period `i', monthly contract" nlcom _b[dpr]/_b[datt] } * First spell of all monthly users (columns 4-6) forvalues i=0/3 { * Price and Attendance reg varmth`i'y datt dpr if (begsp==1 & contrbg==1), robust nocons outreg datt dpr using Table7, ctitle(Mthly`i',all) se noaster bdec(4) append } forvalues i=0/3 { * Ratio: Price per attendance cap reg varmth`i'y datt dpr if (begsp==1 & contrbg==1), robust nocons display "Price per average attendance in 6-month period `i', monthly contract" nlcom _b[dpr]/_b[datt] } *** Annual contracts, unsubsidized users *** Generate Year 1 and Year 2 figures * First spell of unsubsidized annual users (columns 1-3) foreach i in 1 2 { * Price and Attendance reg varyr`i'y datt dpr if (pricmth>=58 & begsp==1 & contrbg==2), robust nocons outreg datt dpr using Table7, ctitle(Yrly`i',uns) se noaster bdec(4) append } foreach i in 1 2 { * Ratio: Price per attendance cap reg varyr`i'y datt dpr if (pricmth>=58 & begsp==1 & contrbg==2), robust nocons display "Price per average attendance in year `i', annual contract" nlcom _b[dpr]/_b[datt] } *First spell of all annual users (columns 4-6) foreach i in 1 2 { * Price and Attendance reg varyr`i'y datt dpr if (begsp==1 & contrbg==2), robust nocons outreg datt dpr using Table7, ctitle(Yrly`i',all) se noaster bdec(4) append } foreach i in 1 2 { * Ratio: Price per attendance cap reg varyr`i'y datt dpr if (begsp==1 & contrbg==2), robust nocons display "Price per average attendance in year `i', annual contract" nlcom _b[dpr]/_b[datt] } ***************************************************************** * OTHER RESULTS MENTIONED IN PAPER ***************************************************************** use GymDataFinalAER,clear ************** Section 2 * Survey on Boston-area health clubs -- See DellaVigna and Malmendier, QJE 2002. ************** Section 3 * Survey on expectations of attendance * See Excel file "HealthClubSurveyResultsSep02.xls" * Text of survey question is "Survey Questionnaire on Health Club Attendance Aug2002.doc" ************** Section 3.2 -- Compare paying $12 per visit and getting 10-visit pass su tenpass su totatt2 * Ratio of the two is $10.91 ************** Section 3.2, page 9 -- also page 7, footnote and Intro. ** Loss for monthly contract -- Compare to total expenditure reg totglos if (pricmth>=70 & month<=7 & contrbg2==1 & begsp==1) reg totprice if (pricmth>=70 & month<=7 & contrbg2==1 & begsp==1) ** Loss for annual contract reg totglos if (pricmth>=58 & month<=7 & contrbg2==2 & begsp==1) reg totprice if (pricmth>=58 & month<=7 & contrbg2==2 & begsp==1) ************** Section 3.2, Underrecording of Attendance ************** Section 3.2, Percent that rents Lockers su dlockersp if spellno==1 ************** Section 5, Footnote 26 su dswitch if contrbg==1 & spellno==1 ************** Section 5, Footnote 26 * Generates result on health insurance use GymDataFinalAERRatio,clear * Count observations su attmt0 if (begsp==1 & contrbg==1 & hinsur==1 & datt==1) * Generate summary for first 6 months foreach i in 0 { * Price and Attendance reg varmth`i'y datt dpr if (begsp==1 & contrbg==1 & hinsur==1), robust nocons } foreach i in 0 { * Ratio: Price per attendance cap reg varmth`i'y datt dpr if (begsp==1 & contrbg==1 & hinsur==1), robust nocons display "Price per average attendance in 6-month period `i', monthly contract" nlcom _b[dpr]/_b[datt] } log close