SAS and Python

The code

Run it in the browser

The notebook implements every step of the SAS pipeline in pandas, SciPy, and statsmodels, and adds the diagnostics the SAS run did not produce: confidence intervals and bootstrap effect sizes, normality testing with a distribution-free sensitivity check, Holm correction, duplicate-key detection in the merge, and cross-validated R².

Open in Colab View on GitHub

The notebook runs on synthetic data. The real Qualtrics exports carry respondent IP addresses, geolocation, and response keys, so they are not published and never will be. The notebook instead simulates two survey files from the study's published aggregate statistics, calibrated so that the features the analysis turns on are all present: items that correlate strongly within a wave, a within-participant correlation across waves, a minority of participants who decline, and colliding participant codes.

Numbers it produces are therefore simulated and are not the study's results. The real findings are on the analysis page and in the executed SAS output. A single flag at the top of Part 1 switches the notebook onto the real exports for anyone with authorised access.

The pipeline

1
Import

A Qualtrics export carries two header rows, short names in the first and full question text in the second. The programs read names from row two and data from row three.

2
Convert and keep

Likert items arrive as character and are converted with input(var, best32.). A failed conversion yields a missing value rather than an error, so NMISS is checked. Only the participant code, the items, and the covariates are kept, which is what keeps Qualtrics identifiers out of the output.

3
Merge

An inner join on the participant code. The code is free text and is not unique, so the join can return more rows than there are participants. See the note below.

4
Test

PROC TTEST with ten PAIRED statements, one per item.

5
Model

A secondary regression sequence predicting the comfort item from the other nine, with COLLIN diagnostics.

Two known issues in these programs. The merge keys on a field that is not unique, so the merged table holds 57 rows from 52 distinct codes and some participants are counted more than once. And the regression sequence selects predictors and reports fit on the same data, which biases the reported fit upward. Neither changes the study's conclusions. Both are set out in full on the analysis page, and the notebook detects the first and quantifies the second.

The paired comparisons

SurveyPairedTTest202506.sas, 269 lines.

This is the program the study's headline result comes from. It imports both surveys, keeps only the participant code and the ten items, merges on the code, and runs ten paired t-tests.

The merge and the testsexcerpt
PROC SQL;
    CREATE TABLE merged_analysis_data AS
    SELECT
        a.ParticipantID,
        a.Pre_Q1, a.Pre_Q2, /* ... */ a.Pre_Q10,
        b.Post_Q1, b.Post_Q2, /* ... */ b.Post_Q10
    FROM pre_data_final AS a
    INNER JOIN post_data_final AS b
    ON a.ParticipantID = b.ParticipantID;
QUIT;

PROC TTEST DATA=merged_analysis_data ALPHA=0.05;
    PAIRED
        Post_Q1 * Pre_Q1
        Post_Q2 * Pre_Q2
        /* ... through Q10 ... */
    ;
RUN;

Source on GitHub Formatted listing Executed output

Show the full program (269 lines)
SurveyPairedTTest202506.sasSAS
/* Reset results viewer */
ods html close;
ods listing close;
ods html;
ods listing;

* Set options, footnotes, form setting;
options ps=60 ls=78 nodate pageno=1;

/*Import raw data */
/* GETNAMES=YES reads the first row as variable names.
   DATAROW=3 tells SAS that the actual data starts from the 3rd row,
   effectively skipping the 2nd row (which contains descriptive header info).
*/
proc import datafile="\\apporto.com\dfs\WCUPA\Users\0068114_wcupa\Desktop\Survey\WPV-Spring2025-Demographics-Survey-PRE_June 12, 2025_15.16.xlsx"
    out=pre_survey_raw
    dbms=XLSX
    replace;
    getnames=YES;
	range="Sheet0$A2:0";

run;

proc import datafile="\\apporto.com\dfs\WCUPA\Users\0068114_wcupa\Desktop\Survey\WPV-Spring2025-Survey-POST_June 12, 2025_15.20.xlsx"
    out=post_survey_raw
    dbms=XLSX
    replace;
    getnames=YES;
	range="Sheet0$A2:0";
run;

/* Select relevant columns and rename them for consistent merging and analysis.
   SAS automatically handles implicit numeric conversion for columns that contain
   only numeric values. Missing values are represented as '.'.
*/

DATA pre_data_cleaned;
    SET pre_survey_raw (
	RENAME= (
		Create_a_unique_identifier_using = ParticipantID
		How_comfortable_are_you_in_worki = Pre_Q1
		How_good_is_your_present_level_o = Pre_Q2
		How_able_are_you_to_intervene_ph = Pre_Q3
		How_self_assured_do_you_feel_in =  Pre_Q4
		How_able_are_you_to_intervene_ps = Pre_Q5
		How_good_is_your_present_level_1 = Pre_Q6
		How_safe_do_you_feel_around_an_a = Pre_Q7
		How_effective_are_the_techniques = Pre_Q8
		How_able_are_you_to_meet_the_nee = Pre_Q9
		How_able_are_you_to_protect_your = Pre_Q10));
	;
	KEEP ParticipantID Pre_Q1 Pre_Q2 Pre_Q3 Pre_Q4 Pre_Q5 Pre_Q6 Pre_Q7 Pre_Q8 Pre_Q9 Pre_Q10;
Run;

data pre_data_final;
	set pre_data_cleaned;
	numeric_01 = input(Pre_Q1, best32.);
	numeric_02 = input(Pre_Q2, best32.);
	numeric_03 = input(Pre_Q3, best32.);
	numeric_04 = input(Pre_Q4, best32.);
	numeric_05 = input(Pre_Q5, best32.);
	numeric_06 = input(Pre_Q6, best32.);
	numeric_07 = input(Pre_Q7, best32.);
	numeric_08 = input(Pre_Q8, best32.);
	numeric_09 = input(Pre_Q9, best32.);
	numeric_10 = input(Pre_Q10, best32.);
	drop 
		Pre_Q1
		Pre_Q2
		Pre_Q3
		Pre_Q4
		Pre_Q5
		Pre_Q6
		Pre_Q7
		Pre_Q8
		Pre_Q9
		Pre_Q10
		;
	rename
		numeric_01 = Pre_Q1
		numeric_02 = Pre_Q2
		numeric_03 = Pre_Q3
		numeric_04 = Pre_Q4
		numeric_05 = Pre_Q5
		numeric_06 = Pre_Q6
		numeric_07 = Pre_Q7
		numeric_08 = Pre_Q8
		numeric_09 = Pre_Q9
		numeric_10 = Pre_Q10
		;
