Run it in the browser
The notebook loads the response matrix, scores the four UTAUT constructs, runs the one-sample comparisons against the scale midpoint, and adds confidence intervals, bootstrap effect sizes, reliability, normality checks with a distribution-free alternative, and a Holm correction.
The notebook ships with the response data. Unlike most survey files, this one carries no identifiers at all: 19 rows, 18 columns, every value an integer from 1 to 5, with no participant code, timestamp or free text. It is embedded in the notebook so every cell runs with no setup and reproduces the real figures rather than simulated ones.
The pipeline
Read the spreadsheet and split the header row from the responses.
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 afterwards. There are no missing values here.
Average each construct's items: Q1–Q6, Q7–Q10, Q11–Q15, Q16–Q18. Scores stay on the original 1 to 5 scale.
PROC MEANS and PROC FREQ for the descriptives, then a
one-sample comparison of each construct against the midpoint of 3.
One change was made to the program before publishing it. The
original proc import read from a Windows UNC path on the university's
virtual desktop, which included an account identifier. That is now a
&datapath. macro variable set at the top, which both removes the
identifier and makes the program runnable elsewhere. Nothing else was altered.
The SAS program
VRSurveyAnalysis.sas, 331 lines.
Source on GitHub The analysis it produced
Show the full program (331 lines)
VRSurveyAnalysis.sasSAS/* Path to the survey export. Set this before running. The original ran from a WCU Apporto virtual desktop; that path resolves nowhere else, and it contained an account ID that does not belong in a public repository. */ %let datapath = C:\path\to\VR Survey Data.xlsx; /* 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; proc import datafile="&datapath." out=raw_data dbms=xlsx replace; getnames=no; run; proc print data=raw_data(OBS=5); run; /*Use first row as header and create actual variable names */ data headers labels data_clean; set raw_data; if _n_ = 1 then output headers; /* First row = header */ else output data_clean; /* Actual data starts from 3rd row */ run; proc print data=data_clean(OBS=5); run; data vr_survey_data; set data_clean ( rename= ( A = Q01_PFM_solve_problems B = Q02_PFM_life_easier C = Q03_PFM_accmp_task D = Q04_PFM_incr_productivity E = Q05_PFM_useful_daily_life F = Q06_PFM_responsibility G = Q07_SOC_encourage_to_use H = Q08_SOC_important_use I = Q09_SOC_think_i_should J = Q10_SOC_find_it_helpful K = Q11_EFF_easy_for_me L = Q12_EFF_easy_to_use M = Q13_EFF_without_hassle N = Q14_EFF_interaction_clear O = Q15_EFF_not_difficult P = Q16_FAC_easily_get_tech Q = Q17_FAC_know_who_contact R = Q18_FAC_reach_info )); run; proc print data=vr_survey_data(OBS=5); run; data final_vr_survey_data; set vr_survey_data; /*Convert to numeric*/ numeric_01 = input(Q01_PFM_solve_problems, best32.); numeric_02 = input(Q02_PFM_life_easier, best32.); numeric_03 = input(Q03_PFM_accmp_task, best32.); numeric_04 = input(Q04_PFM_incr_productivity, best32.); numeric_05 = input(Q05_PFM_useful_daily_life, best32.); numeric_06 = input(Q06_PFM_responsibility, best32.); numeric_07 = input(Q07_SOC_encourage_to_use, best32.); numeric_08 = input(Q08_SOC_important_use, best32.); numeric_09 = input(Q09_SOC_think_i_should, best32.); numeric_10 = input(Q10_SOC_find_it_helpful, best32.); numeric_11 = input(Q11_EFF_easy_for_me, best32.); numeric_12 = input(Q12_EFF_easy_to_use, best32.); numeric_13 = input(Q13_EFF_without_hassle, best32.); numeric_14 = input(Q14_EFF_interaction_clear, best32.); numeric_15 = input(Q15_EFF_not_difficult, best32.); numeric_16 = input(Q16_FAC_easily_get_tech, best32.); numeric_17 = input(Q17_FAC_know_who_contact, best32.); numeric_18 = input(Q18_FAC_reach_info, best32.); drop Q01_PFM_solve_problems Q02_PFM_life_easier Q03_PFM_accmp_task Q04_PFM_incr_productivity Q05_PFM_useful_daily_life Q06_PFM_responsibility Q07_SOC_encourage_to_use Q08_SOC_important_use Q09_SOC_think_i_should Q10_SOC_find_it_helpful Q11_EFF_easy_for_me Q12_EFF_easy_to_use Q13_EFF_without_hassle Q14_EFF_interaction_clear Q15_EFF_not_difficult Q16_FAC_easily_get_tech Q17_FAC_know_who_contact Q18_FAC_reach_info; rename numeric_01 = Q01_PFM_solve_problems numeric_02 = Q02_PFM_life_easier numeric_03 = Q03_PFM_accmp_task numeric_04 = Q04_PFM_incr_productivity numeric_05 = Q05_PFM_useful_daily_life numeric_06 = Q06_PFM_responsibility numeric_07 = Q07_SOC_encourage_to_use numeric_08 = Q08_SOC_important_use numeric_09 = Q09_SOC_think_i_should numeric_10 = Q10_SOC_find_it_helpful numeric_11 = Q11_EFF_easy_for_me numeric_12 = Q12_EFF_easy_to_use numeric_13 = Q13_EFF_without_hassle numeric_14 = Q14_EFF_interaction_clear numeric_15 = Q15_EFF_not_difficult numeric_16 = Q16_FAC_easily_get_tech numeric_17 = Q17_FAC_know_who_contact numeric_18 = Q18_FAC_reach_info; RUN; PROC CONTENTS DATA=final_vr_survey_data; RUN; /* --- Descriptive Statistics for Performance Expectancy --- */ PROC MEANS DATA=final_vr_survey_data MEAN MEDIAN MODE STD; VAR Q01_PFM_solve_problems Q02_PFM_life_easier Q03_PFM_accmp_task Q04_PFM_incr_productivity Q05_PFM_useful_daily_life Q06_PFM_responsibility Q07_SOC_encourage_to_use Q08_SOC_important_use Q09_SOC_think_i_should Q10_SOC_find_it_helpful Q11_EFF_easy_for_me Q12_EFF_easy_to_use Q13_EFF_without_hassle Q14_EFF_interaction_clear Q15_EFF_not_difficult Q16_FAC_easily_get_tech Q17_FAC_know_who_contact Q18_FAC_reach_info; TITLE 'Statistical Analysis of VR Survey Individual Questions (Mean, Median, Std Dev)'; RUN; PROC FORMAT; VALUE survey_scale 1 = 'Strongly Disagree' 2 = 'Disagree' 3 = 'Neither Agree nor Disagree' 4 = 'Agree' 5 = 'Strongly Agree'; RUN; PROC FREQ DATA=final_vr_survey_data; TABLE Q01_PFM_solve_problems Q02_PFM_life_easier Q03_PFM_accmp_task Q04_PFM_incr_productivity Q05_PFM_useful_daily_life Q06_PFM_responsibility Q07_SOC_encourage_to_use Q08_SOC_important_use Q09_SOC_think_i_should Q10_SOC_find_it_helpful Q11_EFF_easy_for_me Q12_EFF_easy_to_use Q13_EFF_without_hassle Q14_EFF_interaction_clear Q15_EFF_not_difficult Q16_FAC_easily_get_tech Q17_FAC_know_who_contact Q18_FAC_reach_info; FORMAT Q01_PFM_solve_problems Q02_PFM_life_easier Q03_PFM_accmp_task Q04_PFM_incr_productivity Q05_PFM_useful_daily_life Q06_PFM_responsibility Q07_SOC_encourage_to_use Q08_SOC_important_use Q09_SOC_think_i_should Q10_SOC_find_it_helpful Q11_EFF_easy_for_me Q12_EFF_easy_to_use Q13_EFF_without_hassle Q14_EFF_interaction_clear Q15_EFF_not_difficult Q16_FAC_easily_get_tech Q17_FAC_know_who_contact Q18_FAC_reach_info survey_scale.; TITLE "Frequency Counts of VR Survey Individual Questions"; RUN; proc sgplot data=final_vr_survey_data; histogram Q07_SOC_encourage_to_use / binwidth=1; xaxis values=(1 2 3 4 5) valuesformat=survey_scale.; yaxis label="Frequency"; title "Distribution of Q07_SOC_encourage_to_use"; run; proc sgplot data=final_vr_survey_data; histogram Q17_FAC_know_who_contact / binwidth=1; xaxis values=(1 2 3 4 5) valuesformat=survey_scale.; yaxis label="Frequency"; title "Distribution of Q17_FAC_know_who_contact"; run; DATA vr_survey_composite; SET final_vr_survey_data; /* Calculate Performance Expectancy composite score (average of Q1-Q6) */ Performance_Expectancy = (Q01_PFM_solve_problems + Q02_PFM_life_easier + Q03_PFM_accmp_task + Q04_PFM_incr_productivity + Q05_PFM_useful_daily_life + Q06_PFM_responsibility) / 6; /* Calculate Social Influence composite score (average of Q7-Q10) */ Social_Influence = (Q07_SOC_encourage_to_use + Q08_SOC_important_use + Q09_SOC_think_i_should + Q10_SOC_find_it_helpful) / 4; /* Calculate Effort Expectancy composite score (average of Q11-Q15) */ Effort_Expectancy = (Q11_EFF_easy_for_me + Q12_EFF_easy_to_use + Q13_EFF_without_hassle + Q14_EFF_interaction_clear + Q15_EFF_not_difficult) / 5; /* Calculate Facilitating Conditions composite score (average of Q16-Q18) */ Facilitating_Conditions = (Q16_FAC_easily_get_tech + Q17_FAC_know_who_contact + Q18_FAC_reach_info) / 3; RUN; PROC MEANS DATA=vr_survey_composite MEAN MEDIAN STDDEV; VAR Performance_Expectancy Social_Influence Effort_Expectancy Facilitating_Conditions; TITLE 'Statistical Analysis of VR Survey Question Groups (Mean, Median, Std Dev)'; RUN; /* --- Cronbach's Alpha for Performance Expectancy --- */ ods graphics on; title 'Cronbachs Alpha for Performance Expectancy'; PROC CORR DATA=final_vr_survey_data NOMISS ALPHA; VAR Q01_PFM_solve_problems Q02_PFM_life_easier Q03_PFM_accmp_task Q04_PFM_incr_productivity Q05_PFM_useful_daily_life Q06_PFM_responsibility; RUN; title 'Cronbachs Alpha for Social Influence'; PROC CORR DATA=final_vr_survey_data NOMISS ALPHA; VAR Q07_SOC_encourage_to_use Q08_SOC_important_use Q09_SOC_think_i_should Q10_SOC_find_it_helpful; RUN; title 'Cronbachs Alpha for Effort Expectancy'; PROC CORR DATA=final_vr_survey_data NOMISS ALPHA; VAR Q11_EFF_easy_for_me Q12_EFF_easy_to_use Q13_EFF_without_hassle Q14_EFF_interaction_clear Q15_EFF_not_difficult; RUN; title 'Cronbachs Alpha for Facilitating Conditions'; PROC CORR DATA=final_vr_survey_data NOMISS ALPHA; VAR Q16_FAC_easily_get_tech Q17_FAC_know_who_contact Q18_FAC_reach_info; RUN; /* ========================================================= INTERPRETATION GUIDELINES FOR CRONBACH'S ALPHA: a = 0.9 = Excellent reliability a = 0.8 = Good reliability a = 0.7 = Acceptable reliability a = 0.6 = Questionable reliability a < 0.6 = Poor reliability =========================================================== */ data alpha_summary; length construct $30 reliability $25; format alpha 8.2; input construct $ 1-30 alpha items reliability $; datalines; Performance_Expectancy 0.91 6 Excellent_Reliability Social_Influence 0.93 4 Excellent_Reliability Effort_Expectancy 0.84 5 Good_Reliability Facilitating_Conditions 0.70 3 Acceptable_Reliability ; run; proc print data=alpha_summary noobs; title "Summary of Cronbach's Alpha Values for All Constructs"; run; title "Spearman's Correlation Matrix for Individual Questions"; PROC CORR DATA=final_vr_survey_data SPEARMAN NOMISS; VAR Q01_PFM_solve_problems Q02_PFM_life_easier Q03_PFM_accmp_task Q04_PFM_incr_productivity Q05_PFM_useful_daily_life Q06_PFM_responsibility Q07_SOC_encourage_to_use Q08_SOC_important_use Q09_SOC_think_i_should Q10_SOC_find_it_helpful Q11_EFF_easy_for_me Q12_EFF_easy_to_use Q13_EFF_without_hassle Q14_EFF_interaction_clear Q15_EFF_not_difficult Q16_FAC_easily_get_tech Q17_FAC_know_who_contact Q18_FAC_reach_info; RUN;
SAS to Python
| SAS | Python | Note |
|---|---|---|
proc import ... dbms=xlsx | pd.read_excel(path) | |
input(var, best32.) | pd.to_numeric(s, errors="coerce") | Both turn a failed conversion into missing, silently |
PROC MEANS MEAN MEDIAN MODE STD | df.agg([...]) | Check NMISS after converting |
PROC FREQ | value_counts() | |
PROC SGPLOT VBAR | matplotlib, or inline SVG | The site's charts are SVG so they follow light and dark mode |
PROC TTEST H0=3 | scipy.stats.ttest_1samp(x, 3) | The comparison value must be stated; here it is the scale midpoint |
| no equivalent in the program | scipy.stats.shapiro, wilcoxon | Assumption check and distribution-free alternative |
| no equivalent in the program | bootstrap, Holm, Cronbach's alpha | Added here; see the analysis page |
Rebuilding this site
The repository contains the whole pipeline, not just the output. Everything that
needs the response file writes aggregate JSON into tools/derived/, which is
committed, so every page rebuilds on a fresh checkout.
bash tools/build.sh # rebuild the pages from committed data bash tools/build.sh --all # also recompute from the response file