Notes for SAS programming Econ424 Fall 2009 Why SAS? • Able to process large data set(s) • Easy to cope with multiple variables • Able to track all the operations on the data set(s) • Generate systematic output • Summary statistics • Graphs • Regression results • Most government agencies and private sectors use SAS Where to find SAS? • • The MS Window version of SAS is only available on campus – class website, “computer resources”, “On-campus computer lab” – list computer lab location, hours and software You can access SAS remotely via glue.umd.edu, but you cannot use the interactive windows – use a secured telnet (e.g. ssh) to remotely login glue.umd.edu with your directory ID and password – type “tap sas” to tell the system that you want to access SAS – use any text editor (say pico) to edit your sas program (say myprog.sas). You can also create the text-only .sas file in your PC and (securely) ftp it into glue. – In glue, type “sas myprog.sas &” will send the sas program to run in the background. – The computer will automatically generate myprog.log to tell you how each command runs in sas. If your program produces any output, the output will be automatically saved in myprog.lst. All in the same directory as your .sas file. Roadmap • • • • • • • • Thinking in “SAS” Basic rules Read in data Data cleaning commands Summary statistics Combine two or more datasets Hypothesis testing Regression Thinking in “SAS” • What is a program? – Algorithm, recipe, set of instructions • How is programming done in SAS? – SAS is like programming in any language: • Step by step instructions • Can create your own routines to process data • Most instructions are set up in a logical manner – SAS is NOT like other languages: • Some syntax is peculiar to SAS • Written specifically for statistics so it isn’t all-purpose • Canned processes that you cannot edit nor can you see the code Thinking in “SAS” • Creating a program – What is your problem? (take project 3 as an example) – How can you find a solution? – What steps need to be taken to find an answer? • Do I need to read in data? – What variables do I need? – Where is the data? – What format is the data in? • How do I need to clean the data? – Are there outliers? – Are there any unexpected values in the data? • How do I need to transform the data? – Are the variables in the form that I need? Basic rules (1) – organize files • • • • • .sas – program file .log – notes, errors, warnings .lst – output .sas7bdat – data file library – a cabinet to put data in – Default: Work library • temporary, erased after you close the session – Permanent library • libname mylib “m:\”; • mylib.mydata = a sas data file named “mydata” in library “mylib” • run and recall .sas Basic rules (2) -- program • every command ends with ; • format does not matter if x=1 then y=1; else y=2; is the same as if x=1 then y=1; else y=2; • case insensitive • comment * this is comment; /* this is comment */; Basic rule (3) – variable • Type – numeric (default, 8 digit, . stands for missing value) – character ($, default 8 digit, blank stands for missing) • Variable names – <=32 characters if SAS 9.0 or above – <=8 characters if SAS 8 or below – case insensitive • Must start with letter or “_” _name, my_name, zip5, u_and_me -name, my-name, 5zip, per%, u&me, my@w, my$sign Basic rules (4) – data step • Data step create a new data set called “newdata” in the temporary library DATA newdata; use the data set called “proj3rawdata” in set proj3rawdata; the temporary library fracuninsured=uninsured/total; percentuninsured=fracuninsured*100; run; Define new variables input data “proj3rawdata” obs1 obs2 … obs n define “fracuninsured” define “percentuninsured” output data “newdata” obs1 … obs n Basic rules (5) – proc step • PROC step Action PROC PRINT data=newdata; var fracuninsured percentuninsured; title “print out new data”; run; Signal the end of PROC step, could be ignored if this is followed by a Data or Proc step Data source Read in data (1) – table editor • Tools – table editor • choose an existing library or define a new library • rename variable • save as Read in data (2) – by program • Data format – – – – Datalines (enter the data in the program) Existing data text, comma or tab delimited Existing data text, fixed width From an existing excel file • The following several slides won’t be covered in class. But you are welcome to use them by yourselves. Read in data (2) -- datalines data testdata1; infile datalines; input id height weight gender $ age; datalines; 1 68 144 M 23 2 78 . M 34 No ; until you finish all 3 62 99 F 37 the data lines ; /* you only need one semicolon at the end of all data lines, but the semicolon must stand alone in one line */ proc contents data=testdata1; run; proc print data=testdata1; run; Read in data (3) – more datalines /* read in data in fixed columns */ data testdata1; infile datalines; input id 1 height 2-3 weight 4-6 gender $7 age 8-9; datalines; 168144M23 278 M34 36299 F37 ; Read in data (4) – more datalines data testdata1; infile datalines; input id : 1. height : 2. weight : 3. gender : $1. age : 2.; datalines; 1 68 144 M 23 2 78 . M 34 3 62 99 F 37 ; Read in data (4) – more datalines *alternatively; data testdata1; infile datalines; informat id 1. height 2. weight 3. gender $1. age 2.; input id height weight gender age; datalines; 1 68 144 M 23 2 78 . M 34 3 62 99 F 37 ; Read in data (5) – .csv data testdata1; infile datalines dlm=‘,’ dsd missover; /* what if you do not have dsd and/or missover */ input id height weight gender $ age ; datalines; 1, 68, 144, M, 23 2, 78, , M, 34 3, 62, 99, F, 37 ; /* what if you forget to type 23 */ run; Read in data (6) – .csv file /* save the project 3 cleaned raw data in a comma delimited file (.csv) in M:\ before running the following codes */ Restrict your filename <=8 characters libname mylib "M:\"; filename mycsv "M:\project3-rawdata-cleaned.csv"; data mylib.proj3rawdata; Be consistent with yourself infile mycsv firstobs=2 dlm=',' dsd missover lrecl=900; input year: 4. state: $2. total insured uninsured; Be consistent with yourself run; proc contents data=mylib.proj3rawdata; run; proc print data=mylib.proj3rawdata; run; Note the options in the infile command! Read in data (7) – from excel filename myexcel “M:\project3-rawdata-cleaned.xls”; proc import datafile=myexcel out=proj3rawdata2 DBMS=excel replace; run; No ; until data proj3rawdata3; Be consistent with yourselfthe end of set proj3rawdata2; the whole fracuninsured=uninsured/total; sentence percentuninsured=fracuninsured*100; run; proc contents data=proj3rawdata2; run; proc print data=proj3rawdata2; run; proc contents data=proj3rawdata3; run; proc print data=proj3rawdata3; run; 21 Read in data (7) – from excel Be careful ! SAS will read the first line as variable names, and assume the raw data start from the second row. SAS assigns numeric and character type automatically. Sometime it does make mistake. 22 Data cleaning (1) – if then Format: IF condition THEN action; ELSE IF condition THEN action; ELSE action; Note: (1) the if-then-else can be nested as many as you want (2) if you need multiple actions instead of one action, use “DO; action1; action2; END; ” Data cleaning (1) – if then • • • • • • • = ~= > < >= <= in or or or or or or EQ NE GT LT GE LE means equals means not equal means greater than means less than means greater than or equal means less than or equal means subset – if gender in (‘M’, ‘F’) then ..; • Multiple conditions: AND (&), OR(|) Data cleaning (1) – if then *reading in program of proj3rawdata3 is on page 21; data proj3rawdata3; set proj3rawdata3; IF fracuninsured<0.15 THEN uninsuregrp=0; ELSE uninsuregrp=1; run; proc contents data=proj3rawdata3; run; proc print data=proj3rawdata3; run; Note: (1) the code is less efficient if you replace ELSE ..; with IF fracuninsured>=0.15 THEN ..; (2) missing value is always counted as the smallest negative, so fracuninsured=. will satisfy the condition fracuinsured<0.15. If you want to ignore the missing obs set the condition as 0<=fracuninsured<0.15. Data cleaning (1) – if then * Multiple actions in each branch; data proj3rawdata3; set proj3rawdata3; IF fracuninsured<0.15 AND uninsured>1000000 THEN DO; uninsuredgrp=0; uninsuredpop=‘over 1 million'; END; the do-end pair ELSE DO; acts as brackets uninsuredgrp=1; uninsuredpop=‘less than 1 million'; END; run; proc print data=proj3rawdata3; run; Data cleaning (1) – if then *Use if commands to choose a subsample; data proj3subsample; /* note here we generate a new data set */ set proj3rawdata3; IF fracuninsured=. Then delete; If fracuninsured<=0.1; run; proc print data=proj3subsample; run; Data cleaning (1) – exercise still use proj3rawdata. define newgrp = 1 if fracuninsured <0.1 (low) 2 if 0.1<=fracuninsured<0.15 (mid-low) 3 if 0.15<=fracuninsured<0.2 (mid-high) 4 if fracuninsured>=0.2 (high). Data cleaning (1) – exercise answer data proj3rawdata3; set proj3rawdata3; if fracuninsured<0.1 then newgrp=1; else if fracuninsured<0.15 then newgrp=2; else if fracuninsured<0.2 then newgrp=3; else newgrp=4; run; proc contents data=proj3rawdata3; run; proc print data=proj3rawdata3; run; Question: What if one observation has fracuninsured=.? Save data * Save in sas format; libname mylib “M:\”; data mylib,proj3rawdata3; set proj3rawdata3; run; * Export data to excel; Proc export data=proj3rawdata3 outfile=“M:\proj3data-fromsas.xls” dbms=excel replace; Run; No ; here You can also export a sas data file into a comma delimited text file if you write dbms=csv. Pages 31-34 are optional material for data cleaning. They are not required, but you may find them useful in the future. We skip them in the regular class. Data cleaning (2) – convert variable type Numeric to character: age1=put(age, $2.); age and age1 have the same contents but different formats Character to numeric: age2=input(age1, 1.); now age and age2 are both numeric, but age2 is chopped at the first digit Take a sub string of a character age3=substr(age1,2,1); now age3 is a sub string of age1, starting from the second digit of age1 (the meaning of “2”) and having one digit in total (the meaning of “1”). Data cleaning (2) - example * we want to convert studid 012345678 to 012-345-678; data testdata2; infile datalines; input studid : 9. studname : $1.; datalines; 012345678 A 135792468 B 009876543 C ; proc print; run; data testdata2; set testdata2; if studid LT 1E+7 then studid1= '00’||compress(put(studid, $9.)); else if 1E+7 LE studid LT 1E+8 then studid1='0'||compress(put(studid, $9.)); else studid1= put(studid, $9.); studid2=substr(studid1,1,3)||'-'||substr(studid1,4,3)||''||substr(studid1,7,3); proc print; run; Data cleaning (2) - exercise You have the following data, variables in sequence are SSN, score1, score2, score3, score4, score5: 123-45-6789 100 98 96 95 92 344-56-7234 69 79 82 65 88 898-23-1234 80 80 82 86 92 Calculate the average and standard deviation of the five scores for each individual. Use if-then command to find out who has the highest average score, and report his SSN without dashes. Data summary roadmap • • • • • • • • • Proc contents – variable definitions Proc print – raw data Proc format – make your print look nicer Proc sort – sort the data Proc means – basic summary statistics Proc univariate – detailed summary stat Proc freq – frequency count Proc chart – histogram proc plot – scatter plot proc format (1) *Continue the data cleaning exercise on page 29; Defining “group” as a data proj3rawdata3; numeric variable will save space set proj3rawdata3; if fracuninsured<0.1then newgrp=1; else if fracuninsured<0.15 then newgrp=2; else if fracuninsured<0.2 then newgrp=3; else newgrp=4; run; proc format (2) proc format; value newgroup 1=‘low’ 2=‘mid-low’ no ; here until 3=‘mid-high’ the end of the 4=‘high’; value command run; proc print data=proj3rawdata3; format newgrp newgroup. fracuninsured 4.2; title ‘report new group in words’; no ; here until label fracuninsured=‘fraction uninsured’ the end of the newgrp=‘new group 1-4’; var fracuninsured newgrp; label command run; proc sort proc sort data=proj3rawdata3; by year state; run; proc sort data=proj3rawdata3 out=proj3rawdata3_sorted; by year descending fracuninsured; run; * note that missing value is always counted as the smallest; proc means and proc univariate proc means data=proj3rawdata3; class newgrp; var insured uninsured fracuninsured; run; By default, proc means report mean, stdev, min, max Could choose what to report: proc means data=proj3rawdata3 n mean median; proc sort data=proj3rawdata3; by newgrp; run; proc univariate data=proj3rawdata3; by newgrp; var insured uninsured fracuninsured; run; By default, proc univariate report median, and many other statistics Notes on proc means and proc univariate *if you do not use class or by command, the statistics are based on the full sample. If you use class or by var x, the statistics are based on the subsample defined by each value of var x. *You can use class or by in proc means, but only by in proc univariate; *whenever you use “by var x”, the data set should be sorted by var x beforehand; proc means and proc univariate allow multiple groups data proj3rawdata3; set proj3rawdata3; if totalpop<6000000 then popgrp=“low”; else popgrp=“high”; run; proc means data=proj3rawdata3; class newgrp popgrp; var fracuninsured; run; proc sort data=proj3rawdata3; by newgrp popgrp; run; proc univariate data=proj3rawdata3; by newgrp popgrp; var fracuninsured; run; proc freq * Remember we already generate a variable called newgrp to indicate categories of fraction uninsured and a variable called popgrp to indicate categories of population size; proc freq data=proj3rawdata3; tables newgrp One dimension frequency table popgrp newgrp*popgrp; run; Two-dimension frequency table proc chart – histogram for categorical variables proc chart data=proj3rawdata3; title ‘histogram for newgrp’; vbar newgrp; run; proc chart data=proj3rawdata3; title ‘frequency by two variables’; vbar newgrp / group=popgrp; run; proc chart – histogram for continuous variable proc chart data=proj3rawdata3; title “histogram for continuous variable’; vbar fracuninsured; run; proc chart data=proj3rawdata3; title ‘histogram with specific midpoints’; vbar fracuninsured / midpoints=0 to 1 by 0.05; run; proc plot – scatter plot proc plot data=proj3rawdata3; title ‘scatter plot of fracuninsured and totalpop’; plot fracuninsured*totalpop; run; scatter plot is less informative for categorical variables proc plot data=proj3rawdata3; title ‘scatter plot of newgrp and popgrp’; plot newgrp*popgrp; run; fancy proc means proc means data=proj3rawdata3; class newgrp popgrp; var uninsured fracuninsured; output out = summary1 mean = avguninsured avgfracuninsured; run; proc print data=summary1; run; The following page may be useful in practice, but I am not going to cover it in class. some summary stat. in proc print * Assume we have already defined newgrp and popgrp in proj3rawdata3; proc sort data=proj3rawdata3; by popgrp; run; proc print data=proj3rawdata3 n; where fracuninsured>=0.1; by popgrp; sum totalpop; var totalpop insured uninsured fracuninsured; run; How to handle multiple data sets? • Add more observations to an existing data and the new observations follow the same data structure as the old one append • Add more variables to an existing data and the new variables refer to the same subjects as in the old data merge • Sometimes we may need to change data structure to fit in append or merge …. merge and append proj3rawdata3: year state totalpop … fracuninsured newgrp popgrp 2009 MA 6420947 … 0.0548 summary1: newgrp 1 1 high popgrp avguninsured avgfracuninsured high 7500000 0.073 merged: year state totalpop ….fracuninsured newgrp popgrp avguninsure avgfracuninsured 2009 MA 6420947 … 0.0548 1 high 7500000 0.073 appended: year state totalpop ….fracuninsured newgrp popgrp avguninsure avgfracuninsured 2009 MA 6420947 … 0.0548 1 high . . . . . 1 high 7500000 0.073 merge two datasets proc sort data=proj3rawdata3; by newgrp popgrp; run; proc sort data=summary1; by newgrp popgrp; run; data merged; merge proj3rawdata3 (in=one) summary1 (in=two); by newgrp popgrp; if one=1 & two=1; What if this line is run; “if one=1 OR two=1;”? Keep track of matched and unmatched records data allrecords; merge proj3rawdata3 (in=one) summary1 (in=two); by newgrp popgrp; myone=one; SAS will drop variables mytwo=two; “one” and “two” if one=1 or two=1; automatically at the end of run; the DATA step. If you want proc freq data=allrecords; to keep them, you can copy tables myone*mytwo; them into new variables “myone” and “mytwo” run; be careful about merge! • always put the merged data into a new data set • must sort by the key variables before merge • ok for one-to-one, multi-to-one, one-to-multi, but no good for multi-to-multi • be careful of what records you want to keep, and what records you want to delete • what if variable x appears in both datasets, but x is not in the “by” statement? – after the merge x takes the value defined in the last dataset of the “merge” statement append data appended; set proj3rawdata3 summary1; run; proc print data=appended; run; proc print data=merged; run; Class example of merge and append: reshape and summarize Task1: reshape proj3rawdata3 from long to wide Task2: generate average fracuninsured per state and merge it back to the main data Source format of Proj3rawdata3 (long): year state totalpop fracuninsured …. 2009 MA 6420947 0.0548 …. 2009 HI 1257622 0.078 …. …. 2008 MA 6339513 0.0536 …. 2008 HI 1267409 0.075 ….. Target format (wide) state totalpop2009 fracuninsured2009 . .. Totalpop2008 MA 6420947 0.0548 …. 6339513 HI 1257622 0.078 …. 1267409 fracuninsured2008 ….. 0.0536 …… 0.075 …….. Main data issues • From long to wide, variable names are different except for the key variable (state) • We can generate average fracuninsured per state either before or after the reshape, but the merge code will be different depending on when we compute the average fracuninsured Step 1 to reshape: generate a sub-sample for each year, so that we have: subsample2009 subsample2008 …. subsample2003 focus on 2009 data subsample2009; set proj3rawdata3; if year=2009; run; data subsample2009; set subsample2009; rename totalpop=totalpop2009; rename insured=insured2009; rename uninsured=uninsured2009; rename fracuninsured=fracuninsured2009; drop year; run; Same for 2008 data subsample2008; set proj3rawdata3; if year=2008; run; data subsample2008; set subsample2008; rename totalpop=totalpop2008; rename insured=insured2008; rename uninsured=uninsured2008; rename fracuninsured=fracuninsured2008; drop year; run; Step 2 to reshape: merge each year’s subsample by state proc sort data=subsample2009; by state; run; … proc sort data=subsample2003; by state; run; data reshaped; merge subsample2009 subsample2008 subsample2007 subsample2006 subsample2005 subsample2004 subsample2003; by state; run; proc print data=reshaped; run; Generate average fracuninsured by state proc means data=proj3rawdata3; class state; var fracuninsured; output out=avgperstate mean=avgfrac_bystate; run; Merge the data file “avgperstate” back to reshaped proc sort data=reshaped; by state; run; proc sort data=avgperstate; by state; run; data reshaped_withavg; merge reshaped (in=one) avgperstate (in=two); by state; myone=one; mytwo=two; if one=1 | two=1; run; proc print data=reshaped_withavg; run; Check observations in reshaped_withavg proc freq data=reshaped_withavg; tables myone*mytwo; run; mean comparison: two groups Example: does the average fracuninsured differ between 2008 and 2009? H0: mean of fracuninsured2008 = mean of fracuninsured2009. H1: mean of fracuninsured2008 not equal to mean of fracuninsured2009. This is a two-tail mean-comparison test between the 2008 sample and the 2009 sample. The test result will be different if (1) (2) we treat 2008 and 2009 as two independent samples; or We treat 2008 and 2009 as matched pairs (matched by state). mean comparison: two groups SAS performs mean comparison in a regression framework. H0: mean of fracuninsured2008 = mean of fracuninsured2009. H1: mean of fracuninsured2008 not equal to mean of fracuninsured2009. Step 1: focus on the subsample that has 2008 and 2009 data only. Step 2: create a binary variable dummy2009=1 if year=2009, 0 if year=2008. Step 3: depend on whether 2008 and 2009 are independent samples or matched pairs. If independent samples, regress fracuninsured as: fracuninsured = a + b* dummy2009 + error If matched pairs, regress fracuninsured as: fracuninsured = a + b * dummy2009 + c1* dummy_AL + c2* dummy_AK + …+c51*dummy_WY + error mean comparison: two groups as two independent samples * Focus on 2008 and 2009 data only; Data subsample0809; Set proj3rawdata3; If year=2008 or year=2009; If year=2009 then dummy2009=1; else dummy2009=0; Run; * Treat 2008 and 2009 as two independent samples; Proc reg data=subsample0809; Model fracuninsured=dummy2009; Run; The difference between 2008 and 2009 is captured in the coefficient of dummy2009. So the hypothesis test is equivalent to: H0: coefficient of dummy2009=0. H1: coefficient of dummy2009 not equal to 0. mean comparison: two groups as matched pairs (matched by state) * Focus on 2008 and 2009 data only; data subsample0809; set proj3rawdata3; if year=2008 or year=2009; if year=2009 then dummy2009=1; else dummy2009=0; run; * Treat 2008 and 2009 as matched pairs (matched by state); proc glm data=subsample0809; class state; model fracuninsured =dummy2009 state/solution; run; The within-state difference between 2008 and 2009 is captured in the coefficient of dummy2009. So the hypothesis test is equivalent to: H0: coefficient of dummy2009=0. H1: coefficient of dummy2009 not equal to 0. mean comparison: more than two groups Example: does the average fracuninsured differ between any two years in our data? (here year = 2003, 2004, … 2009) The test result will be different if (1) (2) we treat year t and year t’ as two independent samples; or We treat year t and year t’ as matched pairs (matched by state). mean comparison: every year as an independent sample * Treat every year as an independent sample; * Now we need to use the whole data of proj3rawdata3; proc glm data=proj3rawdata3; class year; model fracuninsured=year; means year/waller; means year/lsd cldiff; run; mean comparison: every year as matched pairs (matched by state) * Treat every year as matched by state; * First define dummies for each year; data proj3rawdata3; set proj3rawdata3; if year=2004 then dummy2004=1; else dummy2004=0; if year=2005 then dummy2005=1; else dummy2005=0; … if year=2009 then dummy2009=1; else dummy2009=0; run; proc glm data=proj3rawdata3; class state; model fracuninsured=dummy2004 dummy2005 dummy2006 dummy2007 dummy2008 dummy2009 state/solution; run; The coefficient of dummy2004 captures the difference between 2003 and 2004. The coefficient of dummy2005 captures the difference between 2003 and 2005. notes on mean comparison 1. The logic of mean comparison is the same as in Excel 2. Be careful about one-tail and two-tail tests. The standard SAS output of coefficient t-stat and p-value are based on a two-tail test of H0: coeff=0, but could be used for a one-tail test if we compare 1-alpha vs. pvalue/2 instead of p-value. 3. Comparison across more than two groups (as independent samples) H0: all groups have the same mean F-test of whole regression OR H0: group x and group y has the same mean waller or lsd statistics 4. Comparison across more than two groups (as matched pairs) requires specific test on regression coefficients. H0: 2003 = 2004 test the coefficient of dummy2004=0 because 2003 is set as the benchmark H0: 2004=2005 test the coefficient of dummy2004 = coefficient of dummy2005. Explicit hypothesis tests in proc reg and proc glm * Treating each year as independent samples; Proc reg data=proj3rawdata3; Model fracuninsured=dummy2004 dummy2005 dummy2006 dummy2007 dummy2008 dummy2009; Test fracuninsured2003=fracuninsured2008; Test dummy2008=0; Test dummy2008=dummy2009; Test fracuninsured2008=fracuninsured2009; Run; * Treating each year as matched by state; Proc glm data=proj3rawdata3; Class year state; Model fracuninsured=year state/solution; Contrast ‘test 2003 vs. 2008’ year 1 0 0 0 -1 0; Test fracuninsured2003=fracuninsured2008; Contrast ‘test 2008 vs. 2009’ year 0 0 0 0 1 -1; Test fracuninsured2008=fracuninsured2009; Run; In class exercise for mean comparison Main question: compare fracuninsured in west, midatlantic and everywhere else, where west = CA, WA, OR midatlantic = DE, DC, MD, VA step 0: define west, midatlantic and everywhereelse exercise 1: compare west and midatlantic 1(a). as two independent samples 1(b). consider the match by year exercise 2: compare west, midatlantic, and everywhere else 2(a). as three independent samples; 2(b). consider the match by year; regression in SAS Question: how do fracuninsured vary by total population of a state? * model: fracuninsured=a+b*totalpop+error; proc reg data=proj3rawdata3; model fracuninsured=totalpop; run; * Add year fixed effects; * Model: fracuninsured=a+b*totalpop+c1*dummy2004 +c2*dummy2005 + …+c51*dummy2009+error; proc glm data=proj3rawdata3; class year; model fracuninsured=totalpop year/solution; run; A comprehensive example A review of 1. readin data 2. summary statistics 3. mean comparison 4. regression reg-cityreg-simple.sas in N:\share\ A Case Study of Los Angeles Restaurants Nov. 16-18, 1997 CBS 2 News “Behind the Kitchen Door” January 16, 1998, LA county inspectors start issuing hygiene grade cards A grade if score of 90 to 100 B grade if score of 80 to 89 C grade if score of 70 to 79 score below 70 actual score shown Grade cards are prominently displayed in restaurant windows Score not shown on grade cards Take the idea to data Research Question: Does better information lead to better hygiene quality? better Information better quality regulation hygiene scores by county by city Data complications (blue font indicates our final choices) Unit of analysis: individual restaurant? city? zipcode? census tract? Unit of time: each inspection? per month? per quarter? per year? Define information: county regulation? city regulation? the date of passing the regulation? days since passing the regulation? % of days under regulation? Define quality: average hygiene score? the number of A restaurants? % of A restaurants? How to test the idea? • Regression: quality = α+β*information+error +something else? Something else could be: year trend, seasonality, city specific effects, …. real test reg-cityreg-simple.sas in N:\share\ Questions • How many observations in the sample? – log of the first data step, or output from proc contents • How many variables in the sample? How many are numerical, how many are characters? – Output from proc contents • How many percentage of restaurants have A quality in a typical city-month? – Output from proc means, on per_A Questions • What is the difference between cityreg and ctyreg? We know county regulation came earlier than city regulation, is that reflected in our data? – Yes, cityreg<=ctyreg in every observation – We can check this in proc means for cityreg and ctyreg, or add a proc print to eyeball each obs • What is the difference between cityreg and citymper? What is the mean of cityreg? What is the mean of citymper? Are they consistent with their definitions? – The unit of cityreg is # of days, so it should be a non-negative integer – The unit of citymper is % of days, so it should be a real number between 0 and 1 – To check this, we can add a proc means for cityreg and citymper Questions • Economic theories suggest quality be higher after the regulation if regulation gives consumers better information. Is that true? – The summary statistics reported in proc means (class citym_g or ctym_g) show the average percentage of A restaurants in different regulation environments. – Rigorous mean comparison tests are done in proc glm with waller or lsd options. Questions Summary statistics often reflect many economic factors, not only the one in our mind. That is why we need regressions. Does more regulation lead to higher quality? – is the coefficient of city regulation positive and significantly different from zero? (proc reg) – is the coefficient of county regulation positive and significantly different from zero? (proc reg) – Do we omit other sensible explanations for quality changes? What are they? (proc glm, year, quarter, city) Count duplicates (not required) http://support.sas.com/ctx/samples/index.jsp?sid=67&tab=co de data dups nodups ; set clasdata ; by name class ; /* If the combination of NAME and CLASS is in the data set once, output NODUPS, else output DUPS. */ if first.class and last.class then output nodups ; else output dups ; run; course evaluation • University wide: – www.CourseEvalUM.umd.edu • TTclass in particular: (password plstt) – www.surveyshare.com/survey/take/?sid=81087
© Copyright 2024