run;

DATA post_data_cleaned;
    SET post_survey_raw (
	RENAME= (
		Create_a_unique_identifier_using = ParticipantID
		How_comfortable_are_you_in_worki = Post_Q1
		How_good_is_your_present_level_o = Post_Q2
		How_able_are_you_to_intervene_ph = Post_Q3
		How_self_assured_do_you_feel_in =  Post_Q4
		How_able_are_you_to_intervene_ps = Post_Q5
		How_good_is_your_present_level_1 = Post_Q6
		How_safe_do_you_feel_around_an_a = Post_Q7
		How_effective_are_the_techniques = Post_Q8
		How_able_are_you_to_meet_the_nee = Post_Q9
		How_able_are_you_to_protect_your = Post_Q10));
	;
KEEP ParticipantID Post_Q1 Post_Q2 Post_Q3 Post_Q4 Post_Q5 Post_Q6 Post_Q7 Post_Q8 Post_Q9 Post_Q10;
Run;


data post_data_final;
	set post_data_cleaned;
	numeric_01 = input(Post_Q1, best32.);
	numeric_02 = input(Post_Q2, best32.);
	numeric_03 = input(Post_Q3, best32.);
	numeric_04 = input(Post_Q4, best32.);
	numeric_05 = input(Post_Q5, best32.);
	numeric_06 = input(Post_Q6, best32.);
	numeric_07 = input(Post_Q7, best32.);
	numeric_08 = input(Post_Q8, best32.);
	numeric_09 = input(Post_Q9, best32.);
	numeric_10 = input(Post_Q10, best32.);
	drop 
		Post_Q1
		Post_Q2
		Post_Q3
		Post_Q4
		Post_Q5
		Post_Q6
		Post_Q7
		Post_Q8
		Post_Q9
		Post_Q10
		;
	rename
		numeric_01 = Post_Q1
		numeric_02 = Post_Q2
		numeric_03 = Post_Q3
		numeric_04 = Post_Q4
		numeric_05 = Post_Q5
		numeric_06 = Post_Q6
		numeric_07 = Post_Q7
		numeric_08 = Post_Q8
		numeric_09 = Post_Q9
		numeric_10 = Post_Q10
		;
run;

/* PROC SQL is used to perform an inner join on ParticipantID,
   ensuring that only participants present in both surveys are included.
*/
PROC SQL;
    CREATE TABLE merged_analysis_data AS
    SELECT
        a.ParticipantID,
        a.Pre_Q1, a.Pre_Q2, a.Pre_Q3, a.Pre_Q4, a.Pre_Q5,
        a.Pre_Q6, a.Pre_Q7, a.Pre_Q8, a.Pre_Q9, a.Pre_Q10,
        b.Post_Q1, b.Post_Q2, b.Post_Q3, b.Post_Q4, b.Post_Q5,
        b.Post_Q6, b.Post_Q7, b.Post_Q8, b.Post_Q9, b.Post_Q10
    FROM
        pre_data_final AS a
    INNER JOIN
        post_data_final AS b
    ON
        a.ParticipantID = b.ParticipantID;
QUIT;

/* Print first few rows of merged data to verify structure and content */
PROC PRINT DATA=merged_analysis_data (OBS=5);
    TITLE 'First 5 Rows of Merged Analysis Data';
RUN;

PROC CONTENTS DATA=merged_analysis_data;
    TITLE 'Contents of Merged Analysis Data';
RUN;

/* PROC TTEST performs paired t-tests. SAS automatically excludes observations
   with missing values for the specified paired variables.
   ALPHA=0.05 sets the significance level.
*/

ODS OUTPUT TTests=ttest_results;
ODS OUTPUT Statistics=ttest_statistics;

PROC TTEST DATA=merged_analysis_data ALPHA=0.05;
    PAIRED
        Post_Q1 * Pre_Q1
        Post_Q2 * Pre_Q2
        Post_Q3 * Pre_Q3
        Post_Q4 * Pre_Q4
        Post_Q5 * Pre_Q5
        Post_Q6 * Pre_Q6
        Post_Q7 * Pre_Q7
        Post_Q8 * Pre_Q8
        Post_Q9 * Pre_Q9
        Post_Q10 * Pre_Q10
    ;
    TITLE 'Paired T-test Results for Pre vs. Post Survey Questions';
RUN;

ODS OUTPUT CLOSE;


PROC PRINT DATA=ttest_results(OBS=20);
    TITLE 'First 20 Rows ttest_results';
RUN;

PROC CONTENTS DATA=ttest_results;
    TITLE 'Contents of ttest_results';
RUN;

DATA t_test_results_processed;
    SET ttest_results;
    /* Create a cleaned 'Question' name from the Question_Pair variable */
    LENGTH Question $50;
    IF Difference = 'Post_Q1 - Pre_Q1' THEN Question = 'Question 1';
    ELSE IF Difference = 'Post_Q2 - Pre_Q2' THEN Question = 'Question 2';
    ELSE IF Difference = 'Post_Q3 - Pre_Q3' THEN Question = 'Question 3';
    ELSE IF Difference = 'Post_Q4 - Pre_Q4' THEN Question = 'Question 4';
    ELSE IF Difference = 'Post_Q5 - Pre_Q5' THEN Question = 'Question 5';
    ELSE IF Difference = 'Post_Q6 - Pre_Q6' THEN Question = 'Question 6';
    ELSE IF Difference = 'Post_Q7 - Pre_Q7' THEN Question = 'Question 7';
    ELSE IF Difference = 'Post_Q8 - Pre_Q8' THEN Question = 'Question 8';
    ELSE IF Difference = 'Post_Q9 - Pre_Q9' THEN Question = 'Question 9';
    ELSE IF Difference = 'Post_Q10 - Pre_Q10' THEN Question = 'Question 10';
    ELSE DELETE; /* Remove any rows not corresponding to our specific question pairs */

    /* Determine significance (p < 0.05) */
    LENGTH Significant $3; /* 'Yes' or 'No' */
    IF Probt < 0.05 THEN Significant = 'Yes';
    ELSE Significant = 'No';

    /* Keep only the desired columns for the final summary table */
