-
Notifications
You must be signed in to change notification settings - Fork 5
/
program-list.do
1880 lines (1556 loc) · 51.9 KB
/
program-list.do
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
program define date2string , rclass
version 14
syntax varlist(max=1) , gen(string) [drop]
tokenize `varlist'
tempvar day month year
gen `day' = day(`1')
gen `month' = month(`1')
gen `year' = year(`1')
qui tostring `day' `month' `year' , replace
gen `gen' = `month' + "/" + `day' + "/" + `year'
drop `year' `month' `year'
if "`drop'" == "drop"{
drop `1'
}
end
program esttab2 , rclass
version 14
// This extension is experimental.
//Known issues:
// Can only accept one line of addnotes
syntax , file(string asis) [addnotes(string) debug option(string asis) ///
title(string asis)]
if "`title'" == ""{
local titleloc ""
}
else {
local titleloc "title(`title')"
}
if "`addnotes'" == ""{
local addnotesloc ""
}
else {
local addnotesloc "addnotes(`addnotes')"
}
esttab using "`file'" , se label ///
replace ///
b(4) se(4) `addnotesloc' `option' `titleloc'
if "`debug'" == "" {
project , creates("`file'") preserve
}
eststo clear
end
program evstudy , rclass
version 14
syntax varlist [if], basevar(string) periods(string) ///
varstem(varlist min=1 max=1) [absorb(varlist) ///
bys(varlist min=1) cl(varlist min=1) connected datevar(varlist min=1 max=1) debug ///
file(string) force generate kernel kopts(string) leftperiods(string) ///
maxperiods(string) mevents nolabel omit_graph ///
othervar(varlist min=2 max=2) overlap(string) qui ///
regopts(string) tline(string) surround twopts(string)]
*----------------------- Checks ---------------------------------------------
// Verify that tsperiods is installed
capture findfile tsperiods.ado
if "`r(fn)'" == "" {
di as error "user-written package 'tsperiods' needs to be installed first;"
exit 498
}
// Verify that regsave is installed
capture findfile regsave.ado
if "`r(fn)'" == "" {
di as error "user-written package 'regsave' needs to be installed first;"
exit 498
}
// Verify that graph2 is installed
capture findfile graph2.ado
if "`r(fn)'" == "" {
di as error "user-written package 'graph2' needs to be installed first;"
exit 498
}
// Verify that timedummy exists
capture findfile timedummy.ado
if "`r(fn)'" == "" {
di as error "user-written package 'timedummy' needs to be installed first;"
exit 498
}
// Verify that no variable called 'myevent' exists
if "`generate'" == "generate" {
capture confirm variable myevent
if !_rc {
di "{err}Please drop variable 'myevent'. Evstudy uses this object to temporary store information"
exit
}
}
// Check if absorb is empty
local abscount = 0
foreach var in `absorb'{
local `abscount++'
}
// Check if bys is empty
local byscount = 0
foreach var in `bys'{
local `byscount++'
}
// Check if cl is empty
local clcount = 0
foreach var in `cl'{
local `clcount++'
}
// Check that connected and kernel not used together
if "`connected'" == "connected" & "`kernel'" == "kernel" {
di "{err} 'connected' and 'kernel' cannot both be specified"
exit
}
// Check if datevar is empty
local datecount = 0
foreach var in `datevar'{
local `datecount++'
}
// Check if othervar is empty
local othervarcount = 0
foreach var in `othervar'{
local `othervarcount++'
}
// Verify that if option generate was selected, then bys and datevar specified
if "`generate'" == "generate"{
if `byscount' == 0 | `datecount' == 0{
di "{err}Need to specify bys and datevar if option generate is specified"
exit
}
}
// If user specified overlap, check if user also specified mevents
// Verify that overlap is a positive integer
if "`overlap'" != "" & "`mevents'" == "" {
di "{err}Need to specify 'mevents' if 'overlap' is specified"
exit
// Verify that periods is a positive integer
if `overlap' <= 0{
di "{err}overlap has to be a positive integer"
exit
}
if `overlap' != int(`periods'){
di "{err}overlap has to be an integer"
exit
}
}
// If user specified omit_graph, check that filename is not specified
if "`omit_graph'" == "omit_graph" & "`file'" != "" {
di "{err}Cannot specify 'file' with option 'omit_graph'"
exit
}
// Warn user that in kernel graphs only time coefficients are plotted
if "`kernel'" == "kernel" {
if "`surround'" == "surround" | `othervarcount' > 0 {
di as error "`surround' `othervar' will be included in estimation but the coefficients will NOT be ploted"
}
}
// Verify that periods is a positive integer
if "`maxperiods'" != "" {
if `maxperiods' <= 0{
di "{err}overlap has to be a positive integer"
exit
}
}
// Warn user if panel is unbalanced
sort `bys' `datevar'
tempvar diffdate
by `bys': gen `diffdate' = `datevar' - `datevar'[_n-1]
qui su `diffdate'
local max = r(max)
if `max' > 1 {
di as error "Warning: panel might be unbalanced"
}
drop `diffdate'
*----------------------- Checks ---------------------------------------------
*----------------------- Definitions ----------------------------------------
// Create local for absorb
if `abscount' >0{
local abslocal "absorb(`absorb')"
}
else {
local abslocal "noabsorb"
}
// Define cluster variable
if `clcount' > 0 {
local cluster "cl(`cl')"
}
// Optionally connect graph
if "`connected'" == "connected" {
local connected "recast(connected)"
}
// Define capture (for use with force option)
if "`force'" == "force" & "`generate'" == ""{
di "{err}Option force can only be specified with option generate"
exit
}
if "`nolabel'" == "" {
// Obtain name of dependant variable
local depvar `: word 1 of `varlist''
// Store label
local label_loc : var label `depvar'
local ylabel_loc "ytitle(`label_loc')"
}
// Define tline if one is specified
if "`tline'" != "" {
local tlineval "tline(`tline', lp(solid) lc(red))"
}
// Define periods to the left, if not specified
if "`leftperiods'" == "" {
local leftperiods = `periods'
}
*----------------------- Definitions ----------------------------------------
*----------------------- Generate variables----------------------------------
// Optionally build leads and lags
if "`generate'" == "generate"{ // BEGIN GENERATE LEADS AND LAGS
if "`overlap'" != "" { // If overlap was specified
capture confirm variable overlap // check if overlap was already defined
if "`force'" == "" { // If option force was not specified and variable overlap exists throw error
if !_rc {
di "{err}Variable 'overlap' is already defined."
di "{err}Option 1: drop variable 'overlap'."
di "{err}Option 2: omit 'generate' option."
di "{err}Option 3: specify 'force option'."
exit
}
}
if _rc { // If variable overlap doesn't exist, create it
local overlaploc "overlap(`overlap')"
}
}
// Determine if it's necessary to generate periods dummies or not
// Check whether user specified 'generate', but not 'force', and still the variable exists
local period_dummies_required "FALSE"
forvalues i = 1(1)`leftperiods' {
capture confirm variable `varstem'_f`i'
if _rc { // If it doesn't exist flag to generate
local period_dummies_required "TRUE"
}
else if "`force'" == ""{
di "{err}Variable `varstem'_f`i' already specified"
exit
}
}
forvalues i = 1(1)`periods' {
capture confirm variable `varstem'_l`i'
if _rc { // If it doesn't exist flag to generate
local period_dummies_required "TRUE"
}
else if "`force'" == ""{
di "{err}Variable `varstem'_l`i' already specified"
exit
}
}
if "`surround'" == "surround" {
foreach type in pre post {
capture confirm variable `varstem'_`type'
if _rc {
local period_dummies_required "TRUE"
}
else if "`force'" == ""{
di "{err}Variable `varstem'_`type' already specified"
exit
}
}
}
if "`period_dummies_required'" == "TRUE" {
if "`maxperiods'" == "" { // Use heuristic to determine nr of leads and lags if user did not specify
// Compute the absolute maximum number of leads and lags that we could need
tempvar counts maxcounts
bys `bys': gen `counts' = _n
by `bys' : egen `maxcounts' = max(`counts')
qui su `maxcounts'
local maxperiods = r(max)
drop `counts' `maxcounts'
}
// Construct periods to/from event ---------------------------------------------------------------
tsperiods , bys(`bys') datevar(`datevar') maxperiods(`maxperiods') ///
periods(1) event(`varstem') `mevents' name(myevent) `overlaploc'
// Construct periods to/from event ---------------------------------------------------------------
// Prevent STATA from storing myevent variable
tempvar myevent
qui gen `myevent' = myevent
qui drop myevent
timedummy, varstem(`varstem') periods(`periods') leftperiods(`leftperiods') ///
`surround' epoch(`myevent')
qui drop `myevent'
}
} // END GENERATE LEADS AND LAGS
// Include control for overlap if user specified it
if "`overlap'" != "" {
local overlapctrl "overlap"
}
// Build regression parameters in loop
local conditions ""
local regressors ""
// Leads of the RHS correspond to "pre-trend" = before treatment
if `othervarcount' > 0 {
tokenize `othervar'
if "`kernel'" == "" { // Only include in graph if kernel was not selected
local conditions "`conditions' (`1': _b[`1'] - _b[`basevar'])"
}
local regressors "`regressors' `1'"
}
// Include pre and post controls if selected
if "`surround'" == "surround" {
if "`kernel'" == "" { // Only include in graph if kernel was not selected
local conditions "`conditions' (`varstem'_pre: _b[`varstem'_pre] - _b[`basevar'])"
}
local regressors "`regressors' `varstem'_pre"
}
forvalues i = `leftperiods'(-1)1{
local conditions "`conditions' (`varstem'_f`i':_b[`varstem'_f`i']-_b[`basevar'])"
local regressors "`regressors' `varstem'_f`i'"
}
local conditions "`conditions' (`varstem':_b[`varstem']-_b[`basevar'])"
local regressors "`regressors' `varstem'"
// Lags correspond to "post-trends" = after treatment
forvalues i = 1(1)`periods'{
local conditions "`conditions' (`varstem'_l`i':_b[`varstem'_l`i']-_b[`basevar'])"
local regressors "`regressors' `varstem'_l`i'"
}
// Include pre and post controls if selected
if "`surround'" == "surround" {
if "`kernel'" == "" { // Only include in graph if kernel was not selected
local conditions "`conditions' (`varstem'_post: _b[`varstem'_post] - _b[`basevar'])"
}
local regressors "`regressors' `varstem'_post"
}
if `othervarcount' > 0 {
if "`kernel'" == "" { // Only include in graph if kernel was not selected
local conditions "`conditions' (`2':_b[`2']-_b[`basevar'])"
}
local regressors "`regressors' `2'"
}
// ------------------------ Regression -----------------------------------------
`qui' reghdfe `varlist' `regressors' `overlapctrl' `if', `abslocal' `cluster' `regopts'
// Check if any variables were omitted
local numcoef = `periods' + `leftperiods'
forvalues i = 1(1)`numcoef'{
if !missing(r(label`i')) {
if r(label`i') == "(omitted)"{
di "{err}One or more coefficients were omitted"
exit
}
}
}
// Normalize coefficients
`qui' nlcom `conditions', post
est store NL_EVresults
if "`omit_graph'" == "" {
if "`kernel'" == "kernel"{
preserve
regsave
tempvar days post
qui gen `days' = _n
qui replace `days' = `days' - `periods' - 1
qui gen `post' = (`days' >= 0)
graph twoway (scatter coef `days' if !`post', msize(small) graphregion(color(white)) graphregion(lwidth(vthick))) ///
(lpolyci coef `days' if !`post', lcolor(navy) ciplot(rline) `kopts') ///
(scatter coef `days' if `post', msize(small) color(cranberry*0.5)) ///
(lpolyci coef `days' if `post', `tlineval' lcolor(cranberry) ciplot(rline) `kopts') , ///
legend(off) `twopts' `ylabel_loc'
restore
}
else {
coefplot (NL_EVresults, keep(`varstem'_pre) mcolor(dknavy*0.4) ciopts(color(dknavy*0.4))) ///
(NL_EVresults, drop(`varstem'_pre `varstem'_post) mcolor(dknavy) ciopts(color(dknavy))) ///
(NL_EVresults, keep(`varstem'_post) mcolor(dknavy*0.4) ciopts(color(dknavy*0.4))), ///
ci(90) legend(off) offset(0) scale(1.1) yline(0, lp(solid) lc(black*0.4%80)) `tlineval' xsize(8) `connected' ///
vertical xlabel(, angle(vertical)) graphregion(color(white)) `twopts' `ylabel_loc'
}
if "`file'" != "" {
graph2 , file("`file'") `debug'
}
}
endprogram define graph2 , rclass
version 14
syntax , file(string asis) [options(string) debug]
local pngfile = `file' + ".png"
local pdffile = `file' + ".pdf"
graph export "`pngfile'" , replace `options'
graph export "`pdffile'" , replace `options'
if "`debug'" == ""{
project , creates("`pngfile'") preserve
}
end
program define init , rclass
version 14
// Check dependencies
capture findfile project.ado
if "`r(fn)'" == "" {
di as txt "user-written package project needs to be installed first;"
di as txt "use -ssc install project- to do that"
exit 498
}
capture findfile pexit.ado
if "`r(fn)'" == "" {
di as txt "user-written package pexit needs to be installed first;"
di as txt "use -ssc install pexit- to do that"
exit 498
}
capture macro drop debug
syntax [, debug debroute(string) double hard ignorefold logfile(string) omit proj(string) route(string)]
// Clean session
clear all
discard
// Check that user parameters are correct
if "`hard'" == "hard" & ("`debug'" == "debug" | "`omit'" == "omit"){
di "Cannot use option 'hard' with either 'debug' or 'omit'"
error 184
}
// Define global debug and omit
gl deb = "`debug'"
gl omit = "`omit'"
// Optionally set type double
if "`double'" == "double"{
set type double
}
// Set working directory
if ("$deb" == "debug" & "`proj'" != "") { // In debug mode change to route if specified
project `proj' , cd
if "`debroute'" != ""{ // If debroute specified change WD with respect to root directory
cd `debroute'
}
}
else if "`route'" != "" & "$deb" == ""{
cd `route'
}
// If log option set and not in debug mode open logile
if ("$deb" == "" & "`logfile'" != "") {
cap log close
mata : st_numscalar("LogExists", direxists("./log/")) //check if a log directory exists
local LogFolderSpecified = strpos("`logfile'", "log/") + strpos("`logfile'", "log\")
// If directory exists, but wasn't specified by user, then store logfile there
if LogExists == 1 & `LogFolderSpecified' == 0 & "`ignorefold'" == ""{
local logfile = "./log/" + "`logfile'"
}
log using "`logfile'" , replace
}
// Optionally drop all macros
if "`hard'" == "hard"{
macro drop _all
}
end
program define innerevent , rclass
syntax, bys(varlist min=1) datevar(varlist min=1 max=1) ///
eventnr(varlist min=1 max=1) ///
epoch(varlist min=1 max=1) periods(string) [leftperiods(string)]
/*
Define:
- `bys': an ID, an entity that experiences an event (e.g., a newspaper outlet)
- `eventnr': an indicator for the number of event that `bys' experiences
- `lefperiods', `periods': the relevant ("inner") window that we consider
- `epoch': the counter for periods before/after the event(s)
Purpose:
We want to create dummy variables such that
inner_`bys'_`eventnr' = `bys' x `eventnr' x inner_`eventnr'
or in other words:
indicator = ID x nr. of event x {pre-window of interest,
window of interest, post-window of interest}
This program returns 3 variables:
+ `bys'_`eventnr': ID x nr. of event
+ inner_`eventnr': dummy for pre-window of interest (=1), window
of interest (=2), post-window of interst (=3)
+ inner_`bys'_`eventnr': indicator for ID x nr. of event x {pre-window of interest,
window of interest, post-window of interest}
*/
// Check that variables do no exist
foreach var in `bys'_`eventnr' inner_`eventnr' inner_`bys'_`eventnr' {
capture confirm variable `var'
if !_rc { // If 'eventnr' exists and 'mevents' selected, throw exception
di "{err}Please drop variable `var'. innerevent uses this variable name."
exit
}
}
// If `leftperiods' doesn't exist, assume `periods'
if "`leftperiods'" == "" {
local leftperiods = -`periods'
}
// Calculate j: the power of ten that we need to multiply `bys' by
// to generate an ID such that each `bys' has at most one event.
qui su `eventnr'
local max = r(max)
local j = 0
local rest = 1
while `rest' >= 1{
local `j++'
local rest = `max'/10^`j'
}
// `bys'_eventnr: ID for `bys', such that each ID has at most one event
qui gen `bys'_`eventnr' = `bys'*10^`j' + `eventnr'
// For `bys'_`eventnr' with `epoch' that go back before `leftperiods'
// and further than `periods', we want to be able to distinguish
// whether the `bys'_`eventnr' x `epoch' corresponds to the window close
// to the event or not.
tempvar marker nvals
bys `bys'_`eventnr' `epoch': gen `nvals' = _n
qui gen `marker' = (`epoch' == -`leftperiods' & `nvals' == 1 | ///
`epoch' == `periods' + 1 & `nvals' == 1)
sort `bys'_`eventnr' `epoch'
by `bys'_`eventnr': gen inner_`eventnr' = sum(`marker')
qui replace inner_`eventnr' = inner_`eventnr' + 1
// By construction inner_`eventnr' should have values <= 3
qui su inner_`eventnr'
local max = r(max)
if `max' > 3 {
di "{err}Unknown fatal error. Check variable `eventnr'"
exit
}
gen inner_`bys'_`eventnr' = `bys'_`eventnr'*10 + inner_`eventnr'
drop `marker' `nvals'
end
program define isorder , rclass
syntax varlist
tempvar order1 order2
gen `order1' = _n
sort `varlist'
gen `order2' = _n
qui count if `order1' != `order2'
local counts = r(N)
if `counts' == 0{
di "Database ordered according to `varlist'"
local statusval 1
}
else{
di "Database is NOT ordered according to `varlist'"
local statusval 0
}
return local ordered `statusval'
end
program mcompare , rclass
version 14
syntax varlist(min=2)
local counter = 0
foreach var in `varlist'{
local `counter++'
}
token `varlist'
forvalues i=2(1)`counter'{
compare `1' ``i''
}
end
program define merge2 , rclass
version 14
syntax varlist , type(string) file(string asis) ///
[datevar(varlist) tdate(string) ///
fdate(string) moptions(string) ///
idstr(varlist) idnum(varlist) original debug]
// If not in debug mode register project functionality
if "`debug'" == ""{
if "`original'" == "" {
project, uses(`file') preserve
}
else{
project, original(`file') preserve
}
}
// Routine if user selected a DTA file as using file
if strpos(`file', ".dta") > 0{
// Check for invalid options when using DTA files as using file
if "`datevar'" != "" | "`tdate'" != "" | "`fdate'" != "" | "`idstr'" != "" |"`idnum'" != ""{
di "Only variables file, type, varlist, original and debug are allowed when using file is a STATA file."
error 601
}
if "`moptions'" != "" {
merge `type' `varlist' using `file' , `moptions'
}
else {
merge `type' `varlist' using `file'
}
}
else { // Routine if user selected a CSV file as using file
tempfile masterfile usingfile
// Save masterfile and import using file -----------------------------------
save `masterfile'
import delimited using `file' , clear case(preserve)
// If requested string/destring variables
if "`idnumeric'" != ""{
destring `idnumeric' , replace
}
if "`idstring'" != ""{
tostring `idstring' , replace
}
// If requested create a date variable
if "`datevar'" != "" {
tempvar newdate
gen `newdate' = date(`datevar', "`tdate'")
drop `datevar'
gen `datevar' = `newdate'
format `fdate' `datevar'
}
save `usingfile'
// ---------------------------------------------------------------------------
// Load masterfile and perform merge
use `masterfile' , clear
// If requested string/destring variables
if "`idnumeric'" != ""{
destring `idnumeric' , replace
}
if "`idstring'" != ""{
tostring `idstring' , replace
}
// Merge
if "`moptions'" != "" {
merge `type' `varlist' using `usingfile' , `moptions'
}
else {
merge `type' `varlist' using `usingfile'
}
}
end
program define missing2zero , rclass
version 14
syntax varlist [, substitute(string) mean bys(varlist)]
// Check for mixed-types in varlist
local rcSum = 0 // rcSum > 0 indicates at least one string variable
local rcProduct = 1 // rcProduct == 0 indicates at least one numeric variable
local byscount = 0
foreach var in `bys' {
local `byscount++'
}
foreach var in `varlist'{
capture confirm numeric variable `var'
local rcSum = `rcSum' + _rc
local rcProduct = `rcProduct'*_rc
}
if `rcSum' > 0 & `rcProduct' == 0{
di "Cannot mix numeric and string variables"
exit 109
}
if "`substitute'" != "" & "`mean'" == "mean" {
di as error "'substitute' cannot be combined with 'mean'"
exit
}
if `rcSum' > 0 & "`mean'" == "mean" {
di as error "'mean' is not defined for string variables"
exit
}
// Assign default values if none specified
if `rcSum' == 0 & "`substitute'" == ""{ // If numeric variables specified
local substitute = 0
}
else if `rcProduct' > 0 & "`substitute'" == "" { // If string variables specified
local substitute "NaN"
}
foreach var in `varlist'{
capture confirm numeric variable `var' // check type of variable
if _rc == 0 { // If numeric
if "`mean'" == "mean" { // if user wants to fill missing with mean value
tempvar vartemp
if `byscount' > 0 {
bys `bys': egen `vartemp' = mean(`var')
}
else {
egen `vartemp' = mean(`var')
}
qui replace `var' = `vartemp' if missing(`var')
drop `vartemp'
}
else { // if user wants to fill with zero or custom value
recode `var' (. = `substitute')
}
} // If string
else {
qui replace `var' = "`substitute'" if `var' == ""
}
}
end
program define pdo , rclass
version 14
syntax , file(string) [debug quietly]
if "`debug'" == "debug"{
`quietly' do "`file'"
}
else{
project , do("`file'")
}
end
program define pexit , rclass
version 14
capture findfile project.ado
if "`r(fn)'" == "" {
di as txt "user-written package project needs to be installed first;"
di as txt "use -ssc install project- to do that"
exit 498
}
capture findfile init.ado
if "`r(fn)'" == "" {
di as txt "user-written package init needs to be installed first;"
di as txt "use -ssc install init- to do that"
exit 498
}
syntax [, summary(string) debug]
if "`debug'" == ""{
cap log close
if "`summary'" != ""{
eststo clear
estpost summarize _all
esttab using "`summary'" , ///
cells("mean(fmt(2)) sd(fmt(2)) min(fmt(1)) max(fmt(0))") ///
nomtitle nonumber replace
}
}
exit
end
program polgenerate
syntax varlist(numeric) , p(int)
foreach var in `varlist'{
forvalues i = 2(1)`p'{
* Generate variable
cap gen `var'_`i' = `var'^`i'
* Label variable
local lab: variable label `var'
label variable `var'_`i' "`lab', p(`i')"
}
}
end
program define psave , rclass
version 14
// Verify dependencies
capture findfile init.ado
if "`r(fn)'" == "" {
di as txt "user-written package init needs to be installed first;"
di as txt "use -ssc install init- to do that"
exit 498
}
syntax , file(string asis) [clear com csvnone debug eopts(string) ///
old(string) preserve]
if "`clear'" == "clear"{
di "Option clear is ignored in psave"
}
// Drops CSV, DTA file extensions, if any are present
local newfile = subinstr(`file', ".csv", "", .)
local newfile = subinstr("`newfile'", ".dta", "", .)
// Define names for output files
local filecsv = "`newfile'" + ".csv"
local filedta = "`newfile'" + ".dta"
local filedta_old = "`newfile'" + "_v`old'" + ".dta"
// If csvnone is selected, check that CSV file doesn't exist
if "`csvnone'" == "csvnone"{
capture confirm file "`filecsv'"
if _rc ==0{ //If CSV file exists throw exception
di "CSV file already exists. Consider deleting it or avoiding option csvnone."
error 602
}
}
// Optionally compress to save information
if "`com'" == "com"{
qui compress
}
// Save DTA in current format
save "`filedta'" , replace
// Optionally save DTA in old version
if "`old'" != ""{
confirm integer number `old'
saveold "`filedta_old'" , replace version(`old')
}
// If debug and CSVnone are not set, store CSV
if "`debug'" == "" & "`csvnone'" == ""{
export delimited using "`filecsv'", replace `eopts'
project, creates("`filecsv'") `preserve'
}
// Register with project
if "`debug'" == "" & "`csvnone'" == "csvnone"{
project , creates("`filedta'") `preserve'
}
end
program define puse, rclass
version 14
/*
puse tries to read data and register project functionality in the following
order (unless specified otherwise by user):
Read:
1. DTA
2. CSV
3. Excel
project:
1. CSV
2. DTA
3. Excel
*/
capture findfile init.ado
if "`r(fn)'" == "" {
di as txt "user-written package init needs to be installed first;"
di as txt "use -ssc install init- to do that"
exit 498
}
syntax, file(string asis) [clear debug opts(string) original preserve]
if "`preserve'" == "preserve"{
di "Option preserve is ignored in puse"
}
// Generate names of files based on extension
local newfile = subinstr(`file', ".csv", "", .)
local newfile = subinstr("`newfile'", ".dta", "", .)
local filecsv = "`newfile'" + ".csv"
local filedta = "`newfile'" + ".dta"
if strpos(`file', ".xls") > 0{
local filexls = `file'
}
// Check existance of files
capture confirm file "`filedta'"
local dtaExists = _rc
capture confirm file "`filecsv'"
local csvExists = _rc
capture confirm file "`filexls'"
local xlsExists = _rc
local exists = min(`dtaExists', `csvExists', `xlsExists')
if `exists' != 0{
di as error "No files found: `filedta' `filecsv' `filexls'"
error 601
}
// Throw exception if user specifies a file extension, but puse reads a different one.
if strpos(`file', ".csv") > 0 & `dtaExists' == 0{
di as error "CSV specified, but puse reads DTA file."
error 601
}
else if strpos(`file', ".xls") > 0 & `dtaExists' == 0{
di as error "XLS specified, but puse reads DTA file"
error 601
}
else if strpos(`file', ".xls") > 0 & `csvExists' == 0{
di as error "XLS/XLSX specified, but puse reads CSV file"
error 601
}