RUN;


PROC PRINT DATA=t_test_results_processed(OBS=20);
    TITLE 'First 20 Rows t_test_results_processed';
RUN;


PROC PRINT DATA=ttest_statistics(OBS=20);
    TITLE 'First 20 Rows ttest_statistics';
RUN;

PROC CONTENTS DATA=ttest_statistics;
    TITLE 'Contents of ttest_statistics';
RUN;


PROC SQL;
    CREATE TABLE final_summary_table AS
    SELECT
*
    FROM
        t_test_results_processed AS t
    LEFT JOIN
        ttest_statistics AS m
    ON
        t.Difference = m.Difference
    ORDER BY t.Difference; /* Order the table by question for readability */
QUIT;

/* Display the final summary table */
PROC PRINT DATA=final_summary_table NOOBS;
    TITLE 'Summary of Paired T-test Results';
RUN;

The pre-simulation survey

Survey202506.sas, 424 lines.

Imports the pre survey, splits the two Qualtrics header rows, converts the Likert items from character to numeric, builds the clinical experience dummies, then runs descriptives and a sequence of regression models.

Dropping the identifier columns before any outputexcerpt
data analysis_data;
    set final_survey_data;
    KEEP ParticipantID
         q10_1_how_comfortable_are_you
         q11_1_how_good_is_your_present
         /* ... the remaining items ... */
         Exp1 Exp2 Exp3;
run;

Source on GitHub Formatted listing Executed output

Show the full program (424 lines)
Survey202506.sasSAS
/* Reset results viewer */
ods html close;
ods listing close;
ods html;
ods listing;

* Set options, footnotes, form setting;
options ps=60 ls=78 nodate pageno=1;

/*Import raw data (let SAS assign default variable names from row 1) */
proc import datafile="\\apporto.com\dfs\WCUPA\Users\0068114_wcupa\Desktop\Survey\WPV-Spring2025-Demographics-Survey-PRE_June 12, 2025_15.16.xlsx"
    out=raw_data
    dbms=xlsx
    replace;
    getnames=no;
run;

/*Use first two rows as header and create actual variable names */
data headers labels data_clean;
    set raw_data;
    if _n_ = 1 then output headers; /* First row = first part of header */
    else if _n_ = 2 then output labels; /* Second row = second part of header */
    else output data_clean; /* Actual data starts from 3rd row */
run;

data survey_data;
    set data_clean (
    rename= ( 
           A = startdate
           B = enddate
           C = status_response_type
           D = ipaddress
           E = progress
           F = duration_in_seconds
           G = finished
           H = recorded_date
           I = responseid
           J = recipientlastname
           K = recipientfirstname
           L = recipientemail
           M = externalreference
           N = locationlatitude
           O = locationlongitude
           P = distributionchannel
           Q = user_language
           R = q1_create_a_unique_id
           S = q2_what_is_your_major
           T = q3_what_is_your_age
           U = q4_which_of_the_foll_best
           V = q5_i_have_participated_in_clin
           W = q6_i_have_clinical_experience
           X = q7_if_you_have_clinical_experi
           Y = q8_if_you_have_clinical_experi
           Z = q10_1_how_comfortable_are_you
           AA = q11_1_how_good_is_your_present
           AB = q12_1_how_able_are_you_to_inte
           AC = q13_1_how_self_assured_do_you
           AD = q14_1_how_able_are_you_to_inte
           AE = q15_1_how_good_is_your_present
           AF = q16_1_how_safe_do_you_feel_aro
           AG = q17_1_how_effective_are_the_te
           AH = q18_1_how_able_are_you_to_meet
           AI = q19_1_how_able_are_you_to_prot
           AJ = q20_how_do_you_feel_going_into));
run;

data final_survey_data;
    set survey_data;
	LENGTH Exp1 8;
	LENGTH Exp2 8;
	LENGTH Exp3 8;
/*Convert to numeric*/
    numeric_01 = input(q10_1_how_comfortable_are_you, best32.);
    numeric_02 = input(q11_1_how_good_is_your_present, best32.);
	numeric_03 = input(q12_1_how_able_are_you_to_inte, best32.);
    numeric_04 = input(q13_1_how_self_assured_do_you, best32.);
	numeric_05 = input(q14_1_how_able_are_you_to_inte, best32.);
    numeric_06 = input(q15_1_how_good_is_your_present, best32.);
	numeric_07 = input(q16_1_how_safe_do_you_feel_aro, best32.);
	numeric_08 = input(q17_1_how_effective_are_the_te, best32.);
	numeric_09 = input(q18_1_how_able_are_you_to_meet, best32.);
	numeric_10 = input(q19_1_how_able_are_you_to_prot, best32.);

    drop q10_1_how_comfortable_are_you 
         q11_1_how_good_is_your_present
		q12_1_how_able_are_you_to_inte
		q13_1_how_self_assured_do_you
		q14_1_how_able_are_you_to_inte
		q15_1_how_good_is_your_present
		q16_1_how_safe_do_you_feel_aro
		q17_1_how_effective_are_the_te
		q18_1_how_able_are_you_to_meet
		q19_1_how_able_are_you_to_prot;

    rename numeric_01 = q10_1_how_comfortable_are_you
           numeric_02 = q11_1_how_good_is_your_present
			numeric_03 = q12_1_how_able_are_you_to_inte
    		numeric_04 = q13_1_how_self_assured_do_you
			numeric_05 = q14_1_how_able_are_you_to_inte
    		numeric_06 = q15_1_how_good_is_your_present
			numeric_07 = q16_1_how_safe_do_you_feel_aro
			numeric_08 = q17_1_how_effective_are_the_te
			numeric_09 = q18_1_how_able_are_you_to_meet
			numeric_10 = q19_1_how_able_are_you_to_prot;

			/* Add in dummy data for experience */

			/*
q8_if_you_have_clinical_experi                                   	Exp1      	Exp 2					Exp3
																	I dont		3 months to 6 months	6 months to 9 months	
I don't have clinical experience outside of my program at WCU    	1			0						0
3 months to 6 months												0			1						0
6 months to 9 months												0			0						1
Longer than 1 year													0			0						0
			*/

IF q8_if_you_have_clinical_experi = 'I don&apos;t have clinical experience outside of my program at WCU' THEN
DO;
	Exp1 = 1;
	Exp2 = 0;
	Exp3 = 0;
END;
IF q8_if_you_have_clinical_experi = '3 months to 6 months' THEN
DO;
	Exp1 = 0;
	Exp2 = 1;
	Exp3 = 0;
END;
IF q8_if_you_have_clinical_experi = '6 months to 9 months' THEN
DO;
	Exp1 = 0;
	Exp2 = 0;
	Exp3 = 1;
END;
IF q8_if_you_have_clinical_experi = 'Longer than 1 year' THEN
DO;
	Exp1 = 0;
	Exp2 = 0;
	Exp3 = 0;
END;

run;


/* ===========================================================================
   DE-IDENTIFY BEFORE ANYTHING PRINTS.

   The Qualtrics export carries direct identifiers (ipaddress, recipientemail,
   recipientfirstname, recipientlastname), geolocation (locationlatitude,
   locationlongitude), the response key (responseid) and timestamps. proc import
   brings every one of them through, and any proc print / proc contents / ods pdf
   run against a dataset that still holds them writes real respondent data into
   the results file.

   KEEP rather than DROP on purpose: a KEEP list fails closed, so a column added
   to a future Qualtrics export cannot leak by default.

   Same pattern as SurveyPairedTTest202506.sas, whose output is clean.
   =========================================================================== */
data analysis_data;
    set final_survey_data;
    KEEP q1_create_a_unique_id
         q2_what_is_your_major
         q3_what_is_your_age
         q4_which_of_the_foll_best
         q5_i_have_participated_in_clin
         q6_i_have_clinical_experience
         q7_if_you_have_clinical_experi
         q8_if_you_have_clinical_experi
         q10_1_how_comfortable_are_you
         q11_1_how_good_is_your_present
         q12_1_how_able_are_you_to_inte
         q13_1_how_self_assured_do_you
         q14_1_how_able_are_you_to_inte
         q15_1_how_good_is_your_present
         q16_1_how_safe_do_you_feel_aro
         q17_1_how_effective_are_the_te
         q18_1_how_able_are_you_to_meet
         q19_1_how_able_are_you_to_prot
         q20_how_do_you_feel_going_into
         Exp1 Exp2 Exp3;
run;

/* Row-level check for the analyst only. ParticipantID is a quasi-identifier
   (birth year + mother's initials), so it is excluded from the listing. */
proc print data=analysis_data(OBS=30);
    VAR q2_what_is_your_major q3_what_is_your_age q4_which_of_the_foll_best
        q10_1_how_comfortable_are_you q11_1_how_good_is_your_present
        q12_1_how_able_are_you_to_inte q13_1_how_self_assured_do_you;
    TITLE "Import check, first 30 rows (identifiers removed)";
run;

PROC CONTENTS DATA=analysis_data;
RUN;

/* Descriptive statistics for numeric variables */
PROC MEANS DATA=analysis_data N NMISS MEAN STD MIN MAX Q1 MEDIAN Q3;
    VAR 
		q10_1_how_comfortable_are_you
		q11_1_how_good_is_your_present
		q12_1_how_able_are_you_to_inte
		q13_1_how_self_assured_do_you
		q14_1_how_able_are_you_to_inte
		q15_1_how_good_is_your_present
		q16_1_how_safe_do_you_feel_aro
		q17_1_how_effective_are_the_te
		q18_1_how_able_are_you_to_meet
		q19_1_how_able_are_you_to_prot;

	TITLE "Descriptive Statistics for Numeric Variables"; 
RUN;


/* Distributions */
PROC UNIVARIATE DATA=analysis_data PLOT;
     VAR 
		q10_1_how_comfortable_are_you
		q11_1_how_good_is_your_present
		q12_1_how_able_are_you_to_inte
		q13_1_how_self_assured_do_you
		q14_1_how_able_are_you_to_inte
		q15_1_how_good_is_your_present
		q16_1_how_safe_do_you_feel_aro
		q17_1_how_effective_are_the_te
		q18_1_how_able_are_you_to_meet
		q19_1_how_able_are_you_to_prot;
    HISTOGRAM;
	TITLE "Distributions for Numeric Variables";
RUN;


/* Frequency counts for categorical variables*/
PROC FREQ DATA=analysis_data;
    TABLE q2_what_is_your_major 
		q3_what_is_your_age
		q4_which_of_the_foll_best
		q5_i_have_participated_in_clin
		q6_i_have_clinical_experience
		q8_if_you_have_clinical_experi;
	TITLE "Frequency Counts";
RUN;


%macro hist_ratings(var, label);
    PROC SGPLOT DATA=analysis_data;
        HISTOGRAM &var / BINWIDTH=1;
        TITLE "Distribution of " &label;
        XAXIS LABEL=&label;
        YAXIS LABEL="Frequency";
    RUN;
%mend hist_ratings;

%hist_ratings(q10_1_how_comfortable_are_you, "q10_1_how_comfortable_are_you");
%hist_ratings(q11_1_how_good_is_your_present, "q11_1_how_good_is_your_present");
%hist_ratings(q12_1_how_able_are_you_to_inte, "q12_1_how_able_are_you_to_inte");
%hist_ratings(q13_1_how_self_assured_do_you, "q13_1_how_self_assured_do_you");
%hist_ratings(q14_1_how_able_are_you_to_inte, "q14_1_how_able_are_you_to_inte");
%hist_ratings(q15_1_how_good_is_your_present, "q15_1_how_good_is_your_present");
%hist_ratings(q16_1_how_safe_do_you_feel_aro, "q16_1_how_safe_do_you_feel_aro");
%hist_ratings(q17_1_how_effective_are_the_te, "q17_1_how_effective_are_the_te");
%hist_ratings(q18_1_how_able_are_you_to_meet, "q18_1_how_able_are_you_to_meet");
%hist_ratings(q19_1_how_able_are_you_to_prot, "q19_1_how_able_are_you_to_prot");

/* Models */

/* All Possible Models */

PROC REG DATA = analysis_data;
	Title 'q10_1_how_comfortable_are_you All Possible Models';
	MODEL q10_1_how_comfortable_are_you = 
		q11_1_how_good_is_your_present
		q12_1_how_able_are_you_to_inte
		q13_1_how_self_assured_do_you
		q14_1_how_able_are_you_to_inte
		q15_1_how_good_is_your_present
		q16_1_how_safe_do_you_feel_aro
		q17_1_how_effective_are_the_te
		q18_1_how_able_are_you_to_meet
		q19_1_how_able_are_you_to_prot /
		SELECTION = RSQUARE CP MSE;
RUN;

/* Selected Model */

PROC REG DATA = analysis_data;
	Title 'q10_1_how_comfortable_are_you Selected Model';
	MODEL q10_1_how_comfortable_are_you = 
		q11_1_how_good_is_your_present
		q12_1_how_able_are_you_to_inte
		q13_1_how_self_assured_do_you
		q14_1_how_able_are_you_to_inte
		q15_1_how_good_is_your_present
		q16_1_how_safe_do_you_feel_aro
		q17_1_how_effective_are_the_te
		q18_1_how_able_are_you_to_meet
		q19_1_how_able_are_you_to_prot; 
RUN;



/* All Possible Models */

PROC REG DATA = analysis_data;
	Title 'q10_1_how_comfortable_are_you All Possible Models (Include Expereince Level)';
	MODEL q10_1_how_comfortable_are_you = 
		q11_1_how_good_is_your_present
		q12_1_how_able_are_you_to_inte
		q13_1_how_self_assured_do_you
		q14_1_how_able_are_you_to_inte
		q15_1_how_good_is_your_present
		q16_1_how_safe_do_you_feel_aro
		q17_1_how_effective_are_the_te
		q18_1_how_able_are_you_to_meet
		q19_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3 /
		SELECTION = RSQUARE CP MSE;
RUN;


/* Selected Model */

PROC REG DATA = analysis_data;
	Title 'q10_1_how_comfortable_are_you Selected Model (Include Experience Level)';
	MODEL q10_1_how_comfortable_are_you = 
		q11_1_how_good_is_your_present
		q12_1_how_able_are_you_to_inte
		q13_1_how_self_assured_do_you
		q14_1_how_able_are_you_to_inte
		q15_1_how_good_is_your_present
		q16_1_how_safe_do_you_feel_aro
		q17_1_how_effective_are_the_te
		q18_1_how_able_are_you_to_meet
		q19_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3; 
RUN;


PROC REG DATA = analysis_data;
	Title 'q10_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)';
	MODEL q10_1_how_comfortable_are_you = 
		q11_1_how_good_is_your_present
		q12_1_how_able_are_you_to_inte
		q13_1_how_self_assured_do_you
		q14_1_how_able_are_you_to_inte
		q15_1_how_good_is_your_present
		q16_1_how_safe_do_you_feel_aro
		q17_1_how_effective_are_the_te
		q18_1_how_able_are_you_to_meet
		q19_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3 
		/ COLLIN;
RUN;


PROC REG DATA = analysis_data;
	Title 'q10_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)(Remove q18_1_how_able_are_you_to_meet)';
	MODEL q10_1_how_comfortable_are_you = 
		q11_1_how_good_is_your_present
		q12_1_how_able_are_you_to_inte
		q13_1_how_self_assured_do_you
		q14_1_how_able_are_you_to_inte
		q15_1_how_good_is_your_present
		q16_1_how_safe_do_you_feel_aro
		q17_1_how_effective_are_the_te
		q19_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3 
		/ COLLIN;
RUN;


PROC REG DATA = analysis_data;
	Title 'q10_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)(Remove q18_1_how_able_are_you_to_meet, q14_1_how_able_are_you_to_inte )';
	MODEL q10_1_how_comfortable_are_you = 
		q11_1_how_good_is_your_present
		q12_1_how_able_are_you_to_inte
		q13_1_how_self_assured_do_you
		q15_1_how_good_is_your_present
		q16_1_how_safe_do_you_feel_aro
		q17_1_how_effective_are_the_te
		q19_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3 
		/ COLLIN;
RUN;

PROC REG DATA = analysis_data;
	Title 'q10_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)(Remove q18_1_how_able_are_you_to_meet, q14_1_how_able_are_you_to_inte,q13_1_how_self_assured_do_you  )';
	MODEL q10_1_how_comfortable_are_you = 
		q11_1_how_good_is_your_present
		q12_1_how_able_are_you_to_inte
		q15_1_how_good_is_your_present
		q16_1_how_safe_do_you_feel_aro
		q17_1_how_effective_are_the_te
		q19_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3 
		/ COLLIN;
RUN;

PROC REG DATA = analysis_data;
	Title 'q10_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)(Remove q18_1_how_able_are_you_to_meet, q14_1_how_able_are_you_to_inte,q13_1_how_self_assured_do_you,q19_1_how_able_are_you_to_prot   )';
	MODEL q10_1_how_comfortable_are_you = 
		q11_1_how_good_is_your_present
		q12_1_how_able_are_you_to_inte
		q15_1_how_good_is_your_present
		q16_1_how_safe_do_you_feel_aro
		q17_1_how_effective_are_the_te
		Exp1
		Exp2
		Exp3 
		/ COLLIN;
RUN;

The post-simulation survey

SurveyPost202506.sas, 477 lines.

The same shape as the pre-survey program, run against the post-simulation export.

The experience dummiesexcerpt
IF q8_if_you_have_clinical_experi = '3 months to 6 months' THEN
DO;
    Exp1 = 0;
    Exp2 = 1;
    Exp3 = 0;
END;
/* "Longer than 1 year" is the reference category: Exp1 = Exp2 = Exp3 = 0.
   A response matching none of the four leaves all three MISSING, not zero,
   and the row drops silently from any model using them. */

Source on GitHub Formatted listing Executed output

Show the full program (477 lines)
SurveyPost202506.sasSAS
/* Reset results viewer */
ods html close;
ods listing close;
ods html;
ods listing;

* Set options, footnotes, form setting;
options ps=60 ls=78 nodate pageno=1;

/*Import raw data (let SAS assign default variable names from row 1) */
proc import datafile="\\apporto.com\dfs\WCUPA\Users\0068114_wcupa\Desktop\Survey\WPV-Spring2025-Survey-POST_June 12, 2025_15.20.xlsx"
    out=raw_data
    dbms=xlsx
    replace;
    getnames=no;
run;

/*Use first two rows as header and create actual variable names */
data headers labels data_clean;
    set raw_data;
    if _n_ = 1 then output headers; /* First row = first part of header */
    else if _n_ = 2 then output labels; /* Second row = second part of header */
    else output data_clean; /* Actual data starts from 3rd row */
run;

data survey_data;
    set data_clean (
    rename= ( 
           A = startdate
           B = enddate
           C = status_response_type
           D = ipaddress
           E = progress
           F = duration_in_seconds
           G = finished
           H = recorded_date
           I = responseid
           J = recipientlastname
           K = recipientfirstname
           L = recipientemail
           M = externalreference
           N = locationlatitude
           O = locationlongitude
           P = distributionchannel
           Q = user_language
           R = q1_create_a_unique_id
           S = q2_what_is_your_major
           T = q3_what_is_your_age
           U = q4_which_of_the_foll_best
           V = q5_i_have_participated_in_clin
           W = q6_i_have_clinical_experience
           X = q7_if_you_have_clinical_experi
           Y = q8_if_you_have_clinical_experi
		   Z = q2_did_you_actively_partc
		   AA = q3_feel_at_end_sumu
           AB = q4_feel_at_debrief
		   AC = q15_victim_witness_voilence
		   AD = q16_who_was_perpetrator
		   AE = q5_1_how_comfortable_are_you
           AF = q6_1_how_good_is_your_present
           AG = q7_1_how_able_are_you_to_inte
           AH = q8_1_how_self_assured_do_you
           AI = q9_1_how_able_are_you_to_inte
           AJ = q10_1_how_good_is_your_present
           AK = q11_1_how_safe_do_you_feel_aro
           AL = q12_1_how_effective_are_the_te
           AM = q13_1_how_able_are_you_to_meet
           AN = q14_1_how_able_are_you_to_prot));
run;

data final_survey_data;
    set survey_data;
	LENGTH Exp1 8;
	LENGTH Exp2 8;
	LENGTH Exp3 8;
/*Convert to numeric*/
    numeric_01 = input(q5_1_how_comfortable_are_you, best32.);
    numeric_02 = input(q6_1_how_good_is_your_present, best32.);
	numeric_03 = input(q7_1_how_able_are_you_to_inte, best32.);
    numeric_04 = input(q8_1_how_self_assured_do_you, best32.);
	numeric_05 = input(q9_1_how_able_are_you_to_inte, best32.);
    numeric_06 = input(q10_1_how_good_is_your_present, best32.);
	numeric_07 = input(q11_1_how_safe_do_you_feel_aro, best32.);
	numeric_08 = input(q12_1_how_effective_are_the_te, best32.);
	numeric_09 = input(q13_1_how_able_are_you_to_meet, best32.);
	numeric_10 = input(q14_1_how_able_are_you_to_prot, best32.);

    drop q5_1_how_comfortable_are_you 
         q6_1_how_good_is_your_present
		q7_1_how_able_are_you_to_inte
		q8_1_how_self_assured_do_you
		q9_1_how_able_are_you_to_inte
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q12_1_how_effective_are_the_te
		q13_1_how_able_are_you_to_meet
		q14_1_how_able_are_you_to_prot;

    rename numeric_01 = q5_1_how_comfortable_are_you
           numeric_02 = q6_1_how_good_is_your_present
			numeric_03 = q7_1_how_able_are_you_to_inte
    		numeric_04 = q8_1_how_self_assured_do_you
			numeric_05 = q9_1_how_able_are_you_to_inte
    		numeric_06 = q10_1_how_good_is_your_present
			numeric_07 = q11_1_how_safe_do_you_feel_aro
			numeric_08 = q12_1_how_effective_are_the_te
			numeric_09 = q13_1_how_able_are_you_to_meet
			numeric_10 = q14_1_how_able_are_you_to_prot;

/* Add in dummy data for experience */

			/*
q8_if_you_have_clinical_experi                                   	Exp1      	Exp 2					Exp3
																	I dont		3 months to 6 months	6 months to 9 months	
I don't have clinical experience outside of my program at WCU    	1			0						0
3 months to 6 months												0			1						0
6 months to 9 months												0			0						1
Longer than 1 year													0			0						0
			*/

IF q8_if_you_have_clinical_experi = 'I don&apos;t have clinical experience outside of my program at WCU' THEN
DO;
	Exp1 = 1;
	Exp2 = 0;
	Exp3 = 0;
END;
IF q8_if_you_have_clinical_experi = '3 months to 6 months' THEN
DO;
	Exp1 = 0;
	Exp2 = 1;
	Exp3 = 0;
END;
IF q8_if_you_have_clinical_experi = '6 months to 9 months' THEN
DO;
	Exp1 = 0;
	Exp2 = 0;
	Exp3 = 1;
END;
IF q8_if_you_have_clinical_experi = 'Longer than 1 year' THEN
DO;
	Exp1 = 0;
	Exp2 = 0;
	Exp3 = 0;
END;

run;


/* ===========================================================================
   DE-IDENTIFY BEFORE ANYTHING PRINTS.

   The Qualtrics export carries direct identifiers (ipaddress, recipientemail,
   recipientfirstname, recipientlastname), geolocation (locationlatitude,
   locationlongitude), the response key (responseid) and timestamps. proc import
   brings every one of them through, and any proc print / proc contents / ods pdf
   run against a dataset that still holds them writes real respondent data into
   the results file.

   KEEP rather than DROP on purpose: a KEEP list fails closed, so a column added
   to a future Qualtrics export cannot leak by default.

   Same pattern as SurveyPairedTTest202506.sas, whose output is clean.
   =========================================================================== */
data analysis_data;
    set final_survey_data;
    KEEP q1_create_a_unique_id
         q2_what_is_your_major
         q3_what_is_your_age
         q4_which_of_the_foll_best
         q5_i_have_participated_in_clin
         q6_i_have_clinical_experience
         q7_if_you_have_clinical_experi
         q8_if_you_have_clinical_experi
         q2_did_you_actively_partc
         q3_feel_at_end_sumu
         q4_feel_at_debrief
         q15_victim_witness_voilence
         q16_who_was_perpetrator
         q5_1_how_comfortable_are_you
         q6_1_how_good_is_your_present
         q7_1_how_able_are_you_to_inte
         q8_1_how_self_assured_do_you
         q9_1_how_able_are_you_to_inte
         q10_1_how_good_is_your_present
         q11_1_how_safe_do_you_feel_aro
         q12_1_how_effective_are_the_te
         q13_1_how_able_are_you_to_meet
         q14_1_how_able_are_you_to_prot
         Exp1 Exp2 Exp3;
run;

/* Row-level check for the analyst only. ParticipantID is a quasi-identifier
   (birth year + mother's initials), so it is excluded from the listing. */
proc print data=analysis_data(OBS=10);
    VAR q2_what_is_your_major q3_what_is_your_age q4_which_of_the_foll_best
        q5_1_how_comfortable_are_you q6_1_how_good_is_your_present
        q7_1_how_able_are_you_to_inte q8_1_how_self_assured_do_you;
    TITLE "Import check, first 10 rows (identifiers removed)";
run;

PROC CONTENTS DATA=analysis_data;
RUN;

/* Descriptive statistics for numeric variables */
PROC MEANS DATA=analysis_data N NMISS MEAN STD MIN MAX Q1 MEDIAN Q3;
    VAR 
		q5_1_how_comfortable_are_you
		q6_1_how_good_is_your_present
		q7_1_how_able_are_you_to_inte
		q8_1_how_self_assured_do_you
		q9_1_how_able_are_you_to_inte
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q12_1_how_effective_are_the_te
		q13_1_how_able_are_you_to_meet
		q14_1_how_able_are_you_to_prot;

	TITLE "Descriptive Statistics for Numeric Variables"; 
RUN;


/* Distributions */
PROC UNIVARIATE DATA=analysis_data PLOT;
     VAR 
		q5_1_how_comfortable_are_you
		q6_1_how_good_is_your_present
		q7_1_how_able_are_you_to_inte
		q8_1_how_self_assured_do_you
		q9_1_how_able_are_you_to_inte
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q12_1_how_effective_are_the_te
		q13_1_how_able_are_you_to_meet
		q14_1_how_able_are_you_to_prot;
    HISTOGRAM;
	TITLE "Distributions for Numeric Variables";
RUN;


/* Frequency counts for categorical variables*/
PROC FREQ DATA=analysis_data;
    TABLE q2_what_is_your_major 
		q3_what_is_your_age
		q4_which_of_the_foll_best
		q5_i_have_participated_in_clin
		q6_i_have_clinical_experience
		q8_if_you_have_clinical_experi
		q2_did_you_actively_partc;
	TITLE "Frequency Counts";
RUN;


%macro hist_ratings(var, label);
    PROC SGPLOT DATA=analysis_data;
        HISTOGRAM &var / BINWIDTH=1;
        TITLE "Distribution of " &label;
        XAXIS LABEL=&label;
        YAXIS LABEL="Frequency";
    RUN;
%mend hist_ratings;

%hist_ratings(q5_1_how_comfortable_are_you, "q5_1_how_comfortable_are_you");
%hist_ratings(q6_1_how_good_is_your_present, "q6_1_how_good_is_your_present");
%hist_ratings(q7_1_how_able_are_you_to_inte, "q7_1_how_able_are_you_to_inte");
%hist_ratings(q8_1_how_self_assured_do_you, "q8_1_how_self_assured_do_you");
%hist_ratings(q9_1_how_able_are_you_to_inte, "q9_1_how_able_are_you_to_inte");
%hist_ratings(q10_1_how_good_is_your_present, "q10_1_how_good_is_your_present");
%hist_ratings(q11_1_how_safe_do_you_feel_aro, "q11_1_how_safe_do_you_feel_aro");
%hist_ratings(q12_1_how_effective_are_the_te, "q12_1_how_effective_are_the_te");
%hist_ratings(q13_1_how_able_are_you_to_meet, "q13_1_how_able_are_you_to_meet");
%hist_ratings(q14_1_how_able_are_you_to_prot, "q14_1_how_able_are_you_to_prot");

/* Models */

/* All Possible Models */

PROC REG DATA = analysis_data;
	Title 'q10_1_how_comfortable_are_you All Possible Models';
	MODEL q5_1_how_comfortable_are_you = 
		q6_1_how_good_is_your_present
		q7_1_how_able_are_you_to_inte
		q8_1_how_self_assured_do_you
		q9_1_how_able_are_you_to_inte
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q12_1_how_effective_are_the_te
		q13_1_how_able_are_you_to_meet
		q14_1_how_able_are_you_to_prot /
		SELECTION = RSQUARE CP MSE;
RUN;

/* Selected Model */

PROC REG DATA = analysis_data;
	Title 'q5_1_how_comfortable_are_you Selected Model';
	MODEL q5_1_how_comfortable_are_you = 
		q6_1_how_good_is_your_present
		q7_1_how_able_are_you_to_inte
		q8_1_how_self_assured_do_you
		q9_1_how_able_are_you_to_inte
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q12_1_how_effective_are_the_te
		q13_1_how_able_are_you_to_meet
		q14_1_how_able_are_you_to_prot; 
RUN;

PROC REG DATA = analysis_data;
	Title 'q10_1_how_comfortable_are_you All Possible Models (Include Experience Level)';
	MODEL q5_1_how_comfortable_are_you = 
		q6_1_how_good_is_your_present
		q7_1_how_able_are_you_to_inte
		q8_1_how_self_assured_do_you
		q9_1_how_able_are_you_to_inte
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q12_1_how_effective_are_the_te
		q13_1_how_able_are_you_to_meet
		q14_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3 /
		SELECTION = RSQUARE CP MSE;
RUN;

/* Selected Model */

PROC REG DATA = analysis_data;
	Title 'q5_1_how_comfortable_are_you Selected Model (Include Experience Level)';
	MODEL q5_1_how_comfortable_are_you = 
		q6_1_how_good_is_your_present
		q7_1_how_able_are_you_to_inte
		q8_1_how_self_assured_do_you
		q9_1_how_able_are_you_to_inte
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q12_1_how_effective_are_the_te
		q13_1_how_able_are_you_to_meet
		q14_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3; 
RUN;

PROC REG DATA = analysis_data;
	Title 'q5_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)';
	MODEL q5_1_how_comfortable_are_you = 
		q6_1_how_good_is_your_present
		q7_1_how_able_are_you_to_inte
		q8_1_how_self_assured_do_you
		q9_1_how_able_are_you_to_inte
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q12_1_how_effective_are_the_te
		q13_1_how_able_are_you_to_meet
		q14_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3
		/ COLLIN;; 
RUN;


PROC REG DATA = analysis_data;
	Title 'q5_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)(Remove q13_1_how_able_are_you_to_meet)';
	MODEL q5_1_how_comfortable_are_you = 
		q6_1_how_good_is_your_present
		q7_1_how_able_are_you_to_inte
		q8_1_how_self_assured_do_you
		q9_1_how_able_are_you_to_inte
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q12_1_how_effective_are_the_te
		q14_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3
		/ COLLIN;; 
RUN;


PROC REG DATA = analysis_data;
	Title 'q5_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)(Remove q13_1_how_able_are_you_to_meet, q8_1_how_self_assured_do_you)';
	MODEL q5_1_how_comfortable_are_you = 
		q6_1_how_good_is_your_present
		q7_1_how_able_are_you_to_inte
		q9_1_how_able_are_you_to_inte
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q12_1_how_effective_are_the_te
		q14_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3
		/ COLLIN;; 
RUN;


PROC REG DATA = analysis_data;
	Title 'q5_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)(Remove q13_1_how_able_are_you_to_meet, q8_1_how_self_assured_do_you,q9_1_how_able_are_you_to_inte )';
	MODEL q5_1_how_comfortable_are_you = 
		q6_1_how_good_is_your_present
		q7_1_how_able_are_you_to_inte
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q12_1_how_effective_are_the_te
		q14_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3
		/ COLLIN;; 
RUN;


PROC REG DATA = analysis_data;
	Title 'q5_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)(Remove q13_1_how_able_are_you_to_meet, q8_1_how_self_assured_do_you,q9_1_how_able_are_you_to_inte, q12_1_how_effective_are_the_te )';
	MODEL q5_1_how_comfortable_are_you = 
		q6_1_how_good_is_your_present
		q7_1_how_able_are_you_to_inte
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q14_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3
		/ COLLIN;; 
RUN;


PROC REG DATA = analysis_data;
	Title 'q5_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)(Remove q13_1_how_able_are_you_to_meet, q8_1_how_self_assured_do_you,q9_1_how_able_are_you_to_inte, q12_1_how_effective_are_the_te, q7_1_how_able_are_you_to_inte )';
	MODEL q5_1_how_comfortable_are_you = 
		q6_1_how_good_is_your_present
		q10_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q14_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3
		/ COLLIN;; 
RUN;


PROC REG DATA = analysis_data;
	Title 'q5_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)(Remove q13_1_how_able_are_you_to_meet, q8_1_how_self_assured_do_you,q9_1_how_able_are_you_to_inte, q12_1_how_effective_are_the_te, q7_1_how_able_are_you_to_inte, q10_1_how_good_is_your_present )';
	MODEL q5_1_how_comfortable_are_you = 
		q6_1_how_good_is_your_present
		q11_1_how_safe_do_you_feel_aro
		q14_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3
		/ COLLIN;; 
RUN;

PROC REG DATA = analysis_data;
	Title 'q5_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)(Remove q13_1_how_able_are_you_to_meet, q8_1_how_self_assured_do_you,q9_1_how_able_are_you_to_inte, q12_1_how_effective_are_the_te, q7_1_how_able_are_you_to_inte, q10_1_how_good_is_your_present,q6_1_how_good_is_your_present  )';
	MODEL q5_1_how_comfortable_are_you = 
		q11_1_how_safe_do_you_feel_aro
		q14_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3
		/ COLLIN;; 
RUN;

PROC REG DATA = analysis_data;
	Title 'q5_1_how_comfortable_are_you Selected Model (Include Experience Level)(Collinearity)(Remove q13_1_how_able_are_you_to_meet, q8_1_how_self_assured_do_you,q9_1_how_able_are_you_to_inte, q12_1_how_effective_are_the_te, q7_1_how_able_are_you_to_inte, q10_1_how_good_is_your_present,q6_1_how_good_is_your_present,q11_1_how_safe_do_you_feel_aro   )';
	MODEL q5_1_how_comfortable_are_you = 
		q14_1_how_able_are_you_to_prot
		Exp1
		Exp2
		Exp3
		/ COLLIN;; 
RUN;

SAS to Python

The equivalences the notebook relies on. Where there is no equivalent, that is deliberate.

Procedure-level mapping.
SASPythonNote
proc import ... range="Sheet0$A2:0"pd.read_excel(path, header=1)Handles the two header rows
input(var, best32.)pd.to_numeric(s, errors="coerce")Both turn a failed conversion into missing, silently
PROC MEANS N NMISS MEAN STDdf.agg([...])Always inspect NMISS after converting
PROC FREQvalue_counts()
PROC UNIVARIATE PLOThist(), scipy.stats.shapiroPLOT alone does not test normality
PROC SQL INNER JOINdf.merge(other, on=key)Both fan out on duplicate keys
PROC TTEST ... PAIRED a * bscipy.stats.ttest_relBoth drop incomplete pairs
PROC REG MODEL y = x1 x2sm.OLS(y, add_constant(X)).fit()
PROC REG / COLLINvariance_inflation_factorVIF is the readable form of the same diagnostic
PROC REG / SELECTION = RSQUARE CP MSEno equivalent, deliberatelySelecting and reporting fit on one dataset biases the fit

Running the SAS

These programs were executed on the West Chester University Apporto virtual desktop on June 27, 2025. The proc import paths are Windows UNC paths into that environment and will not resolve anywhere else, so the path is the first thing to change if a program is run elsewhere. Everything else is portable SAS 9.4.

The executed output for each program, and the formatted program listing, are linked from each section above.