Created
May 10, 2024 15:11
-
-
Save statgeek/b55d964c99975c2ba23fa771afe616bc to your computer and use it in GitHub Desktop.
TableN Macro - Author Jeff Meyers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*------------------------------------------------------------------* | |
| MACRO NAME : tablen | |
| SHORT DESC : Creates a descriptives table of multiple variables | |
*------------------------------------------------------------------* | |
| CREATED BY : Meyers, Jeffrey (07/28/2016 3:00) | |
*------------------------------------------------------------------* | |
| VERSION UPDATES: | |
| 2.46 11/03/2021 | |
| Changed code to avoid truncating character strings at 200 | |
| 2.45 08/25/2021 | |
| Corrected issues with merging single row statistics with label row | |
| Added parameter FORCE_MULTIPLE_ROWS to force a single statistic to be on a separate row | |
from label | |
| Added parameter SHOW_LABEL_STATISTIC to remove statistic from label when only one statistic | |
is chosen | |
| Added logic code for when number of observations<number of by groups for continuous variables | |
| 2.44 07/14/2021 | |
| Corrected frozen headers in the excel destination. | |
| 2.43 05/13/2021 | |
| Removed START_AT option from ODS EXCEL output. | |
| Added TOTAL_COL_POS to change the position of the total column to be | |
before or after the BY variable columns. | |
| Fixed issue where stat would be appended to label when 2 continuous stats were listed | |
| Added code to try to detect and change space special characters to regular spaces. | |
| 2.42 04/16/2021 | |
| Corrected issues using END option to evaluate the WHERE clause | |
| Corrected issue with total column percentages when multiple discrete variables present | |
| 2.41 04/12/2021 | |
| Corrected issue when DIS_ORDER=FREQA or FREQD | |
| Added error checking for when WHERE clause fails | |
| Added error checking for when no DISCRETE type variables have >1 level in the data | |
| Added code to ensure all levels have counts across COLBY levels | |
| 2.4 03/24/2021 | |
| Added DIS_MISSPRINT=3 option to add denominators instead of a N missing row | |
| Now allows different display options for each variable (e.g. CONTDISPLAY) | |
| Only having one item for a DISPLAY (e.g. CONTDISPLAY) or DIS_ORDER will | |
collapse the variable's output into one row. The label can still be | |
overwritten by the LABELS option | |
| 2.38 04/23/2020 | |
| Added FREQ parameter for datasets with a variable containing frequency of observations | |
| Added FREQA and FREQD options for DIS_ORDER paramater to order by ascending | |
or descending counts | |
| 2.37 04/08/2020 | |
| Updated BORDERDISPLAY options for HTML output | |
| Fixed several bugs with significant digits | |
| 2.36 03/23/2020 | |
| Removed LOG_REFERENCE since it was not used. REFERENCE should be used | |
| Updates for Windows SAS | |
| 2.35 03/4/2020 | |
| Added a debug option that will keep notes on and not delete temporary datasets | |
| 2.34 02/21/2020 | |
| Corrected issue with BORDERDISPLAY=4 in PDF destination | |
| Made fix to not show . in separating columns when using COLBY in Windows | |
| 2.33 02/12/2020 | |
| Corrected footnote for likelihood-ratio p-value | |
Corrected text in error message for logistic p-values | |
| 2.32 10/01/2019 | |
| Corrected an issue with continuous variables when the BY variable | |
has a missing value. | |
| 2.31 07/26/2019 | |
| Corrected a nesting error when a larger number of variables | |
of the same type are listed. | |
| 2.3 07/24/2019 | |
| Corrected an error when changing orientation that caused the macro | |
to make a sasrtf.rtf file and not correctly change the orientation | |
when using OUTDOC | |
| Added ability to use different significant digits with each variable. | |
can be used to distinguish between variable in each parameter. | |
| 2.2 05/13/2019 | |
| Added logic to avoid errors when only one level of BY variable | |
has values for all continuous variables. | |
| 2.1 04/15/2019 | |
| Corrected issue with survival output not including TIMELIST values | |
| 2.0 04/06/2019 | |
| Updated process to improve efficiency | |
| 1.94 04/05/2019 | |
| Corrected issue with listing output | |
| Corrected issue in survival section | |
| 1.93 11/12/2018 | |
| Corrected spaces causing issues for DIS_ORDER | |
| Corrected SQL issue for Cochran-armitage p-value | |
| 1.92 11/11/2018 | |
| Corrected ORIENTATION option | |
| Corrected SQL issue for continuous ANOVA | |
| 1.91 10/23/2018 | |
| Added value 4 to BORDERDISPLAY to remove horizontal lines | |
within each variable | |
| 1.9 09/19/2018 | |
| Fixed an issue where the label wouldn't show up for a continuous | |
| variable when only one BY group has non-missing values. | |
| 1.8 08/02/2018 | |
| Added BORDERDISPLAY to turn on/off table cell borders | |
| Added type=5 for univariate LOGISTIC regression | |
Can display counts, events, odds ratios, p-values and binomial success rates | |
| 1.7 01/16/2018 | |
| Corrected missing p-values when using dis_order to only show | |
one level of discrete variable. | |
| 1.6 01/06/2018 | |
| Corrected missing labels when discrete variable only has one | |
level. | |
| 1.5 12/21/2017 | |
| Corrected line size calculations for printing to listing when | |
using a BY variable | |
| 1.4 12/13/2017 | |
| Added MEDIAN_IQR to CONTDISPLAY and DATEDISPLAY. | |
| Changed references to NTABLE to TABLEN | |
| 1.3 11/30/2017 | |
| Corrected order of ROWBY | |
| Changed missing values of ROWBY and COLBY to show as Missing group | |
in table | |
| 1.2 11/27/2017 | |
| Restructured logic for completing tables to be printed for efficiency | |
| Added extra programming for RTF location | |
| Added new option for SHOWPVAL: 2. Shows continuous variable p-values | |
when no BY variable is specified | |
| 1.1 11/13/2017 | |
| Corrected multiple logic errors | |
| Added parameter PFOOT to remove automatic p-value footnotes | |
| Changed ordering of BY, COLBY, ROWBY, and discrete variables to be | |
by internal values by default, and added a ORDER_FORMATTED parameter | |
for each to determine if the order is by formatted or unformatted values. | |
| Added additional coding to frozen headers in Excel documents. | |
| Extended maximum label size for variables to be 1000 characters from 100 | |
| 1.0 09/24/2017: Initial Release | |
*------------------------------------------------------------------* | |
| PURPOSE | |
| Create a descriptives table of multiple variables (often called | |
| Table 1 in a manuscript). Continuous, Discrete and Survival variables are | |
| handled differently. Multiple subgroup options are available for | |
| comparisons and different p-values are available for each variable | |
| type. | |
| | |
| 1.0: REQUIRED PARAMETERS | |
| DATA = Specifies the dataset to be used in the macro | |
| VAR = A space delimited list of variables to compute distributions on | |
| TYPE = A space delimited list of values that determines the type for | |
| each variable in the VAR list. Options are 1, 2, 3 and 4. If | |
| the user doesn't specify a TYPE for every VAR then the last listed | |
| type is carried through. The allowable types are as follows: | |
| 1 = Continuous variable. Must be numeric | |
| 2 = Discrete variable. Can be numeric or character | |
| 3 = Date variable. Must be numeric | |
| 4 = Survival time variable. Must be numeric. See section 2.3.4 | |
| 5 = Logistic event variable. See section 2.3.5 | |
| 2.0: OPTIONAL PARAMETERS | |
| 2.1: Subgroup Options | |
| 2.1.1: BY variable Options - Comparisons including p-values | |
| BY = Determines a variable to separate VAR variables into groups for comparison. | |
| Will create one column per level of BY (potentially including missing values) | |
| and will enable p-value comparisons based on PVALS. | |
| BYORDER = Determines the order that the levels of BY variable are shown. Leaving this | |
| missing causes the values to be listed in the order determined by BYORDER_FORMATTED. | |
| Order should be determined by a space delimited numbered list where each | |
| number corresponds to the default order of the BY variable. For example | |
| a GENDER character variable could have values of MALE and FEMALE. Default would list | |
| these values in the order FEMALE then MALE. Specifying BYORDER=2 1 would | |
| change this order to be MALE then FEMALE. Missing values of BY will always | |
| show up as the far left column if enabled. | |
| BYORDER_FORMATTED = Determines if default order of BY variable is the formatted | |
| values. Options are 0 (no) or 1 (yes). Default is 0. | |
| BYLABEL = Determines the label for the BY variable. Default will pull from the dataset. | |
| BY_INCMISS = Determines if missing values are considered a level for comparison in | |
| percentages and p-values. Options are 0 (no) and 1 (yes).Default is 0. | |
| BY_PRINTMISS = Determines if missing values are printed in the table. Options are: | |
| 0 = Do not print unless BY_INCMISS=1 and missing values are present | |
| 1 = Prints column if missing values are present or BY_INCMISS=1 | |
| 2 = Always prints column even if there are no missing values | |
| Default is 1. | |
| 2.1.2: COLBY (Column By) variable Options - Comparisons not including p-values | |
| COLBY = Determines a variable to repeat distributions within subgroups horizontally | |
| in the table. If COLBY has two levels, then 2 independent sets of distributions | |
| are displayed in the table. P-values are not calculated comparing the subgroups | |
| created by this variable. | |
| COLBYORDER = Determines the order that the levels of COLBY variable are shown. Leaving this | |
| missing causes the values to be listed in the order determined by COLBYORDER_FORMATTED. | |
| See BYORDER for details on use. | |
| COLBYORDER_FORMATTED = Determines if default order of COLBY variable is the formatted | |
| values. Options are 0 (no) or 1 (yes). Default is 0. | |
| COLBYLABEL = Determines the label for the COLBY variable. Default will pull from the dataset. | |
| 2.1.3: ROWBY (Row By) variable Options - Comparisons not including p-values | |
| ROWBY = Determines a variable to repeat distributions within subgroups horizontally | |
| in the table. If ROWBY has two levels, then 2 independent sets of distributions | |
| are displayed in the table. P-values are not calculated comparing the subgroups | |
| created by this variable. | |
| ROWBYORDER = Determines the order that the levels of ROWBY variable are shown. Leaving this | |
| missing causes the values to be listed in the order determined by ROWBYORDER_FORMATTED. | |
| See BYORDER for details on use. | |
| ROWBYORDER_FORMATTED = Determines if default order of ROWBY variable is the formatted | |
| values. Options are 0 (no) or 1 (yes). Default is 0. | |
| ROWBYLABEL = Determines the label for the ROWBY variable. Default will pull from the dataset. | |
| 2.1.4: Subset input dataset | |
| WHERE = Allows a where clause to subset the input dataset within the macro. List exactly as | |
| a where clause within a procedure. Example: WHERE=arm='A' | |
| 2.2: P-value Options | |
| PVALS = A space delimited list of values that determines the p-value for | |
| each variable in the VAR list. Options depend on the TYPE of variable. If | |
| the user doesn't specify a p-value for every VAR then the last listed | |
| type is carried through. The allowable types are as follows: | |
| Continuous or Date Variables: | |
| If BY variable is present | |
| 0 = No p-value | |
| 1 = Kruskal-Wallis | |
| 2 = Exact Kruskal-Wallis (long calculation times) | |
| 3 = Wilcoxon rank sum | |
| 4 = Exact Wilcoxon rank sum (long calculation times) | |
| 5 = ANOVA F-test | |
| 6 = Equal variance two sample t-test | |
| 7 = Unequal variance two sample t-test | |
| If BY variable is not present | |
| 0 = No p-value | |
| 1 = Student T-Test | |
| 2 = Sign Rank | |
| Discrete Variables: | |
| If BY variable is present | |
| 0 = No p-value | |
| 1 = Chi-square | |
| 2 = Fisher's exact | |
| 3 = Cochran-Armitage trend test (Either BY or VAR must have 2 levels only) | |
| Survival Variables: | |
| If BY variable is present | |
| 0 = No p-value | |
| 1 = Logrank | |
| 2 = Wilcoxon | |
| 3 = Cox model type-3 score | |
| 4 = Cox model type-3 likelihood-ratio | |
| 5 = Cox model type-3 Wald | |
| Logistic Variables: | |
| If odds ratios are calculated | |
| 0 = No p-value | |
| 1 = type-3 Wald | |
| 2 = Chi-square | |
| 3 = Fisher's exact | |
| Otherwise | |
| 0 = No p-value | |
| 1 = Chi-square | |
| 2 = Fisher's exact | |
| 2.3: Variable Display Options | |
| 2.3.1: Continuous Variables | |
| CONTDISPLAY = Determines which descriptive statistics are calculated for numeric variables. | |
| Options are the following in a space delimited list. Items are shown in the order they are listed. | |
| These options can be changed for each continuous variable by using the | delimiter. | |
| N = Number of non-missing records | |
| NMISS = Number of missing records | |
| N_NMISS = Combines N and NMISS as N (NMISS) | |
| MEAN = Mean of the distribution | |
| SD = Standard Deviation of the distribution | |
| MEAN_SD = Combines Mean and SD as MEAN (SD) | |
| MEDIAN = Median of the distribution | |
| RANGE = Range of the distribution as MIN, MAX | |
| IQR = Interquartile range of the distribution as Q1, Q3 | |
| MEDIAN_RANGE = Combines Median and Range as MEDIAN (MIN, MAX) | |
| MEDIAN_IQR = Combines Median and IQR as MEDIAN (Q1, Q3) | |
| Default is N MEAN_SD MEDIAN RANGE. | |
| 2.3.2: Discrete Variables | |
| DIS_DISPLAY = Determines which descriptive statistics are calculated for numeric variables. | |
| Options are the following: | |
| N = Number within that level | |
| PCT = Percentage within that level. Percentage depends on PCTDISPLAY | |
| N_PCT = Combines N and PCT as N (PCT) | |
| DIS_ORDER = Determines the order that the discrete variable levels are shown. Leaving this | |
| missing causes the values to be listed in the order determined by DIS_ORDER_FORMATTED. | |
| Order can be determined in two ways: | |
| 1) The keywords FREQA (total ascending) or FREQD (total descending) | |
| 2) A space delimited numbered list where each | |
| number corresponds to the alphabetical order of the discrete variable. For example | |
| a GENDER character variable could have values of MALE and FEMALE. Default would list | |
| these values in the order FEMALE then MALE. Specifying DIS_ORDER=2 1 would | |
| change this order to be MALE then FEMALE. | |
| | |
| If there are multiple discrete variables then each can be provided their own list by | |
| separting lists with the | (capital \) symbol. For example, if there are two variables | |
| ARM and GENDER, the orders for each can be modified with DIS_ORDER=3 1 2|2 1. Leave | |
| missing if alphabetical is desired (DIS_ORDER=3 1 2| ). | |
| | |
| DIS_ORDER knows to skip over other types so missing values do | |
| not need to be entered for TYPE 1, 3 or 4 variables. | |
| | |
| The user does not need to specify every level of the discrete variable. If only certain | |
| levels are to be shown such as only showing the Yes values of a Yes/No variable then | |
| user can specify DIS_ORDER=2. A warning will fire but this can be suppressed with DIS_ORDER_OVERRIDE | |
| DIS_ORDER_FORMATTED = Determines if default order of discrete variables is the formatted | |
| values. Options are 0 (no) or 1 (yes). Default is 0. | |
| DIS_ORDER_OVERRIDE = Flag variable to override the warning that comes with DIS_ORDER when not specifying | |
| all values. Options are 0 (no) and 1 (yes). Default is 0. | |
| DIS_INCMISS = Flag variable to determine if missing is a valid level of the discrete variables for percentages | |
| and p-values. Options are 0 (no) and 1 (yes). Default is 0. | |
| DIS_PRINTMISS = Flag variable to determine if missing values are printed for discrete values. Default is 1. | |
| 0 = Do not print unless DIS_INCMISS=1 and missing values are present | |
| 1 = Prints row if missing values are present or DIS_INCMISS=1 | |
| 2 = Always prints row even if there are no missing values | |
| 3 = Turns off missing row and instead adds denominators to variables with missing values. | |
| When PCTDISPLAY=COL will show for each column. When PCTDISPLAY=ROW will show in Total column only. | |
| DIS_MISSORDER = Determines if missing values are printed before or after other levels of discrete variables. | |
| Options are FIRST and LAST. Default is LAST. | |
| DIS_SUFFIX = Determines a suffix that is applied to the end of the label for each discrete variable. This is a | |
| text string that is literally concatenated to the label. Default is AUTO. when AUTO is specified, | |
| the following occurs: | |
| When DIS_DISPLAY=N_PCT then , n (%) | |
| When DIS_DISPLAY=N then , n | |
| When DIS_DISPLAY=PCT then , % | |
| PCTDISPLAY = Determines if percentages are row based or column based. Options are COL and ROW. Default is COL. | |
| 2.3.3: Date Variables | |
| DATEDISPLAY = Determines which descriptive statistics are calculated for date variables. | |
| Options are the following in a space delmited list. Items are shown in the order they are listed. | |
| These options can be changed for each date variable by using the | delimiter. | |
| N = Number of non-missing records | |
| NMISS = Number of missing records | |
| N_NMISS = Combines N and NMISS as N (NMISS) | |
| MEAN = Mean of the distribution | |
| SD = Standard Deviation of the distribution | |
| MEAN_SD = Combines Mean and SD as MEAN (SD) | |
| MEDIAN = Median of the distribution | |
| RANGE = Range of the distribution as MIN, MAX | |
| IQR = Interquartile range of the distribution as Q1, Q3 | |
| MEDIAN_RANGE = Combines Median and Range as MEDIAN (MIN, MAX) | |
| MEDIAN_IQR = Combines Median and IQR as MEDIAN (Q1, Q3) | |
| Default is N MEDIAN RANGE. | |
| DATEFMT = Determines the format for the date values. Default is MMDDYY10. | |
| 2.3.4: Survival Variables | |
| SURVDISPLAY = Determines which descriptive statistics are calculated for survival variables. | |
| Options are the following in a space delmited list. Items are shown in the order they are listed. | |
| These options can be changed for each survival variable by using the | delimiter. | |
| N = Number of patients | |
| EVENTS = Number of events | |
| EVENTS_N = Combines N and Events as EVENTS/N | |
| MEDIAN = Kaplan-Meier survival median and 95% CI | |
| HR = Cox model hazard ratio and 95% CI | |
| COXPVAL = Cox model Wald p-value comparing parameters | |
| TIMELIST = Kaplan-Meier time-point event-free rates and 95% CI | |
| Default is EVENTS_N MEDIAN TIMELIST HR COXPVAL. | |
| SURV_STAT = A space delimited list of variables to containing the censoring values for each | |
| survival variable. The first variable in this list will be matched to the first | |
| TYPE=4 variable in the VAR parameter and so on. | |
| CEN_VL = A space delimited list of censor values. If the user doesn't specify a value for every survival variable | |
| then the last value is carried through. | |
| TIMELIST = A space delimited list of time-points to calculate Kaplan-Meier time-point event-free rates. Separate | |
| time lists must be specified for each survival variable by using the | (capital \) symbol. | |
| example: survival variables FU_TIME and DFS_TIME. Specify TIMELIST=0.5 2|3 5 7 to get the time-point | |
| estimates for FU_TIME at 0.5 and 2, and time-point estimates for DFS_TIME at 3, 5 and 7. | |
| TIME_UNITS = Specifies a unit for the survival variables to be concatenated with the timelist estimates. | |
| Example: TIMELIST=1 and TIME_UNITS=years will make "1 year est (95% CI)" in the table. | |
| TDIVISOR = Specifies a scalar value to multiply the survival variable time values by. Separate values can be specified | |
| for each survival time variable with a space delimted list. If no values are listed then the default is 1 (no change). | |
| REFERENCE = Specifies a value of the BY variable to be used as a reference within a Cox model. The | |
| reference should be the formatted value of the variable. Reference value must exist within all levels | |
| of COLBY and ROWBY if specified. | |
| CONFTYPE = Sets the confidence limit types for the Kaplan-Meier medians and time-point event-free rates. Options are | |
| LOG, ASINSQRT, LOGLOG, LINEAR, and LOGIT. Default is LOG. | |
| TIMELISTFMT = Determines the format for the Kaplan-Meier time-point event-free rates. Options are PPT (proportion) or PCT (Percent). | |
| Default is PPT. | |
| 2.3.5: Logistic Regression Variables | |
| LOG_EVENT = The logistic regression event for the dependent variable specified in VAR. Must match the formatted value exactly. | |
| LOG_DISPLAY = Determines which descriptive statistics are calculated for logistic regression variables. | |
| Options are the following in a space delmited list. Items are shown in the order they are listed. | |
| These options can be changed for each logistic variable by using the | delimiter. | |
| N = Number of patients | |
| EVENTS = Number of events | |
| EVENTS_N = Combines N and Events as EVENTS/N | |
| ODDSRATIO = logistic regression odds ratio of the BY variable | |
| WALDPVAL = logistic regression Wald p-value comparing parameters | |
| BINRATE = Binomial success rate and 95% CI | |
| Default is EVENTS_N BINRATE ODDSRATIO WALDPVAL. | |
| LOG_CONFTYPE = Specifies the method used for the 95% CI of the binomial success rate. Options are BIN (Binomial) or | |
| BINEXACT (Binomial Exact). Default is BIN. | |
| LOG_BINFMT = Determines the format for the binomial success rates. Options are PPT (proportion) or PCT (Percent). | |
| Default is PPT. | |
| 2.3.6: All Variables | |
| LABELS = Sets the labels for the variables in the VAR parameter if the user wishes to override the labels | |
| in the dataset. Labels can be specified from variable to variable by using the | (capital \) symbol. | |
| Entering a blank value results in the label being pulled from the dataset. | |
| FREQ = Specifies a variable that contains the frequency of occurrence of each observation. Will be applied to all variable types. | |
| FORCE_MULTIPLE_ROWS = When only one statistic is selected the default behavior is to merge that statistic into the label row and | |
| add the statistic to the label text. When this is 1 the statistic is printed on its own row, and when this is 0 | |
| the statistic is printed in the same row as the label. Default is 0 | |
| SHOW_LABEL_STATISTIC = When only one statistic is selected the default behavior is to merge that statistic into the label row and | |
| add the statistic to the label text. When this is 1 the statistic is printed with the label, and when this is 0 | |
| the statistic is suppressed from the label. Default is 1 | |
| 2.4: Table Display Options | |
| 2.4.0: Table borders | |
| BORDERDISPLAY = Determines which borders are turned on for the table. Options are: | |
| 1 = Only horizontal borders in the header and footer | |
| 2 = All cell borders are left on | |
| 3 = All cell borders are left on except for titles and footnotes | |
| 4 = Frames around each variable's sections but no horizontal lines within each variable's section | |
| Default is 1. | |
| 2.4.1: Disable Certain Columns or Labels | |
| SHOWTOTAL = Determines if the total columns are displayed. Options are 0 (no) and 1 (yes). Default is 1. | |
| NOTE: this is ignored if there is no BY variable specified. | |
| TOTAL_COL_POS = Determines if TOTAL column is printed before or after BY columns. Options are START and END. Default is END. | |
| SHOWPVAL = Determines if the P-value columns are displayed. Options are 0 (no), 1 (yes when BY is specified), | |
| and 2 (yes with or without BY). Default is 1. | |
| SHOWBYLABEL = Determines if the BY variable label is displayed. Options are 0 (no) and 1 (yes). Default is 1. | |
| SHOWCOLLABEL = Determines if the COLBY label is displayed. Options are 0 (no) and 1 (yes). Default is 1. | |
| 2.4.2: Results Digit Rounding | |
| 2.4.2.1: Continuous Variables | |
| MEANDIGITS = Determines the rounding of decimals for the mean of continuous variables. Can set different digits | |
| for each variable with the | delimiter. | |
| MEDIANDIGITS = Determines the rounding of decimals for the median of continuous variables. Can set different digits | |
| for each variable with the | delimiter. | |
| STDDIGITS = Determines the rounding of decimals for the standard deviation of continuous variables. Can set different digits | |
| for each variable with the | delimiter. | |
| IQRDIGITS = Determines the rounding of decimals for the interquartile range of continuous variables. Can set different digits | |
| for each variable with the | delimiter. | |
| RANGEDIGITS = Determines the rounding of decimals for the range of continuous variables. Can set different digits | |
| for each variable with the | delimiter. | |
| 2.4.2.2: Discrete Variables | |
| PCTDIGITS = Determines the rounding of decimals for the percentages of discrete variables. Can set different digits | |
| for each variable with the | delimiter. | |
| 2.4.2.3: Survival Variables | |
| SMEDIANDIGITS = Determines the rounding of decimals for the Kaplan-Meier median of time-to-event and | |
| confidence bounds for survival variables. Can set different digits | |
| for each variable with the | delimiter. | |
| HRDIGITS = Determines the rounding of decimals for the hazard ratio and confidence bounds of survival variables. Can set different digits | |
| for each variable with the | delimiter. | |
| TLDIGITS = Determines the rounding of decimals for the Kaplan-Meier time-point event-free rates and confidence bounds for | |
| survival variables. Can set different digits | |
| for each variable with the | delimiter. | |
| 2.4.2.4: Logistic Variables | |
| BINDIGITS = Determines the rounding of decimals for the Binomial Success rate and confidence bounds. Can set different digits | |
| for each variable with the | delimiter. | |
| ORDIGITS = Determines the rounding of decimals for the odds ratio and confidence bounds. Can set different digits | |
| for each variable with the | delimiter. | |
| 2.4.2.5: P-values | |
| PVALDIGITS = Determines the rounding of decimals for the p-values for all variables. | |
| 2.4.3: Shading | |
| SHADING = Determines row shading for the table. Default is 1. Options are: | |
| 0 = No shading | |
| 1 = Alternating shading every row | |
| 2 = Alternating shading every variable | |
| 2.4.4: Titles/Footnotes | |
| TITLE = Text string to be used as a title at the top of the table. The ` will be used to manually create a line break. | |
| TITLEALIGN = Determines how the TITLE is aligned. Options are LEFT, RIGHT, or CENTER. Default is LEFT. | |
| FOOTNOTE = Text string to be used as a footnote at the bottom of the table. The ` will be used to manually create a line break. | |
| FOOTNOTEALIGN = Determines how the FOOTNOTE is aligned. Options are LEFT, RIGHT, or CENTER. Default is LEFT. | |
| 2.4.5: Separation of variables | |
| SPLIT = Determines how the table separates one variable from another. Default is SPACE. Options are: | |
| SPACE = Adds a space when one variable ends and another begins | |
| LINE = Adds a line when one variable ends and another begins | |
| NONE = There is no line or space when one variable ends and another begins | |
| 2.4.6: Font Options | |
| 2.4.6.1: Font Size | |
| HEADERSIZE = Determines the font size of the header section of the table. Default is 10pt. | |
| DATASIZE = Determines the font size of the data section of the table. Default is 10pt. | |
| TITLESIZE = Determines the font size of the title section of the table. Default is 10pt. | |
| FOOTNOTESIZE = Determines the font size of the footnote section of the table. Default is 10pt. | |
| 2.4.6.2: Font Family | |
| FONT = Determines the font for the table. Default is Arial. | |
| 2.4.6.3: Font Weight | |
| HEADERWEIGHT = Determines the weight of the font for the header section of the table. Options are Medium (not bold) or BOLD. | |
| Default is MEDIUM. | |
| DATAWEIGHT = Determines the weight of the font for the data section of the table. Options are Medium (not bold) or BOLD. | |
| Default is MEDIUM. | |
| TITLEWEIGHT = Determines the weight of the font for the title section of the table. Options are Medium (not bold) or BOLD. | |
| Default is MEDIUM. | |
| FOOTNOTEWEIGHT = Determines the weight of the font for the footnote section of the table. Options are Medium (not bold) or BOLD. | |
| Default is MEDIUM. | |
| 2.4.7: Column Widths | |
| SUBTITLEWIDTH = Determines the width of the subtitle/factor column. Default is 2.25in. | |
| DATAWIDTH = Determines the width of the DATA columns. Default is 1.1in. | |
| PVALWIDTH = Determines the width of the p-value columns. Default is 0.75in. | |
| ROWBYWIDTH = Determines the width of the ROWBY column. Default is 2in. | |
| 2.4.8: Subtitle Header | |
| SUBTITLEHEADER = Sets the column label for the subtitle/factor column. Default is null (none). | |
| 2.5: Output options | |
| 2.5.1: Output Dataset | |
| OUT = Identifies a dataset name to save out the report dataset. | |
| 2.5.2: Save to a document | |
| OUTDOC = Identifies a file to directly save the table to. | |
| DESTINATION = Identifies the ODS destination to use to save the OUTDOC file. Options are RTF, PDF, EXCEL, POWERPOINT and HTML. | |
| Default is RTF. POWERPOINT and EXCEL are only available in 9.4+. | |
| ORIENTATION = Sets the page orientation of the file identified by OUTDOC. Options are Portrait or Landscape. | |
| Default is PORTRAIT. | |
| EXCEL_SHEETNAME = Sets the name of the sheet for the Excel destination. Default is TABLEN. | |
| 2.6: Debugging options | |
| DEBUG = Determines if notes are suppressed and temporary datasets cleaned up. Options are: | |
| 0: notes are suppressed and temporary datasets are cleaned up | |
| 1: Notes are printed and temporary datasets are left behind. | |
| Default is 0. | |
*------------------------------------------------------------------* | |
| OPERATING SYSTEM COMPATIBILITY | |
| SAS v9.2 or Higher: Yes | |
*------------------------------------------------------------------* | |
| MACRO CALL | |
| | |
| %tablen ( | |
| DATA=, | |
| VAR=, | |
| TYPE= | |
| ); | |
*------------------------------------------------------------------* | |
| EXAMPLES | |
| | |
| Neuralgia dataset for examples: | |
Data Neuralgia; | |
input Treatment $ Sex $ Age Duration Pain $ @@; | |
datalines; | |
P F 68 1 No B M 74 16 No P F 67 30 No | |
P M 66 26 Yes B F 67 28 No B F 77 16 No | |
A F 71 12 No B F 72 50 No B F 76 9 Yes | |
A M 71 17 Yes A F 63 27 No A F 69 18 Yes | |
B F 66 12 No A M 62 42 No P F 64 1 Yes | |
A F 64 17 No P M 74 4 No A F 72 25 No | |
P M 70 1 Yes B M 66 19 No B M 59 29 No | |
A F 64 30 No A M 70 28 No A M 69 1 No | |
B F 78 1 No P M 83 1 Yes B F 69 42 No | |
B M 75 30 Yes P M 77 29 Yes P F 79 20 Yes | |
A M 70 12 No A F 69 12 No B F 65 14 No | |
B M 70 1 No B M 67 23 No A M 76 25 Yes | |
P M 78 12 Yes B M 77 1 Yes B F 69 24 No | |
P M 66 4 Yes P F 65 29 No P M 60 26 Yes | |
A M 78 15 Yes B M 75 21 Yes A F 67 11 No | |
P F 72 27 No P F 70 13 Yes A M 75 6 Yes | |
B F 65 7 No P F 68 27 Yes P M 68 11 Yes | |
P M 67 17 Yes B M 70 22 No A M 65 15 No | |
P F 67 1 Yes A M 67 10 No P F 72 11 Yes | |
A F 74 1 No B M 80 21 Yes A F 69 3 No | |
; | |
run; | |
| Example 1: Generic example | |
%tablen( | |
DATA = NEURALGIA, | |
VAR = TREATMENT SEX AGE DURATION PAIN, | |
TYPE = 2 2 1 1 2); | |
| | |
| Example 2: Adding a BY variable | |
%tablen( | |
DATA = NEURALGIA, | |
VAR = SEX AGE DURATION PAIN, | |
TYPE = 2 1 1 2, | |
BY = TREATMENT); | |
| | |
| Example 3: Change discrete p-values to Fisher's exact | |
%tablen( | |
DATA = NEURALGIA, | |
VAR = SEX AGE DURATION PAIN, | |
TYPE = 2 1 1 2, | |
BY = TREATMENT, | |
PVALS = 2 1 1 2); | |
proc format; | |
value grpLabel 1='ALL' 2='AML low risk' 3='AML high risk'; | |
run; | |
data BMT; | |
input DIAGNOSIS Ftime Status Gender@@; | |
label Ftime="Days"; | |
format Diagnosis grpLabel.; | |
datalines; | |
1 2081 0 1 1 1602 0 1 | |
1 1496 0 1 1 1462 0 0 | |
1 1433 0 1 1 1377 0 1 | |
1 1330 0 1 1 996 0 1 | |
1 226 0 0 1 1199 0 1 | |
1 1111 0 1 1 530 0 1 | |
1 1182 0 0 1 1167 0 0 | |
1 418 2 1 1 383 1 1 | |
1 276 2 0 1 104 1 1 | |
1 609 1 1 1 172 2 0 | |
1 487 2 1 1 662 1 1 | |
1 194 2 0 1 230 1 0 | |
1 526 2 1 1 122 2 1 | |
1 129 1 0 1 74 1 1 | |
1 122 1 0 1 86 2 1 | |
1 466 2 1 1 192 1 1 | |
1 109 1 1 1 55 1 0 | |
1 1 2 1 1 107 2 1 | |
1 110 1 0 1 332 2 1 | |
2 2569 0 1 2 2506 0 1 | |
2 2409 0 1 2 2218 0 1 | |
2 1857 0 0 2 1829 0 1 | |
2 1562 0 1 2 1470 0 1 | |
2 1363 0 1 2 1030 0 0 | |
2 860 0 0 2 1258 0 0 | |
2 2246 0 0 2 1870 0 0 | |
2 1799 0 1 2 1709 0 0 | |
2 1674 0 1 2 1568 0 1 | |
2 1527 0 0 2 1324 0 1 | |
2 957 0 1 2 932 0 0 | |
2 847 0 1 2 848 0 1 | |
2 1850 0 0 2 1843 0 0 | |
2 1535 0 0 2 1447 0 0 | |
2 1384 0 0 2 414 2 1 | |
2 2204 2 0 2 1063 2 1 | |
2 481 2 1 2 105 2 1 | |
2 641 2 1 2 390 2 1 | |
2 288 2 1 2 421 1 1 | |
2 79 2 0 2 748 1 1 | |
2 486 1 0 2 48 2 0 | |
2 272 1 0 2 1074 2 1 | |
2 381 1 0 2 10 2 1 | |
2 53 2 0 2 80 2 0 | |
2 35 2 0 2 248 1 1 | |
2 704 2 0 2 211 1 1 | |
2 219 1 1 2 606 1 1 | |
3 2640 0 1 3 2430 0 1 | |
3 2252 0 1 3 2140 0 1 | |
3 2133 0 0 3 1238 0 1 | |
3 1631 0 1 3 2024 0 0 | |
3 1345 0 1 3 1136 0 1 | |
3 845 0 0 3 422 1 0 | |
3 162 2 1 3 84 1 0 | |
3 100 1 1 3 2 2 1 | |
3 47 1 1 3 242 1 1 | |
3 456 1 1 3 268 1 0 | |
3 318 2 0 3 32 1 1 | |
3 467 1 0 3 47 1 1 | |
3 390 1 1 3 183 2 0 | |
3 105 2 1 3 115 1 0 | |
3 164 2 0 3 93 1 0 | |
3 120 1 0 3 80 2 1 | |
3 677 2 1 3 64 1 0 | |
3 168 2 0 3 74 2 0 | |
3 16 2 0 3 157 1 0 | |
3 625 1 0 3 48 1 0 | |
3 273 1 1 3 63 2 1 | |
3 76 1 1 3 113 1 0 | |
3 363 2 1 | |
; | |
run; | |
| | |
| Example 4: Add in a survival variable | |
%tablen( | |
DATA = BMT, | |
VAR = GENDER STATUS FTIME, | |
TYPE = 2 2 4, | |
BY = DIAGNOSIS, | |
SURV_STAT = STATUS, | |
CEN_VL = 0); | |
| | |
| Example 4: Add time-point estimates and change time units | |
%tablen( | |
DATA = BMT, | |
VAR = GENDER STATUS FTIME, | |
TYPE = 2 2 4, | |
BY = DIAGNOSIS, | |
SURV_STAT = STATUS, | |
CEN_VL = 0, | |
TDIVISOR = 365.25, | |
TIMELIST = 1 2, | |
TIME_UNITS = years); | |
*------------------------------------------------------------------* | |
| This program is free software; you can redistribute it and/or | |
| modify it under the terms of the GNU General Public License as | |
| published by the Free Software Foundation; either version 2 of | |
| the License, or (at your option) any later version. | |
| | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
*------------------------------------------------------------------*/ | |
%macro tablen( | |
/*1.0: Required Parameters*/ | |
data=,var=,type=, | |
/*2.0: Optional Parameters*/ | |
/*2.1: Subgroup Options*/ | |
/*2.1.1: BY variable Options - Comparisons including p-values*/ | |
by=,byorder=,byorder_formatted=0,bylabel=,by_incmiss=0,by_printmiss=1, | |
/*2.1.2: COLBY (Column By) variable Options - Comparisons not including p-values*/ | |
colby=,colbyorder=,colbyorder_formatted=0,colbylabel=, | |
/*2.1.3: ROWBY (Row By) variable Options - Comparisons not including p-values*/ | |
rowby=,rowbyorder=,rowbyorder_formatted=0,rowbylabel=, | |
/*2.1.4: Subset input dataset*/ | |
where=, | |
/*2.2: P-value Options*/ | |
pvals=1,pfoot=1, | |
/*2.3: Variable Display Options*/ | |
/*2.3.1: Continuous Variables*/ | |
contdisplay=n mean_sd median range, | |
/*2.3.2: Discrete Variables*/ | |
dis_display=n_pct,dis_order=,dis_order_formatted=0,dis_order_override=0,dis_incmiss=0,dis_printmiss=1, | |
dis_missorder=last,pctdisplay=col,dis_suffix=AUTO, | |
/*2.3.3: Date Variables*/ | |
datedisplay=n median range,datefmt=mmddyy10., | |
/*2.3.4: Survival Variables*/ | |
survdisplay=events_n median timelist hr coxpval,surv_stat=,cen_vl=, | |
timelist=,time_units=,tdivisor=1,reference=,conftype=log,timelistfmt=ppt, | |
/*2.3.5: Logistic Variables*/ | |
log_event=,log_display=events_n binrate oddsratio waldpval,log_conftype=bin,log_binfmt=ppt, | |
/*2.3.6: All Variables*/ | |
labels=, freq=, force_multiple_rows=0, show_label_statistic=1, | |
/*2.4: Table Display Options*/ | |
/*2.4.0: Table borders*/ | |
borderdisplay=1, | |
/*2.4.1: Disable Certain Columns*/ | |
showtotal=1,total_col_pos=end,showbylabel=1,showcollabel=1,showpval=1, | |
/*2.4.2: Results Digit Rounding*/ | |
/*2.4.2.1: Continuous Variables*/ | |
meandigits=1,mediandigits=1,stddigits=2,iqrdigits=1,rangedigits=1, | |
/*2.4.2.2: Discrete Variables*/ | |
pctdigits=1, | |
/*2.4.2.3: Survival Variables*/ | |
smediandigits=2,hrdigits=2,tldigits=2, | |
/*2.4.2.4: Logistic Variables*/ | |
ordigits=2,bindigits=2, | |
/*2.4.2.5: P-values*/ | |
pvaldigits=4, | |
/*2.4.3: Shading*/ | |
shading=1, | |
/*2.4.4: Titles/Footnotes*/ | |
title=,titlealign=left,footnote=,footnotealign=left, | |
/*2.4.5: Separation of variables*/ | |
split=space, | |
/*2.4.6: Font Options*/ | |
/*2.4.6.1: Font Size*/ | |
headersize=10pt,datasize=10pt,titlesize=10pt,footnotesize=10pt, | |
/*2.4.6.2: Font Family*/ | |
font=Arial, | |
/*2.4.6.3: Font Weight*/ | |
headerweight=medium,dataweight=medium,titleweight=medium,footnoteweight=medium, | |
/*2.4.7: Column Widths*/ | |
subtitlewidth=2.25in,datawidth=1.1in,pvalwidth=0.75in,rowbywidth=2in, | |
/*2.4.8: Subtitle Header*/ | |
subtitleheader=, | |
/*2.5: Output options*/ | |
/*2.5.1: Output Dataset*/ | |
out=, | |
/*2.5.2: Save to a document*/ | |
outdoc=,destination=RTF,orientation=portrait, | |
excel_sheetname=TABLEN, | |
/*2.6: Debuggin Options*/ | |
debug=0 | |
); | |
/**Save current options to reset after macro runs**/ | |
%local _mergenoby _notes _qlm _odspath _starttime _listing _linesize _center _orientation _msglevel _mprint; | |
%let _starttime=%sysfunc(time()); | |
%let _notes=%sysfunc(getoption(notes)); | |
%let _mergenoby=%sysfunc(getoption(mergenoby)); | |
%let _qlm=%sysfunc(getoption(quotelenmax)); | |
%let _linesize=%sysfunc(getoption(linesize)); | |
%let _center=%sysfunc(getoption(center)); | |
%let _orientation=%sysfunc(getoption(orientation)); | |
%let _mprint=%sysfunc(getoption(mprint)); | |
%let _msglevel=%sysfunc(getoption(msglevel)); | |
/**Turn off warnings for merging without a by and long quote lengths**/ | |
/**Turn off notes**/ | |
options mergenoby=NOWARN nonotes noquotelenmax msglevel=N; | |
/*Don't send anything to output window, results window, and set escape character*/ | |
ods noresults escapechar='^'; | |
ods exclude all; | |
%let _odspath=&sysodspath; | |
/**Process Error Handling**/ | |
%if %sysfunc(exist(&data))=0 %then %do; | |
%put ERROR: Dataset &data does not exist; | |
%put ERROR: Please enter a valid dataset; | |
%goto errhandl; | |
%end; | |
%else %if %sysevalf(%superq(data)=,boolean)=1 %then %do; | |
%put ERROR: DATA parameter is required; | |
%put ERROR: Please enter a valid dataset; | |
%goto errhandl; | |
%end; | |
%local z nerror; | |
%let nerror=0; | |
/**Error Handling on Global Parameters**/ | |
%macro _varcheck(parm,require,numeric,dataset=&data,nummsg=); | |
%local _z _numcheck; | |
/**Check if variable parameter is missing**/ | |
%if %sysevalf(%superq(&parm.)=,boolean)=0 %then %do; | |
%if %sysfunc(notdigit(%superq(&parm.))) > 0 %then | |
%do _z = 1 %to %sysfunc(countw(%superq(&parm.),%str( ))); | |
/**Check to make sure variable names are not just numbers**/ | |
%local datid; | |
/**Open up dataset to check for variables**/ | |
%let datid = %sysfunc(open(&dataset)); | |
/**Check if variable exists in dataset**/ | |
%if %sysfunc(varnum(&datid,%scan(%superq(&parm.),&_z,%str( )))) = 0 %then %do; | |
%put ERROR: (Global: %qupcase(&parm)) Variable %qupcase(%scan(%superq(&parm.),&_z,%str( ))) does not exist in dataset &dataset; | |
%local closedatid; | |
/**Close dataset**/ | |
%let closedatid=%sysfunc(close(&datid)); | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%else %do; | |
%local closedatid; | |
%let closedatid=%sysfunc(close(&datid)); | |
%if &numeric=1 %then %do; | |
data _null_; | |
set &dataset (obs=1); | |
call symput('_numcheck',strip(vtype(%qupcase(%scan(%superq(&parm.),&_z,%str( )))))); | |
run; | |
%if %sysevalf(%superq(_numcheck)^=N,boolean) %then %do; | |
%put ERROR: (Global: %qupcase(%scan(%superq(&parm.),&_z,%str( )))) variable must be numeric &nummsg; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%end; | |
%end; | |
%end; | |
%else %do; | |
/**Give error message if variable name is number**/ | |
%put ERROR: (Global: %qupcase(&parm)) variable is not a valid SAS variable name (%superq(&parm.)); | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%end; | |
%else %if &require=1 %then %do; | |
/**Give error if required variable is missing**/ | |
%put ERROR: (Global: %qupcase(&parm)) variable is a required variable but has no value; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%mend; | |
%macro _gparmcheck(parm, parmlist); | |
%local _test _z; | |
/**Check if values are in approved list**/ | |
%do _z=1 %to %sysfunc(countw(&parmlist,|,m)); | |
%if %qupcase(%superq(&parm))=%qupcase(%scan(&parmlist,&_z,|,m)) %then %let _test=1; | |
%end; | |
%if &_test ^= 1 %then %do; | |
/**If not then throw error**/ | |
%put ERROR: (Global: %qupcase(&parm)): %superq(&parm) is not a valid value; | |
%put ERROR: (Global: %qupcase(&parm)): Possible values are &parmlist; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%mend; | |
/**Error Handling on Individual Model Numeric Variables**/ | |
%macro _gnumcheck(parm,min,contain,default); | |
/**Check if missing**/ | |
%local z; | |
%if %sysevalf(%superq(&parm.)=,boolean)=0 %then %do; | |
%do z = 1 %to %sysfunc(countw(%superq(&parm),|,m)); | |
%if %sysevalf(%qscan(%superq(&parm.),&z,|,m)=,boolean) %then %do; | |
/**Check if value is not missing**/ | |
%put ERROR: (Global: %qupcase(&parm) value &z) Cannot be missing and must be greater than &min.; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%else %if %sysfunc(notdigit(%sysfunc(compress(%qscan(%superq(&parm.),&z,|,m),.)))) > 0 %then %do; | |
/**Check if character values are present**/ | |
%put ERROR: (Global: %qupcase(&parm) value &z) Must be numeric. %qupcase(%qscan(%superq(&parm.),&z,|,m)) is not valid.; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%else %if %sysevalf(%superq(min)^=,boolean) %then %do; | |
%if %qscan(%superq(&parm.),&z,|,m) le &min and &contain=0 %then %do; | |
/**Check if value is below minimum threshold**/ | |
%put ERROR: (Global: %qupcase(&parm) value &z) Must be greater than &min. %qupcase(%qscan(%superq(&parm.),&z,|,m)) is not valid.; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%else %if %qscan(%superq(&parm.),&z,|,m) lt &min and &contain=1 %then %do; | |
/**Check if value is below minimum threshold**/ | |
%put ERROR: (Global: %qupcase(&parm) value &z) Must be greater than or equal to &min. %qupcase(%qscan(%superq(&parm.),&z,|,m)) is not valid.; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%end; | |
%end; | |
%end; | |
%else %let &parm.=&default; | |
%mend; | |
/**Error Handling on Global Parameters Involving units**/ | |
%macro _gunitcheck(parm,allowmissing); | |
%if %sysevalf(%superq(&parm)=,boolean)=1 %then %do; | |
%if %sysevalf(&allowmissing^=1,boolean) %then %do; | |
/**Check if missing**/ | |
%put ERROR: (Global: %qupcase(&parm)) Cannot be set to missing; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%end; | |
%else %if %sysfunc(compress(%superq(&parm),ABCDEFGHIJKLMNOPQRSTUVWXYZ,i)) lt 0 %then %do; | |
/**Throw error**/ | |
%put ERROR: (Global: %qupcase(&parm)) Cannot be less than zero (%qupcase(%superq(&parm))); | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%mend; | |
/**Line Pattern Variables**/ | |
%macro _listcheck(var=,_patternlist=,lbl=,msg=,maxvalue=); | |
%local _z _z2 _z3 _test; | |
%if %sysevalf(%superq(lbl)=,boolean) %then %let lbl=%qupcase(&var.); | |
/**Check for missing values**/ | |
%if %sysevalf(%superq(&var.)=,boolean)=0 %then %do _z3=1 %to %sysfunc(countw(%superq(&var.),|,m)); | |
%do _z2=1 %to %sysfunc(countw(%scan(%superq(&var.),&_z3,|),%str( ))); | |
%let _test=; | |
/**Check if values are either in the approved list**/ | |
%do _z = 1 %to %sysfunc(countw(&_patternlist,|)); | |
%if %qupcase(%scan(%scan(%superq(&var.),&_z3,|),&_z2,%str( )|))=%scan(%qupcase(%sysfunc(compress(&_patternlist))),&_z,|,m) %then %let _test=1; | |
%end; | |
%if &_test ^= 1 %then %do; | |
/**Throw error**/ | |
%put ERROR: (Global: &lbl): %qupcase(%scan(%scan(%superq(&var.),&_z3,|),&_z2,%str( )|)) is not in the list of valid values &msg; | |
%put ERROR: (Global: &lbl): Possible values are %qupcase(&_patternlist); | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%end; | |
%end; | |
%else %do; | |
/**Throw error**/ | |
%put ERROR: (Global: &lbl): %qupcase(%superq(&var.)) is not in the list of valid values &msg; | |
%put ERROR: (Global: &lbl): Possible values are %qupcase(&_patternlist); | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%mend; | |
/**Check variables**/ | |
%_varcheck(var,1) | |
%_varcheck(by,0) | |
%_varcheck(rowby,0) | |
%_varcheck(colby,0) | |
%_varcheck(surv_stat,0,1) | |
%_varcheck(freq,0,1) | |
/**Check list parameters**/ | |
%_listcheck(var=type,_patternlist=1|2|3|4|5) | |
%_listcheck(var=contdisplay,_patternlist=N|NMISS|N_NMISS|MEAN|SD|MEAN_SD|MEDIAN|RANGE|IQR|MEDIAN_RANGE|MEDIAN_IQR) | |
%_gparmcheck(dis_display,N|PCT|N_PCT) | |
%_listcheck(var=datedisplay,_patternlist=N|NMISS|N_NMISS|MEAN|SD|MEAN_SD|MEDIAN|RANGE|IQR|MEDIAN_RANGE|MEDIAN_IQR) | |
%_listcheck(var=survdisplay,_patternlist=N|EVENTS|EVENTS_N|MEDIAN|HR|COXPVAL|TIMELIST) | |
%_listcheck(var=log_display,_patternlist=N|EVENTS|EVENTS_N|ODDSRATIO|WALDPVAL|BINRATE) | |
/**Parameter error checks**/ | |
%_gparmcheck(showtotal,0|1) | |
%_gparmcheck(total_col_pos,START|END) | |
%_gparmcheck(showbylabel,0|1) | |
%_gparmcheck(showcollabel,0|1) | |
%_gparmcheck(showpval,0|1|2) | |
%_gparmcheck(pfoot,0|1) | |
%_gparmcheck(shading,0|1|2) | |
%_gparmcheck(titlealign,LEFT|CENTER|RIGHT) | |
%_gparmcheck(footnotealign,LEFT|CENTER|RIGHT) | |
%_gparmcheck(split,NONE|SPACE|LINE) | |
%_gparmcheck(headerweight,MEDIUM|BOLD) | |
%_gparmcheck(dataweight,MEDIUM|BOLD) | |
%_gparmcheck(titleweight,MEDIUM|BOLD) | |
%_gparmcheck(footnoteweight,MEDIUM|BOLD) | |
%if &sysvlong >= 9.04.01M3P062415 %then %do; | |
%_gparmcheck(destination,RTF|PDF|HTML|EXCEL|POWERPOINT) | |
%end; | |
%else %do; | |
%_gparmcheck(destination,RTF|PDF|HTML) | |
%end; | |
%_gparmcheck(orientation,PORTRAIT|LANDSCAPE) | |
%_gparmcheck(dis_printmiss,0|1|2|3) | |
%_gparmcheck(byorder_formatted,0|1) | |
%_gparmcheck(rowbyorder_formatted,0|1) | |
%_gparmcheck(colbyorder_formatted,0|1) | |
%_gparmcheck(dis_order_formatted,0|1) | |
%_gparmcheck(dis_missorder,FIRST|LAST) | |
%_gparmcheck(dis_order_override,0|1) | |
%_gparmcheck(dis_incmiss,0|1) | |
%_gparmcheck(conftype,LOG|ASINSQRT|LOGLOG|LINEAR|LOGIT) | |
%_gparmcheck(timelistfmt,PPT|PCT) | |
%_gparmcheck(log_conftype,BIN|BINEXACT) | |
%_gparmcheck(log_binfmt,PPT|PCT) | |
%_gparmcheck(by_incmiss,0|1) | |
%_gparmcheck(by_printmiss,0|1|2) | |
%_gparmcheck(dis_incmiss,0|1) | |
%_gparmcheck(dis_missorder,FIRST|LAST) | |
%_gparmcheck(pctdisplay,COL|ROW) | |
%_gparmcheck(borderdisplay,1|2|3|4) | |
%_gparmcheck(debug,0|1) | |
%_gparmcheck(force_multiple_rows,0|1) | |
%_gparmcheck(show_label_statistic,0|1) | |
/**Number error checks**/ | |
%_gnumcheck(meandigits,0,1,1) | |
%_gnumcheck(mediandigits,0,1,1) | |
%_gnumcheck(stddigits,0,1,2) | |
%_gnumcheck(iqrdigits,0,1,1) | |
%_gnumcheck(rangedigits,0,1,1) | |
%_gnumcheck(pctdigits,0,1,1) | |
%_gnumcheck(smediandigits,0,1,2) | |
%_gnumcheck(smediandigits,0,1,2) | |
%_gnumcheck(pvaldigits,0,1,4) | |
/*Numbers with units error checks**/ | |
%_gunitcheck(headersize,0) | |
%_gunitcheck(datasize,0) | |
%_gunitcheck(titlesize,0) | |
%_gunitcheck(footnotesize,0) | |
%_gunitcheck(subtitlewidth,0) | |
%_gunitcheck(datawidth,0) | |
%_gunitcheck(pvalwidth,0) | |
%_gunitcheck(rowbywidth,0) | |
%local nerror_run; | |
%let nerror_run=0; | |
%if &nerror=0 %then %do; | |
%local i j _nvar_ _numvars_ _nnumvars_ _ndisvars_ _nsurvvars_ _nlogvars_ | |
_lasttype_ _lastpval_ _lastcens_ _lastndisplay_ _lastddisplay_ _lastsdisplay_ _lastldisplay_ _lastunit_ | |
_numpvals_ _dispvals_ _survpvals_ _logpvals_ | |
_numvars_ _numindex_ _numdisplay_ _numtype_ _meandigit_ _mediandigit_ _stddigit_ _iqrdigit_ _rangedigit_ | |
_disvars_ _disindex_ _disdisplay_ _pctdigit_ | |
_survvars_ _survindex_ _survstat_ _survcens_ _survtimelist_ _survntimelist_ _survunits_ _survdisplay_ _smediandigit_ _hrdigit_ _tldigit_ | |
_logvars_ _logindex_ _logdisplay_ _ordigit_ _bindigit_; | |
/*Extend TYPE and PVALS to length of VAR*/ | |
%let _nvar_=%sysfunc(countw(%superq(var),%str( ))); | |
%do i = 1 %to &_nvar_; | |
%if %sysevalf(%qscan(&pvals,&i,%str( ))^=,boolean) %then %let _lastpval_=%scan(&pvals,&i,%str( )); | |
%else %let pvals=&pvals &_lastpval_; | |
%if %sysevalf(%qscan(&cen_vl,&i,%str( ))^=,boolean) %then %let _lastcens_=%scan(&cen_vl,&i,%str( )); | |
%else %let cen_vl=&cen_vl &_lastcens_; | |
%if %sysevalf(%qscan(&time_units,&i,%str(|))^=,boolean) %then %let _lastunit_=%scan(&time_units,&i,%str(|)); | |
%else %let time_units=&time_units|&_lastunit_; | |
%if %sysevalf(%qscan(&type,&i,%str( ))^=,boolean) %then %let _lasttype_=%scan(&type,&i,%str( )); | |
%else %let type=&type &_lasttype_; | |
%if %sysevalf(%qscan(&contdisplay,&i,|)^=,boolean) %then %let _lastndisplay_=%scan(&contdisplay,&i,|); | |
%else %let contdisplay=&contdisplay|&_lastndisplay_; | |
%if %sysevalf(%qscan(&datedisplay,&i,|)^=,boolean) %then %let _lastddisplay_=%scan(&datedisplay,&i,|); | |
%else %let datedisplay=&datedisplay|&_lastddisplay_; | |
%if %sysevalf(%qscan(&survdisplay,&i,|)^=,boolean) %then %let _lastsdisplay_=%scan(&survdisplay,&i,|); | |
%else %let survdisplay=&survdisplay|&_lastsdisplay_; | |
%if %sysevalf(%qscan(&log_display,&i,|)^=,boolean) %then %let _lastldisplay_=%scan(&log_display,&i,|); | |
%else %let log_display=&log_display|&_lastldisplay_; | |
%if %sysevalf(%qscan(&meandigits,&i,|)^=,boolean) %then %let _meandigit_=%scan(&meandigits,&i,|); | |
%else %let meandigits=&meandigits|&_meandigit_; | |
%if %sysevalf(%qscan(&mediandigits,&i,|)^=,boolean) %then %let _mediandigit_=%scan(&mediandigits,&i,|); | |
%else %let mediandigits=&mediandigits|&_mediandigit_; | |
%if %sysevalf(%qscan(&stddigits,&i,|)^=,boolean) %then %let _stddigit_=%scan(&stddigits,&i,|); | |
%else %let stddigits=&stddigits|&_stddigit_; | |
%if %sysevalf(%qscan(&rangedigits,&i,|)^=,boolean) %then %let _rangedigit_=%scan(&rangedigits,&i,|); | |
%else %let rangedigits=&rangedigits|&_rangedigit_; | |
%if %sysevalf(%qscan(&iqrdigits,&i,|)^=,boolean) %then %let _iqrdigit_=%scan(&iqrdigits,&i,|); | |
%else %let iqrdigits=&iqrdigits|&_iqrdigit_; | |
%if %sysevalf(%qscan(&pctdigits,&i,|)^=,boolean) %then %let _pctdigit_=%scan(&pctdigits,&i,|); | |
%else %let pctdigits=&pctdigits|&_pctdigit_; | |
%if %sysevalf(%qscan(&smediandigits,&i,|)^=,boolean) %then %let _smediandigit_=%scan(&smediandigits,&i,|); | |
%else %let smediandigits=&smediandigits|&_smediandigit_; | |
%if %sysevalf(%qscan(&hrdigits,&i,|)^=,boolean) %then %let _hrdigit_=%scan(&hrdigits,&i,|); | |
%else %let hrdigits=&hrdigits|&_hrdigit_; | |
%if %sysevalf(%qscan(&tldigits,&i,|)^=,boolean) %then %let _tldigit_=%scan(&tldigits,&i,|); | |
%else %let tldigits=&tldigits|&_tldigit_; | |
%if %sysevalf(%qscan(&ordigits,&i,|)^=,boolean) %then %let _ordigit_=%scan(&ordigits,&i,|); | |
%else %let ordigits=&ordigits|&_ordigit_; | |
%if %sysevalf(%qscan(&bindigits,&i,|)^=,boolean) %then %let _bindigit_=%scan(&bindigits,&i,|); | |
%else %let bindigits=&bindigits|&_bindigit_; | |
%end; | |
/*Sort variables by type*/ | |
%do i = 1 %to %sysfunc(countw(%superq(var),%str( ))); | |
%if %scan(%superq(type),&i,%str( ))=1 or %scan(%superq(type),&i,%str( ))=3 %then %do; | |
%let _numvars_=&_numvars_ %scan(%superq(var),&i,%str( )); | |
%let _numpvals_=&_numpvals_ %scan(%superq(pvals),&i,%str( )); | |
%let _numindex_=&_numindex_ &i; | |
%let _numtype_=&_numtype_ %scan(%superq(type),&i,%str( )); | |
%end; | |
%else %if %scan(%superq(type),&i,%str( ))=2 %then %do; | |
%let _disvars_=&_disvars_ %scan(%superq(var),&i,%str( )); | |
%let _dispvals_=&_dispvals_ %scan(%superq(pvals),&i,%str( )); | |
%let _disindex_=&_disindex_ &i; | |
%end; | |
%else %if %scan(%superq(type),&i,%str( ))=4 %then %do; | |
%let _survvars_=&_survvars_ %scan(%superq(var),&i,%str( )); | |
%let _survpvals_=&_survpvals_ %scan(%superq(pvals),&i,%str( )); | |
%let _survindex_=&_survindex_ &i; | |
%end; | |
%else %if %scan(%superq(type),&i,%str( ))=5 %then %do; | |
%let _logvars_=&_logvars_ %scan(%superq(var),&i,%str( )); | |
%let _logpvals_=&_logpvals_ %scan(%superq(pvals),&i,%str( )); | |
%let _logindex_=&_logindex_ &i; | |
%end; | |
%end; | |
/*Confirm Continuous variables are numeric*/ | |
%_varcheck(_numvars_,0,1,nummsg=when TYPE=1) | |
/*Check for appropriate p-values*/ | |
%if %sysevalf(%superq(_numvars_)^=,boolean) %then %do; | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
%_listcheck(var=_numpvals_,_patternlist=0|1|2|3|4|5|6|7,lbl=PVALS,msg=for continuous variables) | |
%end; | |
%else %do; | |
%_listcheck(var=_numpvals_,_patternlist=0|1|2,lbl=PVALS,msg=for continuous variables with no BY variable) | |
%end; | |
%end; | |
%if %sysevalf(%superq(_disvars_)^=,boolean) %then %do; | |
%_listcheck(var=_dispvals_,_patternlist=0|1|2|3,lbl=PVALS,msg=for discrete variables) | |
%end; | |
%if %sysevalf(%superq(_survvars_)^=,boolean) %then %do; | |
%_listcheck(var=_survpvals_,_patternlist=0|1|2|3|4|5,lbl=PVALS,msg=for survival variables) | |
%end; | |
%if %sysevalf(%superq(_logvars_)^=,boolean) %then %do; | |
%_listcheck(var=_logpvals_,_patternlist=0|1|2|3,lbl=PVALS,msg=for logistic variables) | |
%end; | |
/*Calculate the number of each type of variable*/ | |
%let _nnumvars_=%sysfunc(countw(&_numvars_,%str( ))); | |
%let _ndisvars_=%sysfunc(countw(&_disvars_,%str( ))); | |
%let _nsurvvars_=%sysfunc(countw(&_survvars_,%str( ))); | |
%let _nlogvars_=%sysfunc(countw(&_logvars_,%str( ))); | |
/*Check for appropriate CEN_VL values*/ | |
%if &_nsurvvars_>0 and %sysevalf(%superq(cen_vl)^=,boolean) %then %do i = 1 %to &_nsurvvars_; | |
%local _cen_vl&i; | |
%let _cen_vl&i=%qscan(%superq(cen_vl),&i,|,m); | |
%if %sysevalf(%superq(_cen_vl&i)^=,boolean) %then %do j = 1 %to %sysfunc(countw(%superq(_cen_vl&i),%str( ))); | |
%if %sysfunc(notdigit(%sysfunc(compress(%scan(%superq(_cen_vl&i),&j,%str( )),-.)))) > 0 %then %do; | |
/**Check if character values are present**/ | |
%put ERROR: (Global: CEN_VL) Values must be numeric. %scan(%superq(_cen_vl&i),&j,%str( )) is not valid.; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%end; | |
%end; | |
%else %if &_nsurvvars_>0 %then %do; | |
/**Check if character values are present**/ | |
%put ERROR: (Global: CEN_VL) Values cannot be missing when specifying a TYPE=4 variable.; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
/*Check for appropriate TDIVISOR values*/ | |
%if &_nsurvvars_>0 and %sysevalf(%superq(tdivisor)^=,boolean) %then %do i = 1 %to &_nsurvvars_; | |
%local _tdivisor&i; | |
%let _tdivisor&i=%qscan(%superq(tdivisor),&i,%str( ),m); | |
%if %sysevalf(%superq(_tdivisor&i)^=,boolean) %then %do j = 1 %to %sysfunc(countw(%superq(_tdivisor&i),%str( ))); | |
%if %sysfunc(notdigit(%sysfunc(compress(%scan(%superq(_tdivisor&i),&j,%str( )),-.)))) > 0 %then %do; | |
/**Check if character values are present**/ | |
%put ERROR: (Global: TDIVISOR) Values must be numeric. %scan(%superq(_tdivisor&i),&j,%str( )) is not valid.; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%else %if %scan(%superq(_tdivisor&i),&j,%str( )) le 0 %then %do; | |
/**Check if character 0 or negative**/ | |
%put ERROR: (Global: TDIVISOR) Values must be greater than or equal to 0 %scan(%superq(_tdivisor&i),&j,%str( )) is not valid.; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%end; | |
%else %let _tdivisor&i=1; | |
%end; | |
%else %do i = 1 %to &_nsurvvars_; | |
%let _tdivisor&i=1; | |
%end; | |
/*Check for appropriate TIMELIST values*/ | |
%if &_nsurvvars_>0 and %sysevalf(%superq(timelist)^=,boolean) %then %do i = 1 %to &_nsurvvars_; | |
%local _tl_&i; | |
%let _tl_&i=%qscan(%superq(timelist),&i,|,m); | |
%if %sysevalf(%superq(_tl_&i)^=,boolean) %then %do j = 1 %to %sysfunc(countw(%superq(_tl_&i),%str( ))); | |
%if %sysfunc(notdigit(%sysfunc(compress(%scan(%superq(_tl_&i),&j,%str( )),-.)))) > 0 %then %do; | |
/**Check if character values are present**/ | |
%put ERROR: (Global: TIMELIST) Values must be numeric. %scan(%superq(_tl_&i),&j,%str( )) is not valid.; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%else %if %superq(_tl_&i) lt 0 %then %do; | |
/**Check if value is below minimum threshold**/ | |
%put ERROR: (Global: TIMELIST) Values must be greater than or equal to 0. %scan(%superq(_tl_&i),&j,%str( )) is not valid.; | |
%let nerror=%eval(&nerror+1); | |
%end; | |
%end; | |
%end; | |
%end; | |
/*** If any errors exist, stop macro and send to end ***/ | |
%if &nerror > 0 %then %do; | |
%put ERROR: &nerror pre-run errors listed; | |
%put ERROR: Macro TABLEN will cease; | |
%goto errhandl; | |
%end; | |
%if &debug=1 %then %do; | |
options notes mprint; | |
%end; | |
/*Make final macro variable updates*/ | |
%local dis_suffix_listing; | |
%if %sysevalf(%qupcase(%superq(dis_suffix))=AUTO,boolean) %then %do; | |
%if %sysevalf(%qupcase(%superq(dis_display))=N_PCT,boolean) %then %do; | |
%let dis_suffix=^{style [fontweight=medium], n (%)}; | |
%let dis_suffix_listing=, n (%); | |
%end; | |
%else %if %sysevalf(%qupcase(%superq(dis_display))=N,boolean) %then %do; | |
%let dis_suffix=^{style [fontweight=medium], n}; | |
%let dis_suffix_listing=, n; | |
%end; | |
%else %if %sysevalf(%qupcase(%superq(dis_display))=PCT,boolean) %then %do; | |
%let dis_suffix=^{style [fontweight=medium], %}; | |
%let dis_suffix_listing=, %; | |
%end; | |
%end; | |
/**Pull dataset information**/ | |
proc contents data=&data out=_temp noprint; | |
run; | |
/**See if the listing output is turned on**/ | |
proc sql noprint; | |
select 1 into :_listing separated by '' from sashelp.vdest where upcase(destination)='LISTING'; | |
quit; | |
/*Start analysis*/ | |
/*Create subsetted temporary Dataset*/ | |
data _temp; | |
set &data; | |
where &where; | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
%if %sysevalf(%superq(bylabel)=,boolean) %then %do; call symput('bylabel',strip(vlabel(&by))); %end; | |
%end; | |
%if %sysevalf(%superq(rowby)^=,boolean) %then %do; | |
%if %sysevalf(%superq(rowbylabel)=,boolean) %then %do; call symput('rowbylabel',strip(vlabel(&rowby))); %end; | |
%end; | |
%if %sysevalf(%superq(colby)^=,boolean) %then %do; | |
%if %sysevalf(%superq(colbylabel)=,boolean) %then %do; call symput('colbylabel',strip(vlabel(&colby))); %end; | |
%end; | |
run; | |
/**Check where clause**/ | |
%if ^(&sysnobs>0) %then %do; | |
%put ERROR: (Model &z: WHERE): Issue parsing the WHERE clause; | |
%let nerror_run=%eval(&nerror_run+1); | |
%goto errhandl; | |
%end; | |
/**Row By variable Renaming**/ | |
%local nrowby _rowbylength _rowbylvls; | |
%if %sysevalf(%superq(rowby)^=,boolean) %then %do; | |
data _rowbyvar; | |
set _temp (keep=&rowby rename=(&rowby=_rowby_orig_)); | |
length _rowby_ $300.; | |
if strip(vvalue(_rowby_orig_))^='.' then _rowby_=strip(prxchange('s/\s/ /', -1,vvalue(_rowby_orig_))); | |
if missing(_rowby_) then _rowby_='Missing'; | |
_rowbylvl_=.; | |
run; | |
data _rowbyvar; | |
set _rowbyvar; | |
format _rowby_orig_; | |
run; | |
proc sort data=_rowbyvar out=_rowbyvarlvls nodupkey; | |
by _rowby_; | |
run; | |
%if %sysevalf(%superq(rowbyorder_formatted)=0,boolean) %then %do; | |
proc sort data=_rowbyvarlvls; | |
by _rowby_orig_; | |
run; | |
%end; | |
proc sql noprint; | |
select _rowby_ into :_rowbylvls separated by '|' | |
from _rowbyvarlvls; | |
%let nrowby=%sysfunc(countw(%superq(_rowbylvls),|,m)); | |
select max(length(_rowby_)) into :_rowbylength separated by '' | |
from _rowbyvar; | |
alter table _rowbyvar | |
modify _rowby_ char(&_rowbylength); | |
%if %sysevalf(%superq(rowbyorder)^=,boolean) %then %do; | |
update _rowbyvar | |
set _rowbylvl_=case(_rowby_) | |
%do i = 1 %to %sysfunc(countw(%superq(_rowbylvls),|,m)); | |
when "%scan(%superq(_rowbylvls),%scan(%superq(rowbyorder),&i,%str( )),|,m)" then &i | |
%end; | |
else . end; | |
%end; | |
%else %do; | |
update _rowbyvar | |
set _rowbylvl_=case(_rowby_) | |
%do i = 1 %to %sysfunc(countw(%superq(_rowbylvls),|,m)); | |
when "%scan(%superq(_rowbylvls),&i,|,m)" then &i | |
%end; | |
else . end; | |
%end; | |
quit; | |
%if %sysevalf(%superq(rowbyorder)^=,boolean) %then %do; | |
/**Pull largest value in order list**/ | |
%local _maxord; | |
%let _maxord = %sysfunc(max(%sysfunc(tranwrd(%superq(rowbyorder),%str( ),%str(,))))); | |
/**Pull number of items in order list**/ | |
%local _nord; | |
%let _nord = %sysfunc(countw(%superq(rowbyorder),%str( ))); | |
/**Check if there are too many levels given**/ | |
%if &_nord ^= %sysfunc(countw(%superq(_rowbylvls),|)) %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(rowbyorder)): Number in order list (&_nord) does not equal the number of values for rowby variable %qupcase(%superq(rowby)) (%sysfunc(countw(%superq(_rowbylvls),|))); | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
/**Check if the largest value is larger than the number of levels in the by variable**/ | |
%else %if &_maxord > %sysfunc(countw(%superq(_rowbylvls),|)) %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(rowbyorder)): Largest number in order list (&_maxord) is larger than the number of values for rowby variable %qupcase(%superq(rowby)) (%sysfunc(countw(%superq(_rowbylvls),|))); | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
/**Check if all values from 1 to max are represented in the order list**/ | |
%else %do _z2=1 %to %sysfunc(countw(%superq(_rowbylvls),|)); | |
%local _test; | |
%let _test=; | |
%do z = 1 %to &_maxord; | |
%if %scan(%superq(rowbyorder),&z,%str( )) = &_z2 %then %let _test=1; | |
%end; | |
%if &_test ^=1 %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(rowbyorder)): Number &_z2 was not found in the rowbyorder list; | |
%put ERROR: (Global: %qupcase(rowbyorder)): Each number from 1 to maximum number of levels in rowby variable %qupcase(%superq(rowby)) (&_maxord) must be represented; | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
%end; | |
%if &nerror_run =0 %then %do; | |
data _null_; | |
call symput("_rowbylvls", | |
%do j = 1 %to %sysfunc(countw(%superq(rowbyorder),%str( ))); | |
scan("%superq(_rowbylvls)",%scan(%superq(rowbyorder),&j,%str( )),'|') | |
%if &j ^=%sysfunc(countw(%superq(rowbyorder),%str( ))) %then %do; ||'|'|| %end; | |
%end;); | |
run; | |
%end; | |
%end; | |
%end; | |
%else %let nrowby=1; | |
/**Col By variable Renaming**/ | |
%local ncolby _colbylength _colbylvls; | |
%if %sysevalf(%superq(colby)^=,boolean) %then %do; | |
data _colbyvar; | |
set _temp (keep=&colby rename=(&colby=_colby_orig_)); | |
length _colby_ $300.; | |
if strip(vvalue(_colby_orig_))^='.' then _colby_=strip(prxchange('s/\s/ /', -1,vvalue(_colby_orig_))); | |
if missing(_colby_) then _colby_='Missing'; | |
_colbylvl_=.; | |
run; | |
data _colbyvar; | |
set _colbyvar; | |
format _colby_orig_; | |
run; | |
proc sort data=_colbyvar out=_colbyvarlvls nodupkey; | |
by _colby_; | |
run; | |
%if %sysevalf(%superq(colbyorder_formatted)=0,boolean) %then %do; | |
proc sort data=_colbyvarlvls; | |
by _colby_orig_; | |
run; | |
%end; | |
proc sql noprint; | |
select _colby_ into :_colbylvls separated by '|' | |
from _colbyvarlvls; | |
%let ncolby=%sysfunc(countw(%superq(_colbylvls),|,m)); | |
select max(length(_colby_)) into :_colbylength separated by '' | |
from _colbyvar; | |
alter table _colbyvar | |
modify _colby_ char(&_colbylength); | |
%if %sysevalf(%superq(colbyorder)^=,boolean) %then %do; | |
update _colbyvar | |
set _colbylvl_=case(_colby_) | |
%do i = 1 %to %sysfunc(countw(%superq(_colbylvls),|,m)); | |
when "%scan(%superq(_colbylvls),%scan(%superq(colbyorder),&i,%str( )),|,m)" then &i | |
%end; | |
else . end; | |
%end; | |
%else %do; | |
update _colbyvar | |
set _colbylvl_=case(_colby_) | |
%do i = 1 %to %sysfunc(countw(%superq(_colbylvls),|,m)); | |
when "%scan(%superq(_colbylvls),&i,|,m)" then &i | |
%end; | |
else . end; | |
%end; | |
quit; | |
%if %sysevalf(%superq(colbyorder)^=,boolean) %then %do; | |
/**Pull largest value in order list**/ | |
%local _maxord; | |
%let _maxord = %sysfunc(max(%sysfunc(tranwrd(%superq(colbyorder),%str( ),%str(,))))); | |
/**Pull number of items in order list**/ | |
%local _nord; | |
%let _nord = %sysfunc(countw(%superq(colbyorder),%str( ))); | |
/**Check if there are too many levels given**/ | |
%if &_nord ^= %sysfunc(countw(%superq(_colbylvls),|)) %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(colbyorder)): Number in order list (&_nord) does not equal the number of values for COLBY variable | |
%qupcase(%superq(colby)) (%sysfunc(countw(%superq(_colbylvls),|))); | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
/**Check if the largest value is larger than the number of levels in the by variable**/ | |
%else %if &_maxord > %sysfunc(countw(%superq(_colbylvls),|)) %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(colbyorder)): Largest number in order list (&_maxord) is larger than the number of values for COLBY variable | |
%qupcase(%superq(colby)) (%sysfunc(countw(%superq(_colbylvls),|))); | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
/**Check if all values from 1 to max are represented in the order list**/ | |
%else %do _z2=1 %to %sysfunc(countw(%superq(_colbylvls),|)); | |
%local _test; | |
%let _test=; | |
%do z = 1 %to &_maxord; | |
%if %scan(%superq(colbyorder),&z,%str( )) = &_z2 %then %let _test=1; | |
%end; | |
%if &_test ^=1 %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(colbyorder)): Number &_z2 was not found in the colbyorder list; | |
%put ERROR: (Global: %qupcase(colbyorder)): Each number from 1 to maximum number of levels in COLBY variable %qupcase(%superq(colby)) (&_maxord) must be represented; | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
%end; | |
%if &nerror_run =0 %then %do; | |
data _null_; | |
call symput("_colbylvls", | |
%do j = 1 %to %sysfunc(countw(%superq(colbyorder),%str( ))); | |
scan("%superq(_colbylvls)",%scan(%superq(colbyorder),&j,%str( )),'|') | |
%if &j ^=%sysfunc(countw(%superq(colbyorder),%str( ))) %then %do; ||'|'|| %end; | |
%end;); | |
run; | |
%end; | |
%end; | |
%end; | |
%else %let ncolby=1; | |
/**By variable Renaming**/ | |
%local nby _bylength _bylvls; | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
data _byvar; | |
set _temp (keep=&by rename=(&by=_by_orig_)); | |
length _by_ $300.; | |
_by_=strip(prxchange('s/\s/ /', -1,vvalue(_by_orig_))); | |
_bylvl_=.; | |
run; | |
data _byvar; | |
set _byvar; | |
format _by_orig_; | |
run; | |
proc sort data=_byvar out=_byvarlvls nodupkey; | |
by _by_; | |
where ^missing(_by_); | |
run; | |
%if %sysevalf(%superq(byorder_formatted)=0,boolean) %then %do; | |
proc sort data=_byvarlvls; | |
by _by_orig_; | |
run; | |
%end; | |
proc sql noprint; | |
select _by_ into :_bylvls separated by '|' | |
from _byvarlvls; | |
%let nby=%sysfunc(countw(%superq(_bylvls),|,m)); | |
select max(length(_by_)) into :_bylength separated by '' | |
from _byvar; | |
alter table _byvar | |
modify _by_ char(&_bylength); | |
%if %sysevalf(%superq(byorder)^=,boolean) %then %do; | |
update _byvar | |
set _bylvl_=case(_by_) | |
%do i = 1 %to %sysfunc(countw(%superq(_bylvls),|,m)); | |
when "%scan(%superq(_bylvls),%scan(%superq(byorder),&i,%str( )),|,m)" then &i | |
%end; | |
else %if %sysevalf(%superq(by_incmiss)=1,boolean) %then %do; 0 %end; | |
%else %do; .m %end; end; | |
%end; | |
%else %do; | |
update _byvar | |
set _bylvl_=case(_by_) | |
%do i = 1 %to %sysfunc(countw(%superq(_bylvls),|,m)); | |
when "%scan(%superq(_bylvls),&i,|,m)" then &i | |
%end; | |
else %if %sysevalf(%superq(by_incmiss)=1,boolean) %then %do; 0 %end; | |
%else %do; .m %end; end; | |
%end; | |
quit; | |
%if %sysevalf(%superq(byorder)^=,boolean) %then %do; | |
/**Pull largest value in order list**/ | |
%local _maxord _minord; | |
%let _maxord = %sysfunc(max(%sysfunc(tranwrd(%superq(byorder),%str( ),%str(,))))); | |
%let _minord = %sysfunc(min(%sysfunc(tranwrd(%superq(byorder),%str( ),%str(,))))); | |
/**Pull number of items in order list**/ | |
%local _nord; | |
%let _nord = %sysfunc(countw(%superq(byorder),%str( ))); | |
/**Check if there are too many levels given**/ | |
%if &_nord ^= %sysfunc(countw(%superq(_bylvls),|,m)) %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(byorder)): Number in order list (&_nord) is not equal to the number of values for by variable %qupcase(%superq(by)) (%sysfunc(countw(%superq(_bylvls),|,m))); | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
/**Check if the largest value is larger than the number of levels in the by variable**/ | |
%else %if &_maxord > %sysfunc(countw(%superq(_bylvls),|,m)) %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(byorder)): Largest number in order list (&_maxord) is larger than the number of values for by variable %qupcase(%superq(by)) (%sysfunc(countw(%superq(_bylvls),|,m))); | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
/**Check if all values from 1 to max are represented in the order list**/ | |
%else %do _z2=1 %to %sysfunc(countw(%superq(_bylvls),|,m)); | |
%local _test; | |
%let _test=; | |
%do z = 1 %to &_maxord; | |
%if %scan(%superq(byorder),&z,%str( )) = &_z2 %then %let _test=1; | |
%end; | |
%if &_test ^=1 %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(byorder)): Number &_z2 was not found in the byorder list; | |
%put ERROR: (Global: %qupcase(byorder)): Each number from 1 to maximum number of levels in by variable %qupcase(%superq(by)) (&_maxord) must be represented; | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
%end; | |
%if &nerror_run =0 %then %do; | |
data _null_; | |
call symput("_bylvls", | |
%do j = 1 %to %sysfunc(countw(%superq(byorder),%str( ))); | |
scan("%superq(_bylvls)",%scan(%superq(byorder),&j,%str( )),'|') | |
%if &j ^=%sysfunc(countw(%superq(byorder),%str( ))) %then %do; ||'|'|| %end; | |
%end;); | |
run; | |
%end; | |
%end; | |
%end; | |
%else %let nby=1; | |
%local _nbymiss _nobs; | |
proc sql noprint; | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
select sum((_bylvl_=0)) into :_nbymiss separated by '' from _byvar; | |
%end; | |
%else %let _nbymiss=0; | |
select count(*) into :_nobs separated by '' from _temp; | |
quit; | |
/**Change from Wilcoxon to Kruskal-Wallis**/ | |
%if (&nby>2 or (&nby=2 and &_nbymiss>0)) and %sysevalf(%superq(_numpvals_)^=,boolean) %then %do; | |
%let _numpvals_=%sysfunc(tranwrd(&_numpvals_,3,1)); | |
%let _numpvals_=%sysfunc(tranwrd(&_numpvals_,4,2)); | |
%end; | |
/*Rename Variables*/ | |
data _combined; | |
merge %do i = 1 %to &_nnumvars_;_temp (keep=%scan(%superq(_numvars_),&i,%str( )) rename=(%scan(%superq(_numvars_),&i,%str( ))=_num_&i)) %end; | |
%do i = 1 %to &_ndisvars_; _temp (keep=%scan(%superq(_disvars_),&i,%str( )) rename=(%scan(%superq(_disvars_),&i,%str( ))=_dis_orig_&i)) %end; | |
%do i = 1 %to &_nsurvvars_; _temp (keep=%scan(%superq(_survvars_),&i,%str( )) rename=(%scan(%superq(_survvars_),&i,%str( ))=_stime_&i)) | |
_temp (keep=%scan(%superq(surv_stat),&i,%str( )) rename=(%scan(%superq(surv_stat),&i,%str( ))=_sstat_&i)) %end; | |
%do i = 1 %to &_nlogvars_; _temp (keep=%scan(%superq(_logvars_),&i,%str( )) rename=(%scan(%superq(_logvars_),&i,%str( ))=_log_orig_&i)) %end; | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; _byvar %end; | |
%if %sysevalf(%superq(rowby)^=,boolean) %then %do; _rowbyvar %end; | |
%if %sysevalf(%superq(colby)^=,boolean) %then %do; _colbyvar %end; | |
%if %sysevalf(%superq(freq)^=,boolean) %then %do; _temp (keep=%superq(freq) rename=(%superq(freq)=_freq_)) %end;; | |
/**Set up lengths for new variables**/ | |
%if &_ndisvars_>0 or &_nlogvars_>0 %then %do; | |
length %do i = 1 %to &_ndisvars_; _dis_&i %end; %do i = 1 %to &_nlogvars_; _log_&i %end; $300.; | |
%end; | |
/**Setup variables for discrete type variables**/ | |
%if &_ndisvars_>0 %then %do i = 1 %to &_ndisvars_; | |
if strip(vvalue(_dis_orig_&i))^='.' then _dis_&i=strip(prxchange('s/\s/ /', -1, vvalue(_dis_orig_&i))); | |
_dis_&i._lvl=.; | |
%end; | |
/**Setup variables for survival type variables**/ | |
%if &_nsurvvars_>0 %then %do i = 1 %to &_nsurvvars_; | |
_stime_&i=_stime_&i/%superq(_tdivisor&i); | |
%end; | |
/**Setup variables for logistic type variables**/ | |
%if &_nlogvars_>0 %then %do i = 1 %to &_nlogvars_; | |
if strip(vvalue(_log_orig_&i))^='.' then _log_&i=strip(vvalue(_log_orig_&i)); | |
drop _log_orig_&i; | |
%end; | |
/**Setup variables for grouping variables**/ | |
%if %sysevalf(%superq(by)=,boolean) %then %do; _bylvl_=1; _by_='';%end; | |
%if %sysevalf(%superq(rowby)=,boolean) %then %do; _rowbylvl_=1;_rowby_=''; %end; | |
%if %sysevalf(%superq(colby)=,boolean) %then %do; _colbylvl_=1;_colby_='';%end; | |
%if %sysevalf(%superq(freq)=,boolean) %then %do; _freq_=1;%end; | |
run; | |
/**Setup ordering for discrete type variables**/ | |
%if &_ndisvars_>0 %then %do i = 1 %to &_ndisvars_; | |
proc sort data=_combined out=_dvarlvls&i (keep=_dis_orig_&i _dis_&i) nodupkey; | |
by _dis_&i; | |
where ^missing(_dis_&i); | |
format _dis_orig_&i; | |
run; | |
%if %sysevalf(%superq(dis_order_formatted)=0,boolean) %then %do; | |
proc sort data=_dvarlvls&i; | |
by _dis_orig_&i; | |
run; | |
%end; | |
%end; | |
%if &_ndisvars_>0 %then %do; | |
proc sql noprint; | |
%do i = 1 %to &_ndisvars_; | |
%local _null _dislength_&i _dislvls_&i _disorder_&i _disfrqorder_&i; | |
%let _disorder_&i=%sysfunc(strip(%qscan(%superq(dis_order),&i,|,m))); | |
%if %sysevalf(%qupcase(%superq(_disorder_&i))=FREQA,boolean) or %sysevalf(%qupcase(%superq(_disorder_&i))=FREQD,boolean) %then %do; | |
select _dis_&i,count(*) as n into :_dislvls_&i separated by '|',:null | |
from _combined where ^missing(_dis_&i) group by _dis_&i | |
order by n %if %sysevalf(%qupcase(%superq(_disorder_&i))^=FREQA,boolean) %then %do; desc %end;; | |
%end; | |
%else %do; | |
select _dis_&i into :_dislvls_&i separated by '|' | |
from _dvarlvls&i; | |
%end; | |
select max(length(_dis_&i)) into :_dislength_&i separated by '' | |
from _combined; | |
%end; | |
alter table _combined | |
modify | |
%do i = 1 %to &_ndisvars_; | |
%if &i>1 %then %do; , %end; | |
_dis_&i char(&&_dislength_&i) | |
%end;; | |
quit; | |
%do i = 1 %to &_ndisvars_; | |
%local _charcheck_; | |
%if %sysevalf(%superq(_disorder_&i)^=,boolean) %then %do; | |
%if %sysfunc(notdigit(%sysfunc(tranwrd(%superq(_disorder_&i),%str( ),0))))=0 %then %let _charcheck_=0; | |
%else %let _charcheck_=1; | |
%end; | |
%else %let _charcheck_=0; | |
%if %sysevalf(%superq(_disorder_&i)^=,boolean) and &_charcheck_=0 %then %do; | |
/**Pull largest value in order list**/ | |
%local _maxord _minord _exlist&i; | |
%let _exlist&i=%superq(_disorder_&i); | |
%let _minord = %sysfunc(min(%sysfunc(tranwrd(%superq(_disorder_&i),%str( ),%str(,))))); | |
%let _maxord = %sysfunc(max(%sysfunc(tranwrd(%superq(_disorder_&i),%str( ),%str(,))))); | |
/**Pull number of items in order list**/ | |
%local _nord; | |
%let _nord = %sysfunc(countw(%superq(_disorder_&i),%str( ))); | |
/**Check if there are too many levels given**/ | |
%if &_nord > %sysfunc(countw(%superq(_dislvls_&i),|)) %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(dis_order) variable &i): Number in order list (&_nord) greater than the number of values for %scan(&_disvars_,&i,%str( )) variable (%sysfunc(countw(%superq(_dislvls_&i),|))); | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
/**Check if the largest value is larger than the number of levels in the by variable**/ | |
%else %if &_maxord > %sysfunc(countw(%superq(_dislvls_&i),|)) %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(dis_order) variable &i): Largest number in order list (&_maxord) is larger than the number of values for %scan(&_disvars_,&i,%str( )) variable (%sysfunc(countw(%superq(_dislvls_&i),|))); | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
/**Check if the largest value is larger than the number of levels in the by variable**/ | |
%else %if &_minord < 1 %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(dis_order) variable &i): Smallest number in order list (&_minord) is less than 1 for %scan(&_disvars_,&i,%str( )) variable (%sysfunc(countw(%superq(_dislvls_&i),|))); | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
/**Check if all values from 1 to max are represented in the order list**/ | |
%else %do _z2=1 %to %sysfunc(countw(%superq(_dislvls_&i),|)); | |
%local _test _anyprob; | |
%let _test=; | |
%if &_z2=1 %then %let _anyprob=; | |
%do z = 1 %to &_maxord; | |
%if %scan(%superq(_disorder_&i),&z,%str( )) = &_z2 %then %let _test=1; | |
%end; | |
%if &_test ^=1 %then %let _exlist&i=&&_exlist&i &_z2; | |
%if &_test ^=1 and &dis_order_override=0 %then %do; | |
/**Throw errors**/ | |
%if &_anyprob^=1 %then %put WARNING: (GLOBAL: %qupcase(dis_order) %qupcase(%scan(&_disvars_,&i,%str( )))): Not all values of %qupcase(%scan(&_disvars_,&i,%str( ))) accounted for; | |
%put WARNING: (GLOBAL: %qupcase(dis_order) %qupcase(%scan(&_disvars_,&i,%str( )))): Number &_z2 was not found in the DIS_ORDER list; | |
%let _anyprob=1; | |
%end; | |
%end; | |
%if &_anyprob=1 %then %put WARNING: (GLOBAL: %qupcase(dis_order) %qupcase(%scan(&_disvars_,&i,%str( )))): Set DIS_ORDER_OVERRIDE=1 to suppress this warning; | |
%end; | |
%else %if %sysevalf(%superq(_disorder_&i)^=,boolean) and ^(%sysevalf(%qupcase(%superq(_disorder_&i))=FREQA,boolean) or %sysevalf(%qupcase(%superq(_disorder_&i))=FREQD,boolean)) %then %do; | |
/**Throw errors**/ | |
%put ERROR: (Global: %qupcase(dis_order) variable &i): Must specify either FREQA, FREQD or a space delimited numeric list; | |
%put ERROR: (Global: %qupcase(dis_order) variable &i): %superq(_disorder_&i) is not valid; | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
%end; | |
%if &nerror_run =0 %then %do; | |
proc sql noprint; | |
update _combined | |
set | |
%do i = 1 %to &_ndisvars_; | |
%if &i > 1 %then %do; , %end; | |
_dis_&i._lvl=case(_dis_&i) | |
%do j = 1 %to %sysfunc(countw(%superq(_dislvls_&i),|,m)); | |
%if %sysevalf(%superq(_disorder_&i)^=,boolean) and %sysevalf(%qupcase(%superq(_disorder_&i))^=FREQA,boolean) and %sysevalf(%qupcase(%superq(_disorder_&i))^=FREQD,boolean) %then %do; | |
%if %sysevalf(%scan(%superq(_disorder_&i),&j,%str( ))^=,boolean) %then %do; | |
when "%scan(%superq(_dislvls_&i),%scan(%superq(_disorder_&i),&j,%str( )),|,m)" then &j | |
%end; | |
%else %if %sysevalf(%scan(%superq(_exlist&i),&j,%str( ))^=,boolean) %then %do; | |
when "%scan(%superq(_dislvls_&i),%scan(%superq(_exlist&i),&j,%str( )),|,m)" then -&j | |
%end; | |
%end; | |
%else %do; | |
when "%scan(%superq(_dislvls_&i),&j,|,m)" then &j | |
%end; | |
%end; | |
else %if %sysevalf(%superq(dis_incmiss)=1,boolean) %then %do; 0 %end; | |
%else %do; .m %end; end | |
%end; | |
; | |
quit; | |
data _null_; | |
%do i = 1 %to &_ndisvars_; | |
%local _ndislvl_pre&i; | |
%let _ndislvl_pre&i=%sysfunc(countw(%superq(_dislvls_&i),|,m)); | |
%if %sysevalf(%superq(_disorder_&i)^=,boolean) and %sysevalf(%qupcase(%superq(_disorder_&i))^=FREQA,boolean) and %sysevalf(%qupcase(%superq(_disorder_&i))^=FREQD,boolean) %then %do; | |
call symput("_dislvls_&i", | |
%do j = 1 %to %sysfunc(countw(%superq(_disorder_&i),%str( ))); | |
scan("%superq(_dislvls_&i)",%scan(%superq(_disorder_&i),&j,%str( )),'|') | |
%if &j ^=%sysfunc(countw(%superq(_disorder_&i),%str( ))) %then %do; ||'|'|| %end; | |
%end;); | |
%end; | |
%end; | |
run; | |
%end; | |
%end; | |
/**Delete temporary variables**/ | |
proc datasets nolist nodetails; | |
%if &debug=0 %then %do; | |
delete _byvar _rowbyvar _colbyvar _byvarlvls _rowbyvarlvls _colbyvarlvls | |
%do i = 1 %to &_ndisvars_; _dvarlvls&i %end;; | |
%end; | |
quit; | |
/*Display variable values*/ | |
%local j _numindex _disindex _dateindex _survindex _logindex _timelistindex _anytimelist; | |
%let _numindex=0;%let _disindex=0;%let _dateindex=0;%let _survindex=0;%let _timelistindex=0;%let _logindex=0;%let _anytimelist=0; | |
%do i = 1 %to %sysfunc(countw(&var,%str( ))); | |
%local _displaylist_&i _ndisplay_&i; | |
%if %scan(&type,&i,%str( ))=1 or %scan(&type,&i,%str( ))=3 %then %do; | |
%if %scan(&type,&i,%str( ))=1 %then %do; | |
%let _numindex=%sysevalf(&_numindex + 1); | |
%let _displaylist_&i=%scan(%superq(contdisplay),&_numindex,|); | |
%end; | |
%else %if %scan(&type,&i,%str( ))=3 %then %do; | |
%let _dateindex=%sysevalf(&_dateindex + 1); | |
%let _displaylist_&i=%scan(%superq(datedisplay),&_dateindex,|); | |
%end; | |
%let _ndisplay_&i=%sysfunc(countw(&&_displaylist_&i,%str( ))); | |
%do j = 1 %to &&_ndisplay_&i; | |
%local _display_&i._&j; | |
%if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=N) %then %let _display_&i._&j=N; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=NMISS) %then %let _display_&i._&j=Missing; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=N_NMISS) %then %let _display_&i._&j=N (Missing); | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=MEAN) %then %let _display_&i._&j=Mean; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=SD) %then %let _display_&i._&j=SD; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=MEAN_SD) %then %let _display_&i._&j=Mean (SD); | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=MEDIAN) %then %let _display_&i._&j=Median; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=RANGE) %then %let _display_&i._&j=Range; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=IQR) %then %let _display_&i._&j=IQR; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=MEDIAN_RANGE) %then %let _display_&i._&j=Median (Range); | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=MEDIAN_IQR) %then %let _display_&i._&j=Median (IQR); | |
%end; | |
%end; | |
%else %if %scan(&type,&i,%str( ))=2 %then %do; | |
%let _disindex=%sysevalf(&_disindex + 1); | |
%let _displaylist_&i=; | |
%let _ndisplay_&i=%sysevalf(%sysfunc(countw(%superq(_dislvls_&_disindex),|))+1); | |
%local k; | |
%do j = 1 %to &&_ndisplay_&i; | |
%local _display_&i._&j; | |
%end; | |
%if %sysevalf(%qupcase(&dis_missorder)=FIRST,boolean) %then %let _display_&i._1=Missing; | |
%do j = 1 %to %sysfunc(countw(%superq(_dislvls_&_disindex),|)); | |
%let k=%sysevalf(&j + %sysevalf(%qupcase(&dis_missorder)=FIRST,boolean)); | |
%let _display_&i._&k=%qscan(%superq(_dislvls_&_disindex),&j,|); | |
%end; | |
%if %sysevalf(%qupcase(&dis_missorder)=LAST,boolean) %then %let _display_&i._&&_ndisplay_&i=Missing; | |
%end; | |
%else %if %scan(&type,&i,%str( ))=4 %then %do; | |
%let _survindex=%sysevalf(&_survindex + 1); | |
%let _timelistindex=0; | |
%let _displaylist_&i=%scan(%superq(survdisplay),&_survindex,|); | |
%let _ndisplay_&i=%sysfunc(countw(&&_displaylist_&i,%str( ))); | |
%if %sysfunc(find(&&_displaylist_&i,TIMELIST,i))>0 and %sysevalf(%scan(%superq(timelist),&_survindex,|)^=,boolean) %then %do; | |
%let _anytimelist=1; | |
%let _ndisplay_&i=%sysevalf(&&_ndisplay_&i + %sysfunc(countw(%scan(%superq(timelist),&_survindex,|),%str( ))) - 1); | |
%let _displaylist_&i=%sysfunc(tranwrd(%qupcase(&&_displaylist_&i),TIMELIST,%sysfunc(repeat(%str(TIMELIST ),%sysfunc(countw(%scan(%superq(timelist),&_survindex,|),%str( )))-1)))); | |
%end; | |
%else %if %sysfunc(find(&&_displaylist_&i,TIMELIST,i))>0 %then %do; | |
%let _ndisplay_&i=%sysevalf(&&_ndisplay_&i - 1); | |
%let _displaylist_&i=%sysfunc(tranwrd(%qupcase(&&_displaylist_&i),TIMELIST,%str())); | |
%end; | |
%do j = 1 %to &&_ndisplay_&i; | |
%local _display_&i._&j; | |
%if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=N) %then %let _display_&i._&j=N; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=EVENTS) %then %let _display_&i._&j=Events; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=EVENTS_N) %then %let _display_&i._&j=Events/N; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=MEDIAN) %then %let _display_&i._&j=Median (95% CI); | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=HR) %then %let _display_&i._&j=Hazard Ratio (95% CI); | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=COXPVAL) %then %let _display_&i._&j=Wald P-value; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=TIMELIST) %then %do; | |
%let _timelistindex=%sysevalf(&_timelistindex+1); | |
%let _display_&i._&j=%sysfunc(compbl(%scan(%scan(%superq(timelist),&_survindex,|),&_timelistindex,%str( )) %qscan(%superq(time_units),&i,%str(|)) Est (95% CI))); | |
%end; | |
%end; | |
%end; | |
%else %if %scan(&type,&i,%str( ))=5 %then %do; | |
%let _logindex=%sysevalf(&_logindex + 1); | |
%let _displaylist_&i=%scan(%superq(log_display),&_logindex,|); | |
%let _ndisplay_&i=%sysfunc(countw(&&_displaylist_&i,%str( ))); | |
%do j = 1 %to &&_ndisplay_&i; | |
%local _display_&i._&j; | |
%if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=N) %then %let _display_&i._&j=N; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=EVENTS) %then %let _display_&i._&j=Events; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=EVENTS_N) %then %let _display_&i._&j=Events/N; | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=BINRATE) %then %let _display_&i._&j=Event Rate (95% CI); | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=ODDSRATIO) %then %let _display_&i._&j=Odds Ratio (95% CI); | |
%else %if %sysevalf(%qupcase(%scan(%superq(_displaylist_&i),&j,%str( )))=WALDPVAL) %then %let _display_&i._&j=Wald P-value; | |
%end; | |
%end; | |
%end; | |
/**Check for reference values**/ | |
%local _cox _log; | |
%if (&_nsurvvars_>0 or &_nlogvars_>0) and %sysevalf(%superq(by)^=,boolean) %then %do; | |
%if &nby lt 2 %then %do; | |
%let _cox=0; | |
%let _log=0; | |
%end; | |
%else %if %index(%qupcase(&survdisplay),HR) or %index(%qupcase(&survdisplay),COXPVAL) or | |
%index(%qupcase(&log_display),ODDSRATIO) or %index(%qupcase(&log_display),WALDPVAL) or %index(%qupcase(&_logpvals_),1) or | |
%index(%qupcase(&_survpvals_),3) or %index(%qupcase(&_survpvals_),4) or %index(%qupcase(&_survpvals_),5) %then %do; | |
proc sql noprint; | |
%local _test _test2; | |
select %if %sysevalf(%superq(reference)^=,boolean) %then %do;min(test), %end; | |
ifn(max(nby)=min(nby),1,0) | |
into %if %sysevalf(%superq(reference)^=,boolean) %then %do; :_test separated by '', %end; :_test2 separated by '' | |
from (select _rowbylvl_,_colbylvl_, | |
%if %sysevalf(%superq(reference)^=,boolean) %then %do; max(ifn(strip(_by_)="&reference",1,0)) as test, %end; | |
count(distinct _by_) as nby from _combined group by _rowbylvl_,_colbylvl_); | |
quit; | |
%if &_test = 0 and %sysevalf(%superq(reference)^=,boolean) %then %do; | |
/**Throw errors**/ | |
%if %sysevalf(%superq(colby)^=,boolean) and %sysevalf(%superq(rowby)^=,boolean) %then | |
%put ERROR: (Global: %qupcase(REFERENCE)): Specified reference (%superq(reference)) is not present in all combinations of ROWBY and COLBY; | |
%else %if %sysevalf(%superq(colby)^=,boolean) %then | |
%put ERROR: (Global: %qupcase(REFERENCE)): Specified reference (%superq(reference)) is not present in all levels of COLBY; | |
%else %if %sysevalf(%superq(rowby)^=,boolean) %then | |
%put ERROR: (Global: %qupcase(REFERENCE)): Specified reference (%superq(reference)) is not present in all levels of ROWBY; | |
%else %put ERROR: (Global: %qupcase(REFERENCE)): Specified reference (%superq(reference)) is not present in the dataset; | |
%put ERROR: (Global: %qupcase(REFERENCE)): Make sure to specify the formatted value of %superq(by) as a reference level; | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
%else %if &_test2 =0 %then %do; | |
/**Throw warnings**/ | |
%put WARNING: (Global: %qupcase(REFERENCE)): Different number of levels for %superq(by) across COLBY and/or ROWBY subgroups; | |
%let _cox=1; | |
%let _log=1; | |
%end; | |
%else %do; | |
%let _cox=1; | |
%let _log=1; | |
%end; | |
%end; | |
%end; | |
%else %do; | |
%let _cox=0; | |
%let _log=0; | |
%end; | |
%local _refval; | |
%if &_cox = 1 and %sysevalf(%superq(reference)^=,boolean) %then %do; | |
%do i = 1 %to &nby; | |
%if %sysevalf(%qscan(%superq(_bylvls),&i,|,m)=%superq(reference),boolean) %then %do; | |
%let _refval=&i; | |
%let i=&nby; | |
%end; | |
%end; | |
%end; | |
%else %let _refval=&nby; | |
/*Check for 2 levels in each grouping combination*/ | |
%if &nerror_run=0 and &_nlogvars_>0 %then %do i = 1 %to &_nlogvars_; | |
proc sql noprint; | |
%local test1 test2 test3; | |
select min(cnt),max(cnt) into :test1 separated by '',:test2 separated by '' | |
from (select _rowbylvl_,_colbylvl_,_bylvl_,count(distinct _log_&i) as cnt from _combined | |
group by _rowbylvl_,_colbylvl_,_bylvl_); | |
select count(distinct _log_&i) into :test3 separated by '' from _combined; | |
quit; | |
%if &test3^=2 %then %do; | |
%put ERROR: (Global: %qupcase(LOG_EVENT)): Variable %scan(%superq(_logvars_),&i,%str( )) does not have exactly 2 levels in dataset; | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
%else %if &test1 ^= 2 or &test2^=2 %then %do; | |
%put ERROR: (Global: %qupcase(LOG_EVENT)): Variable %scan(%superq(_logvars_),&i,%str( )) does not have exactly 2 levels in all levels of ROWBY, COLBY, and BY variables; | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
%if &nerror_run=0 %then %do; | |
/*Check for appropriate LOG EVENT values*/ | |
%local _log_event&i; | |
%if %sysevalf(%qscan(%superq(log_event),&i,|,m)^=,boolean) %then %do; | |
%let _log_event&i=%qscan(%superq(log_event),&i,|,m); | |
proc sql noprint; | |
%local test; | |
select min(cnt) into :test separated by '' | |
from (select _rowbylvl_,_colbylvl_,_bylvl_,max(ifn(_log_&i="%superq(_log_event&i)",1,0)) as cnt from _combined | |
group by _rowbylvl_,_colbylvl_,_bylvl_); | |
quit; | |
%if &test=0 %then %do; | |
%put ERROR: (Global: %qupcase(LOG_EVENT)): Specified event (%superq(_log_event&i)) for variable %scan(%superq(_logvars_),&i,%str( )) not found in all levels of ROWBY, COLBY, and BY variables; | |
%let nerror_run=%eval(&nerror_run+1); | |
%end; | |
%end; | |
%else %do; | |
proc sql noprint; | |
%local test; | |
select max(_log_&i) into :_log_event&i separated by '' from _combined; | |
quit; | |
%end; | |
%end; | |
%end; | |
/*** If any errors exist, stop macro and send to end ***/ | |
%if &nerror_run > 0 %then %goto errhandl2; | |
/**Col By variable Renaming**/ | |
proc sort data=_combined; | |
by _colbylvl_ _rowbylvl_ _bylvl_; | |
run; | |
/*Calculates N columns for table display*/ | |
%do c = 1 %to &ncolby; | |
%do r = 1 %to &nrowby; | |
%do b = 1 %to &nby; | |
%local r&r._c&c._b&b._n; | |
%end; | |
%local r&r._c&c._n r&r._c&c._miss_n; | |
%end; | |
%end; | |
data _null_; | |
set _combined end=last; | |
by _colbylvl_ _rowbylvl_ _bylvl_; | |
array _counts_ {&ncolby,&nrowby,%sysevalf(&nby+1)} (%sysevalf(&ncolby*&nrowby*(1+&nby))*0); | |
array _counts2_ {&ncolby,&nrowby,2} (%sysevalf(&ncolby*&nrowby*2)*0); | |
retain _counts_ _counts2_; | |
_counts_(_colbylvl_,_rowbylvl_,ifn(_bylvl_ ^in(0 .m),_bylvl_,&nby+1))+1*_freq_; | |
if _bylvl_=0 then do; | |
_counts2_(_colbylvl_,_rowbylvl_,1)+1*_freq_; | |
_counts2_(_colbylvl_,_rowbylvl_,2)+1*_freq_; | |
end; | |
else _counts2_(_colbylvl_,_rowbylvl_,ifn(_bylvl_ ^in(.m),1,2))+1*_freq_; | |
if last then do; | |
do i=1 to &ncolby; | |
do j = 1 to &nrowby; | |
do k = 1 to &nby; | |
call symput(catt("r",j,"_c",i,"_b",k,"_n"),strip(put(_counts_(i,j,k),12.0))); | |
end; | |
call symput(catt("r",j,"_c",i,"_n"),strip(put(_counts2_(i,j,1),12.0))); | |
call symput(catt("r",j,"_c",i,"_miss_n"),strip(put(_counts2_(i,j,2),12.0))); | |
end; | |
end; | |
end; | |
run; | |
proc sql noprint; | |
%do b = 1 %to &nby; | |
%local _b&b._colbylist; | |
select distinct _colbylvl_ into :_b&b._colbylist separated by ' ' | |
from _combined where _bylvl_=&b; | |
%end; | |
%do c = 1 %to &ncolby; | |
%local _c&c._bylist; | |
select distinct _bylvl_ into :_c&c._bylist separated by ' ' | |
from _combined where _colbylvl_=&c and _bylvl_ ^in(.m 0); | |
%end; | |
create table _out | |
(rowby char(100),rowbylvl num,colby char(100),colbylvl num,indent num, | |
vartype num,varnum num,varlevel num,header num, | |
/*Meta-data for table*/ | |
meta num,nby num,ncolby num,nrowby num,title char(2000),footnote char(2000),pfoot char(1000), | |
factor char(2000), | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; | |
b&j._npct char(100), | |
%end; | |
m_npct char(100), | |
t_npct char(100), | |
pvaln num format=pvalue6.4, | |
pvalfoot char(100), | |
null num); | |
quit; | |
/**Assign Variable labels**/ | |
%do i = 1 %to %sysfunc(countw(&var,%str( ))); | |
/**If manual label not given, use variable's current label**/ | |
%if %sysevalf(%qscan(%superq(labels),&i,|,m)=,boolean) %then %do; | |
data _null_; | |
set &data (obs=1); | |
call symput("label&i",strip(vlabel(%scan(&var,&i,%str( ))))); | |
run; | |
%end; | |
%else %let label&i=%qscan(%superq(labels),&i,|,m); | |
%end; | |
%local _rtf; | |
proc sql noprint; | |
select max(ifn(upcase(destination)='RTF',1,0)) | |
into :_rtf separated by '' from sashelp.vdest; | |
quit; | |
%if &_rtf=1 %then %do; | |
ODS RTF EXCLUDE ALL; | |
%end; | |
%if &_nnumvars_>0 %then %do; | |
/*Distributions and p-values for numeric variables*/ | |
data _numeric; | |
set _combined; | |
array _num_ {&_nnumvars_}; | |
array _numtypes_ {&_nnumvars_} (%sysfunc(tranwrd(&_numtype_,%str( ),%str(,)))); | |
do i = 1 to dim(_num_); | |
_numvar_=i; | |
_numval_=_num_(i); | |
_numtype_=_numtypes_(i); | |
if scan("&_numpvals_",i,' ') in('2' '4') then exact=1; | |
else exact=0; | |
if scan("&_numpvals_",i,' ') in('6' '7') then ttest=1; | |
output; | |
end; | |
drop i _numtypes_:; | |
run; | |
%local _nexact _nttest; | |
proc sql noprint; | |
select max(exact),max(ttest) into :_nexact separated by '',:_nttest separated by '' | |
from _numeric; | |
quit; | |
proc sort data=_numeric; | |
by _colbylvl_ _rowbylvl_ _numvar_ _bylvl_; | |
run; | |
/**Get statistics**/ | |
proc means data=_numeric noprint missing; | |
by _colbylvl_ _rowbylvl_ _numvar_ _numtype_; | |
class _bylvl_; | |
var _numval_; | |
output out=_num_stat n=n nmiss=nmiss mean=mean stddev=stddev | |
median=median min=min max=max q1=q1 q3=q3; | |
where _bylvl_^=.m; | |
freq _freq_; | |
run; | |
proc means data=_numeric noprint missing; | |
by _colbylvl_ _rowbylvl_ _numvar_ _numtype_; | |
class _bylvl_; | |
var _numval_; | |
output out=_num_statm n=n nmiss=nmiss mean=mean stddev=stddev | |
median=median min=min max=max q1=q1 q3=q3; | |
where _bylvl_=.m; | |
freq _freq_; | |
run; | |
data _num_stat; | |
set _num_stat _num_statm (where=(_type_=1)); | |
proc sort data=_num_stat; | |
by _colbylvl_ _rowbylvl_ _numvar_ _numtype_; | |
data _num_stat2; | |
set _num_stat; | |
by _colbylvl_ _rowbylvl_ _numvar_ _numtype_; | |
if first._colbylvl_ or first._rowbylvl_ then _conttype_=0; | |
length factor n_pct $100.; | |
if _numtype_=1 then do; | |
if first._numvar_ then _conttype_+1; | |
%do j = 1 %to &_nnumvars_; | |
%if &j>1 %then %do; else %end; | |
if _conttype_=&j then do; | |
factor='N';n_pct=ifc(n>0,strip(put(n,12.0)),'');output; | |
factor="Missing";n_pct=ifc(n>0,strip(put(nmiss,12.0)),'');output; | |
factor="N (Missing)";n_pct=ifc(n>0,strip(put(n,12.0))||' ('||strip(put(nmiss,12.0))||')','');output; | |
factor="Mean";n_pct=ifc(n>0,strip(put(mean,12.%scan(&meandigits,&j,|))),'');output; | |
factor="SD";n_pct=ifc(n>0,strip(put(stddev,12.%scan(&stddigits,&j,|))),'');output; | |
factor="Mean (SD)";n_pct=ifc(n>0,strip(put(mean,12.%scan(&meandigits,&j,|)))||' ('||strip(put(stddev,12.%scan(&stddigits,&j,|)))||')','');output; | |
factor="Median";n_pct=ifc(n>0,strip(put(median,12.%scan(&mediandigits,&j,|))),'');output; | |
factor="Range";n_pct=ifc(n>0,strip(put(min,12.%scan(&rangedigits,&j,|)))||', '||strip(put(max,12.%scan(&rangedigits,&j,|))),'');output; | |
factor="IQR";n_pct=ifc(n>0,strip(put(q1,12.%scan(&iqrdigits,&j,|)))||', '||strip(put(q3,12.%scan(&iqrdigits,&j,|))),'');output; | |
factor="Median (Range)";n_pct=ifc(n>0,strip(put(median,12.%scan(&mediandigits,&j,|))),'')||ifc(n>0,' ('||strip(put(min,12.%scan(&rangedigits,&j,|)))||', '||strip(put(max,12.%scan(&rangedigits,&j,|)))||')','');output; | |
factor="Median (IQR)";n_pct=ifc(n>0,strip(put(median,12.%scan(&mediandigits,&j,|))),'')||ifc(n>0,' ('||strip(put(q1,12.%scan(&iqrdigits,&j,|)))||', '||strip(put(q3,12.%scan(&iqrdigits,&j,|)))||')','');output; | |
end; | |
%end; | |
end; | |
else if _numtype_=3 then do; | |
factor='N';n_pct=ifc(n>0,strip(put(n,12.0)),'');output; | |
factor="Missing";n_pct=ifc(n>0,strip(put(nmiss,12.0)),'');output; | |
factor="N (Missing)";n_pct=ifc(n>0,strip(put(n,12.0))||' ('||strip(put(nmiss,12.0))||')','');output; | |
factor="Mean";n_pct=ifc(n>0,strip(put(mean,&datefmt.)),'');output; | |
factor="SD";n_pct=ifc(n>0,strip(put(stddev,&datefmt.))||' days','');output; | |
factor="Mean (SD)";n_pct=ifc(n>0,strip(put(mean,&datefmt.))||' ('||strip(put(stddev,&datefmt.))||' days)','');output; | |
factor="Median";n_pct=ifc(n>0,strip(put(median,&datefmt.)),'');output; | |
factor="Range";n_pct=ifc(n>0,strip(put(min,&datefmt.))||', '||strip(put(max,&datefmt.)),'');output; | |
factor="IQR";n_pct=ifc(n>0,strip(put(q1,&datefmt.))||', '||strip(put(q3,&datefmt.)),'');output; | |
factor="Median (Range)";n_pct=ifc(n>0,strip(put(median,&datefmt.)),'')||ifc(n>0,' ('||strip(put(min,&datefmt.))||', '||strip(put(max,&datefmt.))||')','');output; | |
factor="Median (IQR)";n_pct=ifc(n>0,strip(put(median,&datefmt.)),'')||ifc(n>0,' ('||strip(put(q1,&datefmt.))||', '||strip(put(q3,&datefmt.))||')','');output; | |
end; | |
keep _colbylvl_ _rowbylvl_ _numvar_ _numtype_ _bylvl_ factor n_pct; | |
run; | |
proc sort data=_num_stat2; | |
by _colbylvl_ _rowbylvl_ _numvar_ _numtype_ factor; | |
data _num_stat3; | |
merge _num_stat2 (where=(_bylvl_=.) rename=(n_pct=t_npct)) | |
_num_stat2 (where=(_bylvl_=ifn(&by_incmiss,0,.m)) rename=(n_pct=m_npct)) | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; | |
_num_stat2 (where=(_bylvl_=&j) rename=(n_pct=b&j._npct)) | |
%end;; | |
by _colbylvl_ _rowbylvl_ _numvar_ _numtype_ factor; | |
drop _bylvl_; | |
run; | |
proc sql noprint; | |
%local nby_num_nomiss; | |
select count(distinct _bylvl_) into :nby_num_nomiss separated by '' from _numeric where ^missing(_numval_); | |
quit; | |
%if %sysevalf(%superq(nby)>1,boolean) and &nby_num_nomiss>1 %then %do; | |
/**Get P-values**/ | |
proc npar1way data=_numeric noprint; | |
by _colbylvl_ _rowbylvl_ _numvar_; | |
class _bylvl_; | |
var _numval_; | |
output out=_num_p1 wilcoxon anova; | |
freq _freq_; | |
run; | |
%if &_nexact=1 %then %do; | |
proc npar1way data=_numeric noprint; | |
by _colbylvl_ _rowbylvl_ _numvar_; | |
class _bylvl_; | |
var _numval_; | |
exact wilcoxon kw; | |
output out=_num_p1e wilcoxon anova; | |
where exact=1; | |
freq _freq_; | |
run; | |
%end; | |
%if &nby =2 and &_nttest=1 %then %do; | |
%if &_rtf=1 %then %do; | |
ODS RTF EXCLUDE ALL; | |
%end; | |
proc ttest data=_numeric; | |
by _colbylvl_ _rowbylvl_ _numvar_; | |
class _bylvl_; | |
var _numval_; | |
ods output TTests=_num_p2; | |
freq _freq_; | |
run; | |
%end; | |
%end; | |
%else %do; | |
proc univariate data=_numeric noprint; | |
by _colbylvl_ _rowbylvl_ _numvar_; | |
var _numval_; | |
output out=_num_p3 probt=probt probs=probs; | |
freq _freq_; | |
run; | |
%end; | |
%end; | |
/*Distributions and p-values for discrete variables*/ | |
%if &_ndisvars_>0 %then %do; | |
data _discrete; | |
set _combined; | |
array _dis_ {&_ndisvars_} $300.; | |
array _dis_lvl {&_ndisvars_} %do i = 1 %to &_ndisvars_; _dis_&i._lvl %end;; | |
array _ndis_ {&_ndisvars_} | |
(%do i = 1 %to &_ndisvars_; | |
%if &i>1 %then %do; , %end; | |
%sysfunc(countw(%superq(_dislvls_&i),|,m)) | |
%end;); | |
length _disval_ $300.; | |
do i = 1 to dim(_dis_); | |
_disvar_=i; | |
_dislvl_=_dis_lvl(i); | |
_disval_=_dis_(i); | |
if scan("&_dispvals_",i,' ') in('2') then exact=1; | |
else exact=0; | |
if scan("&_dispvals_",i,' ') in('3') and (&nby=2 or _ndis_(i)) then trend=1; | |
else trend=0; | |
output; | |
end; | |
drop i; | |
run; | |
%local _dtrend _dexact _dmaxn; | |
proc sql noprint; | |
select max(trend),max(exact) into :_dtrend separated by '',:_dexact separated by '' | |
from _discrete; | |
select max(n) into :_dmaxn separated by '' | |
from (select _colbylvl_,_rowbylvl_,_disvar_,count(distinct _dislvl_) as n | |
from _discrete group by _colbylvl_,_rowbylvl_,_disvar_); | |
quit; | |
proc sort data=_discrete; | |
by _colbylvl_ _rowbylvl_ _disvar_ _bylvl_; | |
run; | |
/**Get Frequencies and first p-value**/ | |
proc freq data=_discrete noprint; | |
*by _colbylvl_ _rowbylvl_ _disvar_; | |
table _colbylvl_*_rowbylvl_*_disvar_*_dislvl_*_bylvl_ / outpct sparse out=_dis_stat; | |
weight _freq_ / zeros; | |
run; | |
%if &nby>1 and &_dmaxn>1 %then %do; | |
proc freq data=_discrete noprint; | |
by _colbylvl_ _rowbylvl_ _disvar_; | |
table _dislvl_*_bylvl_ / chisq nowarn sparse ; | |
output out=_dis_p1 chisq; | |
where _dislvl_^=.m; | |
weight _freq_ /*/ zeros*/; | |
run; | |
%if &_dexact=1 %then %do; | |
proc freq data=_discrete noprint; | |
by _colbylvl_ _rowbylvl_ _disvar_; | |
table _dislvl_*_bylvl_ / fisher nowarn; | |
output out=_dis_p2 fisher; | |
where exact=1 and _dislvl_^=.m; | |
weight _freq_ /*/ zeros*/; | |
run; | |
%end; | |
%if &_dtrend=1 %then %do; | |
proc freq data=_discrete noprint; | |
by _colbylvl_ _rowbylvl_ _disvar_; | |
table _dislvl_*_bylvl_ / trend nowarn ; | |
output out=_dis_p3 trend; | |
where trend=1 and _dislvl_^=.m; | |
weight _freq_ /*/ zeros*/; | |
run; | |
%end; | |
%end; | |
data _dis_stat_missings; | |
array _ndis_ {&_ndisvars_} | |
(%do i = 1 %to &_ndisvars_; | |
%if &i>1 %then %do; , %end; | |
%sysfunc(countw(%superq(_dislvls_&i),|,m)) | |
%end;); | |
do _rowbylvl_ = 1 to &nrowby; | |
do _colbylvl_ = 1 to &ncolby; | |
do _bylvl_ = 1 to &nby; | |
do _disvar_ = 1 to &_ndisvars_; | |
_dislvl_ = ifn(%superq(dis_incmiss),0,.m);output; | |
end; | |
end; | |
_bylvl_=ifn(%superq(by_incmiss),0,.m); | |
do _disvar_ = 1 to &_ndisvars_; | |
do _dislvl_ = 1 to _ndis_(_disvar_); | |
output; | |
end; | |
_dislvl_ = ifn(%superq(dis_incmiss),0,.m);output; | |
end; | |
end; | |
end; | |
drop _ndis_:; | |
run; | |
proc sql noprint; | |
create table _dis_stat2 as | |
select *,sum(ifn(_bylvl_^=.m,count,0)) as row_n_nomiss,sum(ifn(_bylvl_^=.m,column_n_nomiss,0)) as column_t_n_nomiss,sum(column_all) as column_t_all | |
from (select *,sum(ifn(_dislvl_^=.m,count,0)) as column_n_nomiss,sum(count) as column_all | |
from | |
(select * from _dis_stat | |
OUTER UNION CORR | |
select _colbylvl_,_rowbylvl_,_disvar_,_dislvl_,_bylvl_,0 as count,0 as percent,0 as pct_tabl,0 as pct_col,0 as pct_row | |
from _dis_stat_missings) | |
group by _colbylvl_,_rowbylvl_,_bylvl_,_disvar_) | |
group by _colbylvl_,_rowbylvl_,_disvar_,_dislvl_ | |
order by _colbylvl_,_rowbylvl_,_disvar_,_dislvl_,_bylvl_,count; | |
*insert into _dis_stat | |
select _colbylvl_,_rowbylvl_,_disvar_,_dislvl_,_bylvl_,0 as count,0 as percent,0 as pct_col,0 as pct_col,0 as pct_row | |
from _dis_stat_missings; | |
quit; | |
data _dis_stat2; | |
set _dis_stat2; | |
by _colbylvl_ _rowbylvl_ _disvar_ _dislvl_ _bylvl_; | |
retain _tsum _tpct; | |
length n_pct $100.; | |
if first._dislvl_ then do; | |
_tsum=0;_tpct=0; | |
end; | |
if count>=0 and _bylvl_^=.m then _tsum=_tsum+count; | |
if pct_tabl>=0 and _bylvl_^=.m then _tpct=_tpct+pct_tabl; | |
%do j = 1 %to &_ndisvars_; | |
%if &j>1 %then %do; else %end; | |
if _disvar_=&j then do; | |
if upcase("%superq(dis_display)")='N_PCT' then n_pct=compbl(strip(put(count,12.0))|| | |
%if %qupcase(&PCTDISPLAY)=COL and &DIS_PRINTMISS=3 %then %do; | |
ifc(_dislvl_^=.m and _bylvl_^=.m and column_n_nomiss<column_all,'/'||strip(put(column_n_nomiss,12.)),'')|| | |
%end; | |
ifc(_dislvl_^=.m and _bylvl_^=.m,' ('||strip(put(pct_&pctdisplay,12.%scan(&pctdigits,&j,|)))||'%)','')); | |
else if upcase("%superq(dis_display)")='N' then n_pct=strip(put(count,12.0)); | |
else if upcase("%superq(dis_display)")='PCT' then n_pct=ifc(_dislvl_^=.m and _bylvl_^=.m,strip(put(pct_&pctdisplay,12.%scan(&pctdigits,&j,|))),strip(put(count,12.0))); | |
end; | |
%end; | |
if ^last._dislvl_ and last._bylvl_ then output; | |
else if last._dislvl_ then do; | |
output; | |
_bylvl_=.t; | |
%do j = 1 %to &_ndisvars_; | |
%if &j>1 %then %do; else %end; | |
if _disvar_=&j then do; | |
if upcase("%superq(dis_display)")='N_PCT' then n_pct=compbl(strip(put(_tsum,12.0))|| | |
%if &DIS_PRINTMISS=3 %then %do; | |
ifc(_dislvl_^=.m and _bylvl_^=.m and column_t_n_nomiss<column_t_all,'/'||strip(put(column_t_n_nomiss,12.)),'')|| | |
%end; | |
ifc(_dislvl_^=.m,' ('||strip(put(_tpct,12.%scan(&pctdigits,&j,|)))||'%)','')); | |
else if upcase("%superq(dis_display)")='N' then n_pct=strip(put(_tsum,12.0)); | |
else if upcase("%superq(dis_display)")='PCT' then n_pct=ifc(_dislvl_^=.m,strip(put(_tpct,12.%scan(&pctdigits,&j,|))),strip(put(_tsum,12.0))); | |
output; | |
end; | |
%end; | |
end; | |
drop count percent pct_tabl pct_col pct_row _tsum _tpct; | |
run; | |
data _dis_stat3; | |
merge _dis_stat2 (where=(_bylvl_=.t) rename=(n_pct=t_npct)) | |
_dis_stat2 (where=(_bylvl_ in(0 .m)) rename=(n_pct=m_npct)) | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; | |
_dis_stat2 (where=(_bylvl_=&j) rename=(n_pct=b&j._npct)) | |
%end;; | |
by _colbylvl_ _rowbylvl_ _disvar_ _dislvl_; | |
drop _bylvl_; | |
run; | |
%end; | |
/*Distributions and p-values for survival variables*/ | |
%if &_nsurvvars_>0 %then %do; | |
data _survival; | |
set _combined; | |
array _stime_ {&_nsurvvars_}; | |
array _sstat_ {&_nsurvvars_}; | |
array _cen_vl {&_nsurvvars_} (%do j = 1 %to &_nsurvvars_; %if &j>1 %then %do; , %end; %scan(%superq(cen_vl),&j,%str( )) %end;); | |
do i = 1 to dim(_stime_); | |
if _bylvl_=0 then _by_="*M*"; | |
_survvar_=i; | |
_time_=_stime_(i); | |
_stat_=_sstat_(i); | |
_censor_=_cen_vl(i); | |
if ^missing("&by") and _bylvl_^=.m then do; | |
_set_=1; | |
output; | |
end; | |
else if _bylvl_=.m then do; | |
_set_=2; | |
output; | |
end; | |
end; | |
do i = 1 to dim(_stime_); | |
_survvar_=i; | |
_time_=_stime_(i); | |
_stat_=_sstat_(i); | |
_censor_=_cen_vl(i); | |
_bylvl_=.; | |
_by_=''; | |
_set_=3; | |
output; | |
end; | |
drop i _stime_: _sstat_:; | |
run; | |
proc sort data=_survival; | |
by _colbylvl_ _rowbylvl_ _survvar_ _set_ _bylvl_; | |
run; | |
/*Calculate how many unique censor values there are*/ | |
proc sql noprint; | |
select distinct _censor_ into :_cenlist separated by ' ' from _survival; | |
quit; | |
%local k; | |
%do k = 1 %to %sysfunc(countw(&_cenlist,%str( ))); | |
%if &_rtf=1 %then %do; | |
ODS RTF EXCLUDE ALL; | |
%end; | |
proc lifetest data=_survival missing | |
%if &_anytimelist %then %do; | |
timelist=%do j = 1 %to %sysfunc(countw(%superq(timelist),|)); | |
%scan(%superq(timelist),&j,|) | |
%end; | |
reduceout outs=_surv_stat3_&k | |
%end; conftype=&conftype; | |
by _colbylvl_ _rowbylvl_ _survvar_ _set_; | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
strata _bylvl_ / TEST=(LOGRANK WILCOXON); | |
%end; | |
time _time_*_stat_(%scan(%superq(_cenlist),&k,%str( ))); | |
ods output quartiles=_surv_stat2_&k (where=(percent=50)) censoredsummary=_surv_stat1_&k | |
%if &nby>1 %then %do; homtests=_surv_p1_&k %end;; | |
where _censor_=%scan(%superq(_cenlist),&k,%str( )); | |
freq _freq_; | |
run; | |
%if &_cox=1 %then %do; | |
%if &_rtf=1 %then %do; | |
ODS RTF EXCLUDE ALL; | |
%end; | |
proc phreg data=_survival; | |
by _colbylvl_ _rowbylvl_ _survvar_ _set_; | |
class _bylvl_ %if %sysevalf(%superq(reference)^=,boolean) %then %do; (ref="&_refval") %end;; | |
model _time_*_stat_(%scan(%superq(_cenlist),&k,%str( ))) = _bylvl_ / rl type3(LR SCORE WALD); | |
ods output parameterestimates=_surv_stat4_&k | |
%if %sysevalf(9.04.01M2P072314 > &sysvlong,boolean) %then %do; | |
type3=_surv_p2_&k | |
%end; | |
%else %do; | |
modelanova=_surv_p2_&k | |
%end;; | |
where _censor_=%scan(%superq(_cenlist),&k,%str( )) and _set_=1; | |
freq _freq_; | |
run; | |
%end; | |
%end; | |
data _surv_stat1; | |
set %do k = 1 %to %sysfunc(countw(&_cenlist,%str( ))); _surv_stat1_&k %end;; | |
run; | |
data _surv_stat2; | |
set %do k = 1 %to %sysfunc(countw(&_cenlist,%str( ))); _surv_stat2_&k %end;; | |
run; | |
%if &_anytimelist %then %do; | |
data _surv_stat3; | |
set %do k = 1 %to %sysfunc(countw(&_cenlist,%str( ))); _surv_stat3_&k %end;; | |
run; | |
%end; | |
%if &nby>1 %then %do; | |
data _surv_p1; | |
set %do k = 1 %to %sysfunc(countw(&_cenlist,%str( ))); _surv_p1_&k %end;; | |
run; | |
%if &_cox =1 %then %do; | |
data _surv_stat4; | |
set %do k = 1 %to %sysfunc(countw(&_cenlist,%str( ))); _surv_stat4_&k %end;; | |
run; | |
data _surv_p2; | |
set %do k = 1 %to %sysfunc(countw(&_cenlist,%str( ))); _surv_p2_&k %end;; | |
run; | |
%end; | |
%end; | |
%else %if &nby=1 %then %do; | |
data _surv_p1; | |
do r=1 to &nrowby; | |
do c=1 to &ncolby; | |
_rowbylvl_=r;_colbylvl_=c;output; | |
end; | |
end; | |
run; | |
%end; | |
proc sql noprint; | |
create table _surv_stat as | |
select a._colbylvl_,a._rowbylvl_,a._survvar_,a._set_, | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
a._bylvl_, | |
%end; | |
%else %do; | |
. as _bylvl_, | |
%end; | |
strip(put(a.total,12.0)) as n,strip(put(a.failed,12.0)) as events,strip(put(a.failed,12.0))||'/'||strip(put(a.total,12.0)) as events_n, | |
case (a._survvar_) | |
%do i = 1 %to &_nsurvvars_; | |
when &i then | |
ifc(^missing(b.estimate),strip(put(b.estimate,12.%scan(&smediandigits.,&i,|))),'NE')|| ' ('|| | |
ifc(^missing(b.lowerlimit),strip(put(b.lowerlimit,12.%scan(&smediandigits.,&i,|))),'NE')||'^_'||'-'||'^_'|| | |
ifc(^missing(b.upperlimit),strip(put(b.upperlimit,12.%scan(&smediandigits.,&i,|))),'NE')||')' | |
%end; else '' end as median | |
%if &_cox =1 %then %do; | |
,ifc(a._set_=1 and missing(c.hazardratio),'Reference', | |
ifc(a._set_ in(2 3),'', | |
case (a._survvar_) | |
%do i = 1 %to &_nsurvvars_; | |
when &i then strip(put(hazardratio, 12.%scan(&hrdigits.,&i,|)))|| ' ('|| | |
strip(put(hrlowercl,12.%scan(&hrdigits.,&i,|)))||'^_'||'-'||'^_'|| | |
strip(put(hruppercl,12.%scan(&hrdigits.,&i,|))) | |
%end; | |
else '' end||')')) as hr, | |
ifc(a._set_=1 and missing(c.probchisq),'Reference', | |
ifc(a._set_ in(2 3),'',strip(put(c.probchisq,pvalue6.&pvaldigits.)))) as coxpval | |
%end; | |
from (select * from _surv_stat1 %if %sysevalf(%superq(by)^=,boolean) %then %do; where missing(control_var) %end;) a left join _surv_stat2 b | |
on a._colbylvl_=b._colbylvl_ and a._rowbylvl_=b._rowbylvl_ and a._survvar_=b._survvar_ %if %sysevalf(%superq(by)^=,boolean) %then %do; and a._bylvl_=b._bylvl_ %end; | |
and a._set_=b._set_ | |
%if &_cox =1 %then %do; | |
left join _surv_stat4 c | |
on a._colbylvl_=c._colbylvl_ and a._rowbylvl_=c._rowbylvl_ and a._survvar_=c._survvar_ and a._bylvl_=input(c.classval0,12.) | |
%end; | |
order by _colbylvl_,_rowbylvl_,_survvar_,_set_,_bylvl_; | |
%if &_anytimelist=1 %then %do; | |
create table _surv_stat_tl as | |
select a._colbylvl_,a._rowbylvl_,a._survvar_,a._set_, | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
a._bylvl_, | |
%end; | |
%else %do; | |
. as _bylvl_, | |
%end; | |
a.timelist, | |
case (a._survvar_) | |
%do i = 1 %to &_nsurvvars_; | |
when &i then | |
ifc(^missing(survival),strip(put(survival*ifn(upcase("&timelistfmt")="PCT",100,1),12.%scan(&tldigits.,&i,|)))||ifc(upcase("&timelistfmt")="PCT",'%',''),'NE')||' ('|| | |
ifc(^missing(sdf_lcl),strip(put(sdf_lcl*ifn(upcase("&timelistfmt")="PCT",100,1),12.%scan(&tldigits.,&i,|))),'NE')||'^_'||'-'||'^_'|| | |
ifc(^missing(sdf_ucl),strip(put(sdf_ucl*ifn(upcase("&timelistfmt")="PCT",100,1),12.%scan(&tldigits.,&i,|))),'NE')||')' | |
%end; | |
else '' end as tl | |
from _surv_stat3 a | |
order by _colbylvl_,_rowbylvl_,_survvar_,_set_,_bylvl_; | |
%end; | |
quit; | |
data _surv_stat_2; | |
set _surv_stat; | |
length factor n_pct $100.; | |
factor='N';n_pct=n;output; | |
factor='Events';n_pct=events;output; | |
factor='Events/N';n_pct=events_n;output; | |
factor='Median (95% CI)';n_pct=median;output; | |
factor='Hazard Ratio (95% CI)';n_pct=hr;output; | |
factor='Wald P-value';n_pct=coxpval;output; | |
keep _colbylvl_ _rowbylvl_ _survvar_ factor n_pct _set_ _bylvl_; | |
run; | |
%if &_anytimelist=1 %then %do; | |
data _surv_stat_tl2; | |
set _surv_stat_tl; | |
length factor n_pct $100.; | |
factor=catx(' ',timelist,scan("%superq(time_units)",_survvar_,'|','m'),'Est (95% CI)');n_pct=tl; | |
drop timelist tl; | |
run; | |
%end; | |
data _surv_stat_3; | |
set _surv_stat_2 %if &_anytimelist=1 %then %do; _surv_stat_tl2 %end;; | |
run; | |
proc sort data=_surv_stat_3; | |
by _colbylvl_ _rowbylvl_ _survvar_ factor; | |
data _surv_stat_4; | |
merge _surv_stat_3 (where=(_bylvl_=. and _set_=3) rename=(n_pct=t_npct)) | |
_surv_stat_3 (where=(_set_=ifn(&by_incmiss=0,2,1) %if &by_incmiss=1 %then %do; and _bylvl_=0 %end;) rename=(n_pct=m_npct)) | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; | |
_surv_stat_3 (where=(_bylvl_=&j and _set_=1) rename=(n_pct=b&j._npct)) | |
%end;; | |
by _colbylvl_ _rowbylvl_ _survvar_ factor; | |
drop _bylvl_ _set_; | |
run; | |
proc datasets nolist nodetails; | |
%if &debug=0 %then %do; | |
delete %do k = 1 %to %sysfunc(countw(&_cenlist,%str( ))); | |
_surv_stat1_&k _surv_stat1a_&k _surv_stat2_&k _surv_stat2a_&k _surv_stat3_&k _surv_stat3a_&k _surv_stat4_&k _surv_p1_&k _surv_p2_&k | |
_surv_stat1m_&k _surv_stat2m_&k _surv_stat3m_&k | |
%end;; | |
%end; | |
quit; | |
%end; | |
/*Distributions and p-values for logistic variables*/ | |
%if &_nlogvars_>0 %then %do; | |
data _log; | |
set _combined; | |
array _log_ {&_nlogvars_} $300.; | |
array _ev_vl {&_nlogvars_} $300. (%do j = 1 %to &_nlogvars_; %if &j>1 %then %do; , %end; "%superq(_log_event&j)" %end;); | |
do i = 1 to dim(_log_); | |
if scan("&_logpvals_",i,' ') in('3') then exact=1; | |
else exact=0; | |
if _bylvl_=0 then _by_="*M*"; | |
_logvar_=i; | |
_event_=ifn(_log_(i)=_ev_vl(i),1,0); | |
if &nby>1 and _bylvl_^=.m then do; | |
_set_=1; | |
output; | |
end; | |
else if _bylvl_=.m then do; | |
_set_=2; | |
output; | |
end; | |
end; | |
do i = 1 to dim(_log_); | |
if scan("&_logpvals_",i,' ') in('3') then exact=1; | |
else exact=0; | |
_logvar_=i; | |
_logvar_=i; | |
_event_=ifn(_log_(i)=_ev_vl(i),1,0); | |
_bylvl_=.; | |
_by_=''; | |
_set_=3; | |
output; | |
end; | |
drop i _log_: _ev_vl:; | |
run; | |
%local _lexact; | |
proc sql noprint; | |
select max(exact) into :_lexact separated by '' | |
from _log; | |
quit; | |
proc sort data=_log; | |
by _colbylvl_ _rowbylvl_ _logvar_ _set_ _bylvl_; | |
run; | |
/*Counts/Events*/ | |
proc freq data=_log noprint; | |
by _colbylvl_ _rowbylvl_ _logvar_ _set_ _bylvl_; | |
table _event_ / bin(level='1'); | |
output out=_log_stat2 binomial; | |
weight _freq_ / zeros; | |
run; | |
/*P-values*/ | |
%if &nby>1 %then %do; | |
proc freq data=_log noprint; | |
by _colbylvl_ _rowbylvl_ _logvar_ _set_ ; | |
table _bylvl_*_event_ / chisq nowarn %if &_lexact=1 %then %do; fisher %end;; | |
output out=_log_p3 chisq %if &_lexact=1 %then %do; fisher %end;; | |
weight _freq_ / zeros; | |
run; | |
%end; | |
/*Odds Ratios / P-values*/ | |
%if &_log=1 %then %do; | |
%if &_rtf=1 %then %do; | |
ODS RTF EXCLUDE ALL; | |
%end; | |
proc logistic data=_log simple; | |
by _colbylvl_ _rowbylvl_ _logvar_ _set_; | |
freq _freq_; | |
class _bylvl_ %if %sysevalf(%superq(reference)^=,boolean) %then %do; (ref="&_refval") %end;; | |
model _event_(event='1') = _bylvl_ / clodds=wald; | |
ods output parameterestimates=_log_p1 /*Covariate level p-values*/ | |
cloddswald=_log_stat1 /*Odds ratios + CI*/ | |
%if %sysevalf(9.04.01M2P072314 > &sysvlong,boolean) %then %do;/*Type 3 P-values*/ | |
type3=_log_p2 | |
%end; | |
%else %do; | |
modelanova=_log_p2 | |
%end;; | |
where _set_=1; | |
run; | |
%end; | |
%else %if &nby=1 %then %do; | |
data _log_p1; | |
do r=1 to &nrowby; | |
do c=1 to &ncolby; | |
_rowbylvl_=r;_colbylvl_=c;output; | |
end; | |
end; | |
run; | |
%end; | |
proc sql noprint; | |
create table _log_stat as | |
select a._colbylvl_,a._rowbylvl_,a._logvar_,a._set_, | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
a._bylvl_, | |
%end; | |
%else %do; | |
. as _bylvl_, | |
%end; | |
strip(put(a.n,12.0)) as n,strip(put(a.n*_bin_,12.0)) as events,strip(put(a.n*_bin_,12.0))||'/'||strip(put(a.n,12.0)) as events_n, | |
case (a._logvar_) | |
%do i = 1 %to &_nlogvars_; | |
when &i then | |
strip(strip(put(a._bin_*ifn(upcase("&log_binfmt")='PPT',1,100),12.%scan(&bindigits.,&i,|)))||ifc(upcase("&log_binfmt")='PPT',' (','% (')|| | |
%if %sysevalf(%qupcase(%superq(log_conftype))=BIN,boolean) %then %do; | |
strip(put(a.l_bin*ifn(upcase("&log_binfmt")='PPT',1,100),12.%scan(&bindigits.,&i,|)))||'^_'||'-'||'^_'|| | |
strip(put(a.u_bin*ifn(upcase("&log_binfmt")='PPT',1,100),12.%scan(&bindigits.,&i,|)))||ifc(upcase("&log_binfmt")='PPT',')','%)') | |
%end; | |
%else %do; | |
strip(put(a.xl_bin*ifn(upcase("&log_binfmt")='PPT',1,100),12.%scan(&bindigits.,&i,|)))||'^_'||'-'||'^_'|| | |
strip(put(a.xu_bin*ifn(upcase("&log_binfmt")='PPT',1,100),12.%scan(&bindigits.,&i,|)))||ifc(upcase("&log_binfmt")='PPT',')','%)') | |
%end;) | |
%end; else '' end as BINRATE | |
%if &_log =1 %then %do; | |
,case (a._logvar_) | |
%do i = 1 %to &_nlogvars_; | |
when &i then | |
ifc(a._set_=1 and missing(b.oddsratioest),'Reference', | |
ifc(a._set_ in(2 3),'',strip(put(oddsratioest,12.%scan(&ordigits.,&i,|)))|| ' ('|| | |
strip(put(lowercl,12.%scan(&ordigits.,&i,|)))||'^_'||'-'||'^_'|| | |
strip(put(uppercl,12.%scan(&ordigits.,&i,|)))||')')) | |
%end; else '' end as oddsratio, | |
ifc(a._set_=1 and missing(c.probchisq),'Reference', | |
ifc(a._set_ in(2 3),'',strip(put(c.probchisq,pvalue6.&pvaldigits.)))) as waldpval | |
%end; | |
from (select * from _log_stat2) a | |
%if &_log =1 %then %do; | |
left join _log_stat1 b | |
on a._colbylvl_=b._colbylvl_ and a._rowbylvl_=b._rowbylvl_ and a._logvar_=b._logvar_ and a._bylvl_=input(scan(b.effect,2,' '),12.) | |
left join _log_p1 c | |
on a._colbylvl_=c._colbylvl_ and a._rowbylvl_=c._rowbylvl_ and a._logvar_=c._logvar_ and a._bylvl_=input(c.classval0,12.) | |
%end; | |
order by _colbylvl_,_rowbylvl_,_logvar_,_set_,_bylvl_; | |
quit; | |
data _log_stat2; | |
set _log_stat; | |
length factor n_pct $100.; | |
factor='N';n_pct=n;output; | |
factor='Events';n_pct=events;output; | |
factor='Events/N';n_pct=events_n;output; | |
factor='Event Rate (95% CI)';n_pct=binrate;output; | |
%if &_log=1 %then %do; | |
factor='Odds Ratio (95% CI)';n_pct=oddsratio;output; | |
factor='Wald P-value';n_pct=Waldpval;output; | |
%end; | |
keep _colbylvl_ _rowbylvl_ _logvar_ factor n_pct _bylvl_ _set_; | |
run; | |
proc sort data=_log_stat2; | |
by _colbylvl_ _rowbylvl_ _logvar_ factor; | |
data _log_stat3; | |
merge _log_stat2 (where=(_bylvl_=. and _set_=3) rename=(n_pct=t_npct)) | |
_log_stat2 (where=(_set_=ifn(&by_incmiss=0,2,1) %if &by_incmiss=1 %then %do; and _bylvl_=0 %end;) rename=(n_pct=m_npct)) | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; | |
_log_stat2 (where=(_bylvl_=&j and _set_=1) rename=(n_pct=b&j._npct)) | |
%end;; | |
by _colbylvl_ _rowbylvl_ _logvar_ factor; | |
drop _bylvl_ _set_; | |
run; | |
proc datasets nolist nodetails; | |
%if &debug=0 %then %do; | |
delete _log _log_stat1 _log_stat2; | |
%end; | |
quit; | |
%end; | |
/**Insert statistics into output table**/ | |
%local _numindex _disindex _survindex _logindex k; | |
%let _numindex=0; | |
%let _disindex=0; | |
%let _survindex=0; | |
%let _logindex=0; | |
%local k d; | |
%let k=0;%let d=0; | |
data _tester_; | |
length rowby $100. rowbylvl 8. colby $100. colbylvl indent vartype vartypenum varnum varlevel header meta nby ncolby nrowby ptype 8. | |
title footnote $2000. pfoot $1000. factor $2000. | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; | |
b&j._npct | |
%end; | |
m_npct t_npct $100. pvaln 8. pvalfoot $100. null 8.; | |
array _types_ {5} _temporary_; | |
%do r = 1 %to &nrowby; | |
%do c = 1 %to &ncolby; | |
call missing(of _types_(*)); | |
factor=" "; | |
rowbylvl=&r; | |
rowby=put("%scan(%superq(_rowbylvls),&r,|,m)",$100.); | |
indent=0;vartype=0;varnum=0;header=1;meta=0;varlevel=.r;ptype=.; | |
colbylvl=&c;colby=put("%scan(%superq(_colbylvls),&c,|,m)",$100.); | |
%if %sysevalf(%superq(by)^=,boolean) %then %do b = 1 %to %sysfunc(countw(%superq(_c&c._bylist))); | |
b%scan(%superq(_c&c._bylist),&b)_npct="(N=%superq(r&r._c&c._b%scan(%superq(_c&c._bylist),&b)_n))"; | |
%end; | |
m_npct="(N=%superq(r&r._c&c._miss_n))"; | |
t_npct="(N=%superq(r&r._c&c._n))"; | |
if ^missing(rowby) then output _tester_; | |
header=0; | |
call missing(factor,m_npct,t_npct,pvaln,pvalfoot,null | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; | |
,b&j._npct | |
%end;); | |
%let _logindex=0; | |
%do i = 1 %to %sysfunc(countw(&var,%str( ))); | |
%if %sysevalf(%scan(&type,&i,%str( ))^=2,boolean) %then %do; | |
%if &r=1 and &c=1 %then %do; | |
array _ndisplay_&i._ {&&_ndisplay_&i} $300. ( | |
%do j = 1 %to &&_ndisplay_&i; | |
%if &j>1 %then %do; , %end; | |
"%superq(_display_&i._&j)" | |
%end;); | |
%end; | |
%end; | |
%else %do; | |
%if &r=1 and &c=1 %then %do; | |
array _ndisplay_&i._ {&&_ndisplay_&i} $300. ( | |
%do j = 1 %to &&_ndisplay_&i; | |
%if &j>1 %then %do; , %end; | |
"%superq(_display_&i._&j)" | |
%end;); | |
%end; | |
%end; | |
%end; | |
%do i = 1 %to %sysfunc(countw(&var,%str( ))); | |
%if %scan(&type,&i,%str( ))=2 %then %let _disindex=%sysevalf(&_disindex+1); | |
%if %scan(&type,&i,%str( ))=5 %then %let _logindex=%sysevalf(&_logindex+1); | |
%if %sysevalf(%qscan(%superq(labels),&i,|,m)=,boolean) and %scan(&type,&i,%str( ))=5 %then %do; | |
factor="%superq(label&i) (Event=%superq(_log_event&_logindex))"; | |
%if &force_multiple_rows=0 and &show_label_statistic=1 %then %do; | |
if dim(_ndisplay_&i._)=1 then factor=strip(factor)||', '||strip(_ndisplay_&i._(1)); | |
%end; | |
%end; | |
%else %do; | |
factor="%superq(label&i)"; | |
%if &force_multiple_rows=0 and &show_label_statistic=1 %then %do; | |
if %scan(&type,&i,%str( ))^=2 and dim(_ndisplay_&i._)=1 then factor=strip(factor)||', '||strip(_ndisplay_&i._(1)); | |
%if %scan(&type,&i,%str( ))=2 %then %do; | |
else if %scan(&type,&i,%str( ))=2 and dim(_ndisplay_&i._)<=2 and | |
%sysfunc(countw(%scan(%superq(dis_order),&_disindex,|,m),%str( )))=1 and %sysfunc(find(%scan(%superq(dis_order),&_disindex,|,m),freq,i))=0 then | |
factor=strip(factor)|| ' ('||strip(_ndisplay_&i._(1))||')'; | |
%end; | |
%end; | |
%end; | |
varlevel=.l;varnum=&i;ptype=%scan(&pvals,&i,%str( ));vartype=%scan(&type,&i,%str( ));indent=0; | |
_types_(ifn(vartype in(1 3),1,vartype))+1;vartypenum=_types_(ifn(vartype in(1 3),1,vartype)); | |
output _tester_; | |
ptype=.;indent=1; | |
%if %sysevalf(%scan(&type,&i,%str( ))^=2,boolean) %then %do; | |
do i = 1 to dim(_ndisplay_&i._); | |
factor=_ndisplay_&i._(i);varlevel=i; | |
if ^(&nby=1 and ((vartype=4 and _ndisplay_&i._(i) in('Hazard Ratio (95% CI)' 'Wald P-value')) or | |
(vartype=5 and _ndisplay_&i._(i) in('Odds Ratio (95% CI)' 'Wald P-value')))) | |
%if &force_multiple_rows=0 %then %do; and ^(vartype in(1 3 4 5) and dim(_ndisplay_&i._)=1) %end; then output _tester_; | |
end; | |
drop i _ndisplay_&i._:; | |
%end; | |
%else %if %sysevalf(%scan(&type,&i,%str( ))=2,boolean) %then %do; | |
do i = 1 to dim(_ndisplay_&i._); | |
factor=_ndisplay_&i._(i); | |
if i = 1 and upcase("&dis_missorder")='FIRST' then varlevel=0.5; | |
else if i=dim(_ndisplay_&i._) and upcase("&dis_missorder")='LAST' then varlevel=i-0.5; | |
else if upcase("&dis_missorder")='FIRST' then varlevel=i-1; | |
else varlevel=i; | |
output _tester_; | |
end; | |
drop i _ndisplay_&i._:; | |
%end; | |
%end; | |
call missing(rowby,rowbylvl,colby,colbylvl,indent,vartype,varnum,varlevel,header, | |
meta,nby,ncolby,nrowby,title,footnote,pfoot,factor,m_npct,t_npct,pvaln,pvalfoot,null | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; | |
,b&j._npct | |
%end;); | |
%end; | |
%end; | |
run; | |
%do i = 1 %to &_nnumvars_; | |
%if %scan(%superq(_numtype_),&i,%str( ))=1 and %sysfunc(countw(%scan(%superq(contdisplay),&i,|,m),%str( )))=1 %then %do; | |
%local contfactor&i; | |
%if %sysevalf(%qupcase(%scan(%superq(contdisplay),&i,|,m))=N) %then %let contfactor&i=N; | |
%else %if %sysevalf(%qupcase(%scan(%superq(contdisplay),&i,|,m))=NMISS) %then %let contfactor&i=Missing; | |
%else %if %sysevalf(%qupcase(%scan(%superq(contdisplay),&i,|,m))=N_NMISS) %then %let contfactor&i=N (Missing); | |
%else %if %sysevalf(%qupcase(%scan(%superq(contdisplay),&i,|,m))=MEAN) %then %let contfactor&i=Mean; | |
%else %if %sysevalf(%qupcase(%scan(%superq(contdisplay),&i,|,m))=SD) %then %let contfactor&i=SD; | |
%else %if %sysevalf(%qupcase(%scan(%superq(contdisplay),&i,|,m))=MEAN_SD) %then %let contfactor&i=Mean (SD); | |
%else %if %sysevalf(%qupcase(%scan(%superq(contdisplay),&i,|,m))=MEDIAN) %then %let contfactor&i=Median; | |
%else %if %sysevalf(%qupcase(%scan(%superq(contdisplay),&i,|,m))=RANGE) %then %let contfactor&i=Range; | |
%else %if %sysevalf(%qupcase(%scan(%superq(contdisplay),&i,|,m))=IQR) %then %let contfactor&i=IQR; | |
%else %if %sysevalf(%qupcase(%scan(%superq(contdisplay),&i,|,m))=MEDIAN_RANGE) %then %let contfactor&i=Median (Range); | |
%else %if %sysevalf(%qupcase(%scan(%superq(contdisplay),&i,|,m))=MEDIAN_IQR) %then %let contfactor&i=Median (IQR); | |
%end; | |
%else %if %scan(%superq(_numtype_),&i,%str( ))=3 and %sysfunc(countw(%scan(%superq(datedisplay),&i,|,m),%str( )))=1 %then %do; | |
%local datefactor&i; | |
%if %sysevalf(%qupcase(%scan(%superq(datedisplay),&i,|,m))=N) %then %let datefactor&i=N; | |
%else %if %sysevalf(%qupcase(%scan(%superq(datedisplay),&i,|,m))=NMISS) %then %let datefactor&i=Missing; | |
%else %if %sysevalf(%qupcase(%scan(%superq(datedisplay),&i,|,m))=N_NMISS) %then %let datefactor&i=N (Missing); | |
%else %if %sysevalf(%qupcase(%scan(%superq(datedisplay),&i,|,m))=MEAN) %then %let datefactor&i=Mean; | |
%else %if %sysevalf(%qupcase(%scan(%superq(datedisplay),&i,|,m))=SD) %then %let datefactor&i=SD; | |
%else %if %sysevalf(%qupcase(%scan(%superq(datedisplay),&i,|,m))=MEAN_SD) %then %let datefactor&i=Mean (SD); | |
%else %if %sysevalf(%qupcase(%scan(%superq(datedisplay),&i,|,m))=MEDIAN) %then %let datefactor&i=Median; | |
%else %if %sysevalf(%qupcase(%scan(%superq(datedisplay),&i,|,m))=RANGE) %then %let datefactor&i=Range; | |
%else %if %sysevalf(%qupcase(%scan(%superq(datedisplay),&i,|,m))=IQR) %then %let datefactor&i=IQR; | |
%else %if %sysevalf(%qupcase(%scan(%superq(datedisplay),&i,|,m))=MEDIAN_RANGE) %then %let datefactor&i=Median (Range); | |
%else %if %sysevalf(%qupcase(%scan(%superq(datedisplay),&i,|,m))=MEDIAN_IQR) %then %let datefactor&i=Median (IQR); | |
%end; | |
%end; | |
%do i = 1 %to &_nsurvvars_; | |
%if %sysfunc(countw(%scan(%superq(survdisplay),&i,|,m),%str( )))=1 and %sysevalf(%qupcase(%scan(%superq(survdisplay),&i,|,m))^=TIMELIST,boolean) %then %do; | |
%local survfactor&i; | |
%if %sysevalf(%qupcase(%scan(%superq(survdisplay),&i,|,m))=N) %then %let survfactor&i=N; | |
%else %if %sysevalf(%qupcase(%scan(%superq(survdisplay),&i,|,m))=EVENTS) %then %let survfactor&i=Events; | |
%else %if %sysevalf(%qupcase(%scan(%superq(survdisplay),&i,|,m))=EVENTS_N) %then %let survfactor&i=Events/N; | |
%else %if %sysevalf(%qupcase(%scan(%superq(survdisplay),&i,|,m))=MEDIAN) %then %let survfactor&i=Median (95% CI); | |
%else %if %sysevalf(%qupcase(%scan(%superq(survdisplay),&i,|,m))=HR) %then %let survfactor&i=Hazard Ratio (95% CI); | |
%else %if %sysevalf(%qupcase(%scan(%superq(survdisplay),&i,|,m))=COXPVAL) %then %let survfactor&i=Wald P-value; | |
%end; | |
%end; | |
%do i = 1 %to &_nlogvars_; | |
%if %sysfunc(countw(%scan(%superq(log_display),&i,|,m),%str( )))=1 %then %do; | |
%local logfactor&i; | |
%if %sysevalf(%qupcase(%scan(%superq(log_display),&i,|,m))=N) %then %let logfactor&i=N; | |
%else %if %sysevalf(%qupcase(%scan(%superq(log_display),&i,|,m))=EVENTS) %then %let logfactor&i=Events; | |
%else %if %sysevalf(%qupcase(%scan(%superq(log_display),&i,|,m))=EVENTS_N) %then %let logfactor&i=Events/N; | |
%else %if %sysevalf(%qupcase(%scan(%superq(log_display),&i,|,m))=BINRATE) %then %let logfactor&i=Event Rate (95% CI); | |
%else %if %sysevalf(%qupcase(%scan(%superq(log_display),&i,|,m))=ODDSRATIO) %then %let logfactor&i=Odds Ratio (95% CI); | |
%else %if %sysevalf(%qupcase(%scan(%superq(log_display),&i,|,m))=WALDPVAL) %then %let logfactor&i=Wald P-value; | |
%end; | |
%end; | |
%local nby_num_nomiss; | |
proc sql noprint; | |
create table _out as | |
%if %sysevalf(%superq(rowby)^=,boolean) %then %do; | |
select * from _tester_ where header=1 | |
outer union corr | |
%end; | |
%if &_nnumvars_>0 %then %do; | |
select a.*, | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; b&j._npct, %end; | |
m_npct, t_npct | |
%if %sysevalf(%superq(nby)>1,boolean) and &nby_num_nomiss>1 %then %do; | |
, case(a.ptype) | |
when -99 then . | |
%if &_nobs >&nby %then %do; | |
when 1 then p1.p_kw | |
%if &nby=2 and (&_nbymiss=0 or &by_incmiss=0) %then %do; | |
when 3 then p1.p2_wil | |
%end; | |
%if &_nexact=1 %then %do; | |
when 2 then p1e.p_kw | |
%if &nby=2 and &_nbymiss=0 %then %do; | |
when 4 then p1e.p2_wil | |
%end; | |
%end; | |
when 5 then p1.p_f | |
%end; | |
%if &nby =2 and &_nttest=1 %then %do; | |
when 6 then p2a.probt | |
when 7 then p2b.probt | |
%end; | |
else . end as pvaln | |
, put(case(a.ptype) | |
when 1 then 'KW' | |
when 2 then 'EKW' | |
when 3 then 'W' | |
when 4 then 'EW' | |
when 5 then 'ANOVA' | |
when 6 then 'TE' | |
when 7 then 'TU' | |
else '' end,$100.) as pvalfoot | |
%end; | |
%else %if %sysevalf(%superq(by)=,boolean) or &nby=1 %then %do; | |
, case(a.ptype) | |
when 1 then p3.probt | |
when 2 then p3.probs | |
else . end as pvaln | |
, put(case(a.ptype) | |
when 1 then 'ST' | |
when 2 then 'SR' | |
else '' end,$100.) as pvalfoot | |
%end; | |
from (select *, | |
case | |
%do i = 1 %to &_nnumvars_; | |
when vartypenum=&i then | |
%if &force_multiple_rows=0 and %scan(%superq(_numtype_),&i,%str( ))=1 and %sysfunc(countw(%scan(%superq(contdisplay),&i,|,m),%str( )))=1 %then %do; "&&contfactor&i" %end; | |
%else %if &force_multiple_rows=0 and %scan(%superq(_numtype_),&i,%str( ))=3 and %sysfunc(countw(%scan(%superq(datedisplay),&i,|,m),%str( )))=1 %then %do; "&&datefactor&i" %end; | |
%else %do; factor %end; | |
%end; else '' end as _factor | |
from _tester_ (where=(varnum>0 and vartype in(1 3)) drop=%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; b&j._npct %end; m_npct t_npct pvaln pvalfoot null)) a | |
left join _num_stat3 b | |
on a.colbylvl=b._colbylvl_ and a.rowbylvl=b._rowbylvl_ and a.vartypenum=b._numvar_ and a._factor=b.factor | |
%if %sysevalf(%superq(nby)>1,boolean) and &nby_num_nomiss>1 %then %do; | |
left join _num_p1 as p1 on a.colbylvl=p1._colbylvl_ and a.rowbylvl=p1._rowbylvl_ and a.vartypenum=p1._numvar_ | |
%if &_nexact=1 %then %do; | |
left join _num_p1e as p1e on a.colbylvl=p1e._colbylvl_ and a.rowbylvl=p1e._rowbylvl_ and a.vartypenum=p1e._numvar_ | |
%end; | |
%if &nby =2 and &_nttest=1 %then %do; | |
left join (select * from _num_p2 where variances='Equal') as p2a on a.colbylvl=p2a._colbylvl_ and a.rowbylvl=p2a._rowbylvl_ and a.vartypenum=p2a._numvar_ | |
left join (select * from _num_p2 where variances='Unequal') as p2b on a.colbylvl=p2b._colbylvl_ and a.rowbylvl=p2b._rowbylvl_ and a.vartypenum=p2b._numvar_ | |
%end; | |
%end; | |
%else %if %sysevalf(%superq(by)=,boolean) or &nby=1 %then %do; | |
left join _num_p3 as p3 on a.colbylvl=p3._colbylvl_ and a.rowbylvl=p3._rowbylvl_ and a.vartypenum=p3._numvar_ | |
%end; | |
%if &_ndisvars_>0 or &_nsurvvars_>0 or &_nlogvars_>0 %then %do; | |
OUTER UNION CORR | |
%end; | |
%end; | |
%if &_ndisvars_>0 %then %do; | |
select a.*, | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; b.b&j._npct, %end; | |
b.m_npct, b.t_npct | |
%if %sysevalf(%superq(nby)>1,boolean) and &_dmaxn>1 %then %do; | |
, case(a.ptype) | |
when 1 then p1.p_pchi | |
%if &_dexact=1 %then %do; | |
when 2 then p2.xp2_fish | |
%end; | |
%if &_dtrend=1 %then %do; | |
when 3 then p3.p2_trend | |
%end; | |
else . end as pvaln | |
, put(case(a.ptype) | |
when 1 then 'C' | |
%if &_dexact=1 %then %do; | |
when 2 then 'F' | |
%end; | |
%if &_dtrend=1 %then %do; | |
when 3 then 'CAT' | |
%end; | |
else '' end,$100.) as pvalfoot | |
%end; | |
from (select *, | |
case | |
%do i = 1 %to &_ndisvars_; | |
when vartypenum=&i and varlevel=.l then | |
%if &force_multiple_rows=0 and %sysfunc(countw(%scan(%superq(dis_order),&i,|,m),%str( )))=1 and %sysfunc(find(%scan(%superq(dis_order),&i,|,m),freq,i))=0 %then %do; 1 %end; | |
%else %do; varlevel %end; | |
when vartypenum=&i then | |
%if &force_multiple_rows=0 and %sysfunc(countw(%scan(%superq(dis_order),&i,|,m),%str( )))=1 and %sysfunc(find(%scan(%superq(dis_order),&i,|,m),freq,i))=0 %then %do; .e %end; | |
%else %do; varlevel %end; | |
%end; else . end as _varlevel | |
from _tester_ (where=(varnum>0 and vartype in(2)) drop=%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; b&j._npct %end; m_npct t_npct pvaln pvalfoot null) | |
having _varlevel^=.e) a | |
left join _dis_stat3 b | |
on a.colbylvl=b._colbylvl_ and a.rowbylvl=b._rowbylvl_ and a.vartypenum=b._disvar_ and | |
ifn(a._varlevel^=int(a._varlevel) and a._varlevel>0,.m,a._varlevel)=ifn(b._dislvl_ in(.m 0),.m,b._dislvl_) | |
%if %sysevalf(%superq(nby)>1,boolean) and &_dmaxn>1 %then %do; | |
left join _dis_p1 as p1 on a.colbylvl=p1._colbylvl_ and a.rowbylvl=p1._rowbylvl_ and a.vartypenum=p1._disvar_ | |
%if &_dexact=1 %then %do; | |
left join _dis_p2 as p2 on a.colbylvl=p2._colbylvl_ and a.rowbylvl=p2._rowbylvl_ and a.vartypenum=p2._disvar_ | |
%end; | |
%if &_dtrend=1 %then %do; | |
left join _dis_p3 as p3 on a.colbylvl=p3._colbylvl_ and a.rowbylvl=p3._rowbylvl_ and a.vartypenum=p3._disvar_ | |
%end; | |
%end; | |
%if &_nsurvvars_>0 or &_nlogvars_>0 %then %do; | |
OUTER UNION CORR | |
%end; | |
%end; | |
%if &_nsurvvars_>0 %then %do; | |
select a.*, | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; b.b&j._npct, %end; | |
b.m_npct, b.t_npct | |
%if %sysevalf(%superq(nby)>1,boolean) %then %do; | |
, case(a.ptype) | |
when 1 then p1.probchisq | |
when 2 then p1b.probchisq | |
%if &_cox=1 %then %do; | |
when 3 then p2.probscorechisq | |
when 4 then p2.problrchisq | |
when 5 then p2.probchisq | |
%end; | |
else . end as pvaln | |
, put(case(a.ptype) | |
when 1 then 'Logrank' | |
when 2 then 'Wilcoxon' | |
when 3 then 'Score' | |
when 4 then 'lr' | |
when 5 then 'Wald' | |
else '' end,$100.) as pvalfoot | |
%end; | |
from (select *, | |
case | |
%do i = 1 %to &_nsurvvars_; | |
when vartypenum=&i then | |
%if &force_multiple_rows=0 and %sysfunc(countw(%scan(%superq(survdisplay),&i,|,m),%str( )))=1 %then %do; "&&survfactor&i" %end; | |
%else %do; factor %end; | |
%end; else '' end as _factor from _tester_ (where=(varnum>0 and vartype in(4)) drop=%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; b&j._npct %end; m_npct t_npct pvaln pvalfoot null)) a | |
left join _surv_stat_4 b | |
on a.colbylvl=b._colbylvl_ and a.rowbylvl=b._rowbylvl_ and a.vartypenum=b._survvar_ and a._factor=b.factor | |
%if %sysevalf(%superq(nby)>1,boolean) %then %do; | |
left join (select * from _surv_p1 where upcase(test)^="WILCOXON") as p1 on a.colbylvl=p1._colbylvl_ and a.rowbylvl=p1._rowbylvl_ and a.vartypenum=p1._survvar_ | |
left join (select * from _surv_p1 where upcase(test)="WILCOXON") as p1b on a.colbylvl=p1b._colbylvl_ and a.rowbylvl=p1b._rowbylvl_ and a.vartypenum=p1b._survvar_ | |
%if &_cox=1 %then %do; | |
left join _surv_p2 as p2 on a.colbylvl=p2._colbylvl_ and a.rowbylvl=p2._rowbylvl_ and a.vartypenum=p2._survvar_ | |
%end; | |
%end; | |
%if &_nlogvars_>0 %then %do; | |
OUTER UNION CORR | |
%end; | |
%end; | |
%if &_nlogvars_>0 %then %do; | |
select a.*, | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; b.b&j._npct, %end; | |
b.m_npct, b.t_npct | |
%if %sysevalf(%superq(nby)>1,boolean) %then %do; | |
, case(a.ptype) | |
%if &_log=1 %then %do; | |
when 1 then p2.probchisq | |
when 2 then p3.p_pchi | |
%if &_lexact=1 %then %do; | |
when 3 then p3.xp2_fish | |
%end; | |
%end; | |
%else %do; | |
when 1 then p3.p_pchi | |
%if &_lexact=1 %then %do; | |
when 2 then p3.xp2_fish | |
%end; | |
%end; | |
else . end as pvaln | |
, put(case(a.ptype) | |
%if &_log=1 %then %do; | |
when 1 then 'Wald' | |
when 2 then 'C' | |
when 3 then 'F' | |
%end; | |
%else %do; | |
when 1 then 'C' | |
when 2 then 'F' | |
%end; | |
else '' end,$100.) as pvalfoot | |
%end; | |
from | |
(select *, | |
case | |
%do i = 1 %to &_nlogvars_; | |
when vartypenum=&i then | |
%if &force_multiple_rows=0 and %sysfunc(countw(%scan(%superq(log_display),&i,|,m),%str( )))=1 %then %do; "&&logfactor&i" %end; | |
%else %do; factor %end; | |
%end; else '' end as _factor from _tester_ (where=(varnum>0 and vartype in(5)) drop=%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby; b&j._npct %end; m_npct t_npct pvaln pvalfoot null)) a | |
left join _log_stat3 b | |
on a.colbylvl=b._colbylvl_ and a.rowbylvl=b._rowbylvl_ and a.vartypenum=b._logvar_ and a._factor=b.factor | |
%if %sysevalf(%superq(nby)>1,boolean) %then %do; | |
left join _log_p3 as p3 on a.colbylvl=p3._colbylvl_ and a.rowbylvl=p3._rowbylvl_ and a.vartypenum=p3._logvar_ | |
%if &_log=1 %then %do; | |
left join _log_p2 as p2 on a.colbylvl=p2._colbylvl_ and a.rowbylvl=p2._rowbylvl_ and a.vartypenum=p2._logvar_ | |
%end; | |
%end; | |
%end; | |
order by rowbylvl,colbylvl,varnum,varlevel; | |
quit; | |
%do i = 1 %to 20; | |
%local pfoot&i; | |
%end; | |
%local pfoot; | |
%do c = 1 %to &ncolby; | |
%do b = 1 %to &nby; | |
%local c&c._b&b._switch; | |
%end; | |
%local c&c._m_switch c&c._t_switch; | |
%end; | |
%let npfoot=0; | |
proc sort data=_out; | |
by rowbylvl varnum varlevel colbylvl; | |
run; | |
data _out; | |
set _out end=last; | |
by rowbylvl varnum varlevel colbylvl; | |
length factor_listing $2000.; | |
%if %sysevalf(%superq(by)^=,boolean) %then %do b = 1 %to &nby; | |
array _b&b._npct {&ncolby} $100. %do c = 1 %to &ncolby; c&c._b&b._npct %end;; | |
%end; | |
array colby_ {&ncolby} $100.; | |
array _m_npct {&ncolby} $100. %do c = 1 %to &ncolby; c&c._m_npct %end;; | |
array _t_npct {&ncolby} $100. %do c = 1 %to &ncolby; c&c._t_npct %end;; | |
array plist (20) $20. _temporary_; | |
array pvars (&ncolby) $100. %do i=1 %to &ncolby; c&i._pval %end;; | |
array pvars_l (&ncolby) $100. %do i=1 %to &ncolby; c&i._pval_listing %end;; | |
array ntotals (&ncolby) _temporary_; | |
if first.varnum then call missing(of ntotals(*)); | |
retain %if %sysevalf(%superq(by)^=,boolean) %then %do b = 1 %to &nby;_b&b._npct %end; | |
_m_npct _t_npct pvars pvars_l colby_; | |
if first.varlevel then | |
call missing(%if %sysevalf(%superq(by)^=,boolean) %then %do b = 1 %to &nby; of _b&b._npct(*), %end; | |
of _m_npct(*),of _t_npct(*),of pvars(*),of pvars_l(*)); | |
%if %sysevalf(%superq(by)^=,boolean) %then %do b = 1 %to &nby; | |
_b&b._npct(colbylvl)=b&b._npct; | |
%end; | |
colby_(colbylvl)=colby; | |
_m_npct(colbylvl)=m_npct; | |
_t_npct(colbylvl)=t_npct; | |
if vartype=2 and varlevel=.l then do; | |
if indent>0 then factor_listing=repeat('A0A0'x,indent-1)||strip(Factor)||"%superq(dis_suffix_listing)"; | |
else factor_listing=strip(factor)||"%superq(dis_suffix_listing)"; | |
factor=strip(factor)||"%superq(dis_suffix)"; | |
end; | |
/*else if vartype=2 and int(varlevel)=varlevel and missing(_b&b._npct(colbylvl)) then do; | |
if indent>0 then factor_listing=repeat('A0A0'x,indent-1)||strip(Factor); | |
else factor_listing=strip(factor); | |
_b&b._npct(colbylvl) | |
end;*/ | |
else do; | |
if indent>0 then factor_listing=repeat('A0A0'x,indent-1)||strip(Factor); | |
else factor_listing=strip(factor); | |
end; | |
if vartype=2 and ^missing(t_npct) then ntotals(colbylvl)=input(scan(scan(compress(t_npct,'%'),1,'/'),1,' '),12.); | |
if ^missing(pvaln) then do; | |
if &pfoot then do; | |
if ^missing(pvalfoot) then do j = 1 to dim(plist); | |
if missing(plist(j)) or pvalfoot = plist(j) then do; | |
if missing(plist(j)) then plist(j)=pvalfoot; | |
pvars(colbylvl)=strip(put(pvaln,pvalue6.&pvaldigits))||'^{super '||strip(put(j,12.0))||'}'; | |
pvars_l(colbylvl)=strip(put(pvaln,pvalue6.&pvaldigits))||repeat('*',j-1); | |
j=dim(plist); | |
end; | |
end; | |
end; | |
else do; | |
pvars(colbylvl)=strip(put(pvaln,pvalue6.&pvaldigits)); | |
pvars_l(colbylvl)=strip(put(pvaln,pvalue6.&pvaldigits)); | |
end; | |
end; | |
if last.varlevel then do; | |
if vartype=2 and nmiss(of ntotals(*)) < dim(ntotals) then do; | |
/*If No missing and dis_printmiss ^=2 then should delete | |
If dis_incmiss=1 and No missing then delete | |
If dis_printmiss=0 and dis_incmiss=1 and No missing then delete*/ | |
if &dis_printmiss^=2 then do; | |
if sum(of ntotals(*))=0 and varlevel^=.l and int(varlevel)^=varlevel then del=1; | |
else if sum(of ntotals(*))>0 and &dis_printmiss=0 and &dis_incmiss=0 and varlevel^=.l and int(varlevel)^=varlevel then del=1; | |
else if sum(of ntotals(*))>0 and &dis_printmiss=3 and &dis_incmiss=0 and varlevel^=.l and int(varlevel)^=varlevel and upcase("&DIS_DISPLAY")='N_PCT' then del=1; | |
else output; | |
end; | |
else output; | |
end; | |
else output; | |
%if %sysevalf(%qupcase(%superq(split))=SPACE,boolean) %then %do; | |
call missing(factor,factor_listing, | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby;of _b&j._npct(*), %end; | |
of _m_npct(*),of _t_npct(*),of pvars(*),of pvars_l(*)); | |
if ^last and varlevel^=.r and last.varnum and missing(rowby) then output; | |
%end; | |
end; | |
if last then do; | |
do i = 1 to dim(plist)-cmiss(of plist(*)); | |
call symput('pfoot'||strip(put(i,12.0)),strip(plist(i))); | |
end; | |
call symput('npfoot',strip(put(dim(plist)-cmiss(of plist(*)),12.0))); | |
/*Meta-data for table*/ | |
call missing(factor,factor_listing,rowby, | |
%if %sysevalf(%superq(by)^=,boolean) %then %do j = 1 %to &nby;of _b&j._npct(*), %end; | |
of _m_npct(*),of _t_npct(*),of pvars(*),of pvars_l(*)); | |
rowbyvar="&rowby";rowbylabel="%superq(rowbylabel)";rowbylvl=0;varnum=0;meta=1; | |
byvar="&by";byvarlabel="&bylabel";nby=&nby;colbyvar="&colby";colbylabel="&colbylabel";ncolby=&ncolby;nrowby=&nrowby; | |
varlevel=0;indent=.;vartype=.; | |
title=strip("&title");footnote="&footnote"; | |
%local _b; | |
%do c = 1 %to &ncolby; | |
%if %sysevalf(%superq(by)^=,boolean) %then %do b = 1 %to %sysfunc(countw(%superq(_c&c._bylist))) /*&nby*/; | |
%let _b=%scan(%superq(_c&c._bylist),&b); | |
c&c._b&_b._npct=ifc(max(%do r = 1 %to &nrowby; %superq(r&r._c&c._b&_b._n), %end; 0)>0, | |
%if %sysevalf(%superq(rowby)=,boolean) %then %do; | |
"%qscan(%superq(_bylvls),&_b,|,m)~(N=%superq(r1_c&c._b&_b._n))",''); | |
%end; | |
%else %do; | |
"%qscan(%superq(_bylvls),&_b,|,m)",''); | |
%end; | |
call symput("c&c._b&_b._switch",strip(put(^missing(c&c._b&_b._npct),12.0))); | |
%end; | |
c&c._m_npct=ifc(max(%do r = 1 %to &nrowby; %superq(r&r._c&c._miss_n), %end; 0)>0, | |
%if %sysevalf(%superq(rowby)=,boolean) %then %do; | |
"Missing~(N=%superq(r1_c&c._miss_n))" ,''); | |
%end; | |
%else %do; | |
"Missing" ,''); | |
%end; | |
call symput("c&c._m_switch",strip(put(^missing(c&c._m_npct),12.0))); | |
c&c._t_npct=ifc(max(%do r = 1 %to &nrowby; %superq(r&r._c&c._n), %end; 0)>0, | |
%if %sysevalf(%superq(rowby)=,boolean) %then %do; | |
"Total~(N=%superq(r1_c&c._n))",''); | |
%end; | |
%else %do; | |
"Total",''); | |
%end; | |
call symput("c&c._t_switch",strip(put(^missing(c&c._t_npct),12.0))); | |
%end; | |
output; | |
end; | |
keep rowby--factor factor_listing rowbyvar rowbylabel colbyvar colbylabel byvar byvarlabel | |
%do c = 1 %to &ncolby; | |
%if %sysevalf(%superq(by)^=,boolean) %then %do b = 1 %to %sysfunc(countw(%superq(_c&c._bylist))); | |
c&c._b%scan(%superq(_c&c._bylist),&b)_npct | |
%end; | |
c&c._m_npct c&c._t_npct c&c._pval c&c._pval_listing colby_: | |
%end;; | |
drop colby colbylvl; | |
run; | |
proc sql noprint; | |
%local pfoot npfoot maxsublength; | |
select max(length(factor)) into :maxsublength separated by '' | |
from _out; | |
alter table _out | |
modify factor char(&maxsublength); | |
/*Meta-data for table*/ | |
update _out | |
set pfoot=catx(' ', | |
%do i = 1 %to &npfoot; | |
%if %sysevalf(%superq(pfoot&i)=KW,boolean) %then %do; | |
"^{super &i}Kruskal-Wallis p-value; ", | |
%end; | |
%else %if %sysevalf(%superq(pfoot&i)=EKW,boolean) %then %do; | |
"^{super &i}Exact Kruskal-Wallis p-value; ", | |
%end; | |
%else %if %sysevalf(%superq(pfoot&i)=W,boolean) %then %do; | |
"^{super &i}Wilcoxon rank sum p-value; ", | |
%end; | |
%else %if %sysevalf(%superq(pfoot&i)=EW,boolean) %then %do; | |
"^{super &i}Exact Wilcoxon rank sum p-value; ", | |
%end; | |
%else %if %sysevalf(%superq(pfoot&i)=ANOVA,boolean) %then %do; | |
"^{super &i}ANOVA F-test p-value; ", | |
%end; | |
%else %if %sysevalf(%superq(pfoot&i)=TE,boolean) %then %do; | |
"^{super &i}Equal variance two sample t-test; ", | |
%end; | |
%else %if %sysevalf(%superq(pfoot&i)=TU,boolean) %then %do; | |
"^{super &i}Unequal variance two sample t-test; ", | |
%end; | |
%else %if %sysevalf(%superq(pfoot&i)=ST,boolean) %then %do; | |
"^{super &i}Student T-Test; ", | |
%end; | |
%else %if %sysevalf(%superq(pfoot&i)=SR,boolean) %then %do; | |
"^{super &i}Sign Rank; ", | |
%end; | |
%else %if %sysevalf(%superq(pfoot&i)=C,boolean) %then %do; | |
"^{super &i}Chi-Square p-value; ", | |
%end; | |
%else %if %sysevalf(%superq(pfoot&i)=F,boolean) %then %do; | |
"^{super &i}Fisher Exact p-value; ", | |
%end; | |
%else %if %sysevalf(%superq(pfoot&i)=CAT,boolean) %then %do; | |
"^{super &i}Cochran-Armitage trend test; ", | |
%end; | |
%else %if %sysevalf(%qupcase(%superq(pfoot&i))=LOGRANK,boolean) %then %do; | |
"^{super &i}Logrank p-value; ", | |
%end; | |
%else %if %sysevalf(%qupcase(%superq(pfoot&i))=WILCOXON,boolean) %then %do; | |
"^{super &i}Wilcoxon p-value; ", | |
%end; | |
%else %if %sysevalf(%qupcase(%superq(pfoot&i))=SCORE,boolean) %then %do; | |
"^{super &i}Type-3 score p-value; ", | |
%end; | |
%else %if %sysevalf(%qupcase(%superq(pfoot&i))=LR,boolean) %then %do; | |
"^{super &i}Type-3 likelihood-ratio p-value; ", | |
%end; | |
%else %if %sysevalf(%qupcase(%superq(pfoot&i))=WALD,boolean) %then %do; | |
"^{super &i}Type-3 Wald p-value; ", | |
%end; | |
%end; | |
" ") | |
where meta=1; | |
select pfoot | |
into :pfoot separated by '' | |
from _out where meta=1; | |
quit; | |
%if &_rtf=1 %then %do; | |
ODS RTF SELECT ALL; | |
ODS SELECT NONE; | |
%end; | |
/**Run-time Errors are sent there to delete temporary datasets before being sent to | |
errhandl, which stops the macro**/ | |
%errhandl2: | |
proc datasets nolist nodetails; | |
%if &debug=0 %then %do; | |
delete _num_stat _num_statm _num_stat2 _num_stat3 _dis_stat _dis_stat2 _dis_stat3 _combined _tester_ _numeric _discrete _dis_p1 _dis_p2 _dis_p3 _num_p1 _num_p2 _num_p3 _combined | |
_surv_stat1 _surv_stat1a _surv_stat2 _surv_stat2a _surv_stat3 _surv_stat3a _surv_stat4 _surv_p1 _surv_p2 _survival | |
_surv_stat1m _surv_stat2m _surv_stat3m _surv_stat _surv_stat_tl _surv_stat_2 _surv_stat_3 _surv_stat_4 _surv_stat_tl2 | |
_dis_stat_final _dis_stat_missings | |
_log _log_stat _log_stat2 _log_stat3 _log_p1 _log_p2 _log_p3; | |
%end; | |
quit; | |
/**If errors occurred then throw message and end macro**/ | |
%if &nerror_run > 0 %then %do; | |
%put ERROR: &nerror_run run-time errors listed; | |
%put ERROR: Macro TABLEN will cease; | |
%goto errhandl; | |
%end; | |
options orientation=&orientation; | |
ods path WORK.TEMPLAT(UPDATE) SASHELP.TMPLMST (READ); | |
proc template; | |
%if %superq(borderdisplay)=1 %then %do; | |
define style _tablen; | |
parent=styles.rtf; | |
style Table / | |
color=black | |
cellpadding = 0 | |
borderspacing = 0 | |
cellspacing=0 | |
frame = void | |
rules = groups | |
bordercollapse = separate | |
borderleftstyle = none | |
borderrightstyle = none | |
bordertopstyle = none | |
borderbottomstyle = none | |
fontfamily="&font" ; | |
style Header / | |
color=black | |
backgroundcolor = white | |
bordercolor = white | |
borderstyle = none | |
fontfamily="&font" ; | |
style Data / | |
color=black | |
backgroundcolor = white | |
bordercolor = white | |
borderstyle = none | |
fontfamily="&font" ; | |
End; | |
define style _tablenppt; | |
parent=styles.powerpointlight; | |
class Header / | |
background=white | |
fontsize=&headersize | |
color=black | |
fontfamily="&font" | |
fontweight=&headerweight | |
vjust=bottom | |
borderstyle=solid | |
bordercolor=black | |
borderwidth=0.1 ; | |
class Data / | |
background=white | |
fontsize=&datasize | |
color=black | |
fontfamily="&font" | |
fontweight=&dataweight | |
vjust=top | |
borderstyle=hidden; | |
class linecontent / | |
background=white | |
fontsize=&datasize | |
color=black | |
fontfamily="&font" | |
fontweight=&dataweight | |
borderstyle=solid | |
bordercolor=black | |
borderwidth=0.1; | |
class Table / | |
color=black | |
cellpadding=0 | |
borderspacing=0 | |
cellspacing=0 | |
frame=void | |
rules=rows | |
borderstyle=solid | |
bordercolor=black | |
borderwidth=0.1pt; | |
End; | |
%end; | |
%else %if %superq(borderdisplay)=2 %then %do; | |
define style _tablen; | |
parent=styles.rtf; | |
style Table / | |
color=black | |
cellpadding = 0 | |
borderspacing = 0 | |
cellspacing=0 | |
frame = box | |
rules = all | |
bordercollapse = separate | |
borderleftstyle = solid | |
borderrightstyle = solid | |
bordertopstyle = solid | |
borderbottomstyle = solid | |
fontfamily="&font" | |
borderwidth=0.1 | |
bordercolor=black; | |
style Header / | |
color=black | |
backgroundcolor = white | |
bordercolor = white | |
borderstyle = solid | |
borderwidth=0.1 | |
bordercolor=black | |
fontfamily="&font" ; | |
style Data / | |
color=black | |
backgroundcolor = white | |
bordercolor = white | |
borderstyle = solid | |
borderwidth=0.1 | |
bordercolor=black | |
fontfamily="&font" ; | |
End; | |
define style _tablenppt; | |
parent=styles.powerpointlight; | |
class Header / | |
background=white | |
fontsize=&headersize | |
color=black | |
fontfamily="&font" | |
fontweight=&headerweight | |
vjust=bottom | |
borderstyle=solid | |
bordercolor=black | |
borderwidth=0.1 ; | |
class Data / | |
background=white | |
fontsize=&datasize | |
color=black | |
fontfamily="&font" | |
fontweight=&dataweight | |
vjust=top | |
borderstyle=solid | |
bordercolor=black | |
borderwidth=0.1; | |
class linecontent / | |
background=white | |
fontsize=&datasize | |
color=black | |
fontfamily="&font" | |
fontweight=&dataweight | |
borderstyle=solid | |
bordercolor=black | |
borderwidth=0.1; | |
class Table / | |
color=black | |
cellpadding=0 | |
borderspacing=0 | |
cellspacing=0 | |
frame=box | |
rules=all | |
borderstyle=solid | |
bordercolor=black | |
borderwidth=0.1pt; | |
End; | |
%end; | |
%else %if %superq(borderdisplay)=3 or %superq(borderdisplay)=4 %then %do; | |
define style _tablen; | |
parent=styles.rtf; | |
style Table / | |
color=black | |
cellpadding = 0 | |
borderspacing = 0 | |
cellspacing=0 | |
frame = void | |
rules = all | |
bordercollapse = separate | |
borderleftstyle = solid | |
borderrightstyle = solid | |
bordertopstyle = none | |
borderbottomstyle = none | |
fontfamily="&font" | |
borderwidth=0.1 | |
bordercolor=black; | |
style Header / | |
color=black | |
backgroundcolor = white | |
bordercolor = white | |
borderstyle = solid | |
borderwidth=0.1 | |
bordercolor=black | |
bordercollapse = separate | |
borderleftstyle = solid | |
borderrightstyle = solid | |
bordertopstyle = solid | |
borderbottomstyle = solid | |
borderwidth=0.1 | |
bordertopwidth=0.1 | |
borderbottomwidth=0.1 | |
borderleftwidth=0.1 | |
borderrightwidth=0.1 | |
bordercolor=black | |
borderleftcolor=black | |
borderrightcolor=black | |
bordertopcolor=black | |
borderbottomcolor=black | |
fontfamily="&font" ; | |
style Data / | |
color=black | |
backgroundcolor = white | |
bordercolor = white | |
borderstyle = solid | |
bordercollapse = separate | |
borderleftstyle = solid | |
borderrightstyle = solid | |
bordertopstyle = solid | |
borderbottomstyle = solid | |
borderwidth=0.1 | |
bordertopwidth=0.1 | |
borderbottomwidth=0.1 | |
borderleftwidth=0.1 | |
borderrightwidth=0.1 | |
bordercolor=black | |
borderleftcolor=black | |
borderrightcolor=black | |
bordertopcolor=black | |
borderbottomcolor=black | |
fontfamily="&font" ; | |
End; | |
define style _tablenppt; | |
parent=styles.powerpointlight; | |
class Header / | |
background=white | |
fontsize=&headersize | |
color=black | |
fontfamily="&font" | |
fontweight=&headerweight | |
vjust=bottom | |
borderstyle=solid | |
bordercolor=black | |
borderwidth=0.1 ; | |
class Data / | |
background=white | |
fontsize=&datasize | |
color=black | |
fontfamily="&font" | |
fontweight=&dataweight | |
vjust=top | |
borderstyle=solid | |
bordercolor=black | |
borderwidth=0.1; | |
class linecontent / | |
background=white | |
fontsize=&datasize | |
color=black | |
fontfamily="&font" | |
fontweight=&dataweight | |
borderstyle=solid | |
bordercolor=black | |
borderwidth=0.1; | |
class Table / | |
color=black | |
cellpadding=0 | |
borderspacing=0 | |
cellspacing=0 | |
frame=box | |
rules=all | |
borderstyle=solid | |
bordercolor=black | |
borderwidth=0.1pt; | |
End; | |
%end; | |
run; | |
%if %sysevalf(%superq(outdoc)^=,boolean) %then %do; | |
%if %qupcase(&destination)=HTML %then %do; | |
ods &destination style=_tablen | |
%if %upcase(&sysscpl)=LINUX or %upcase(&sysscpl)=UNIX %then %do; | |
path="%substr(&outdoc,1,%sysfunc(find(&outdoc,/,-%sysfunc(length(&outdoc)))))" | |
file="%scan(&outdoc,1,/,b)" | |
%end; | |
%else %do; | |
path="%substr(&outdoc,1,%sysfunc(find(&outdoc,\,-%sysfunc(length(&outdoc)))))" | |
file="%scan(&outdoc,1,\,b)" | |
%end;; | |
%end; | |
%else %do; | |
ods &destination file="&outdoc" style=_tablen; | |
%end; | |
%end; | |
proc sql noprint; | |
%local _listing _ppt _other _html _destinations _styles k pfoot_list _rtf _rtf2; | |
%let _rtf2=_rtf; | |
select max(ifn(upcase(destination)='LISTING',1,0)), | |
max(ifn(upcase(destination) in('HTML'),1,0)), | |
max(ifn(upcase(destination) ^in('LISTING' 'OUTPUT' 'POWERPOINT' 'RTF' 'HTML'),1,0)), | |
max(ifn(upcase(destination) in('POWERPOINT'),1,0)), | |
max(ifn(upcase(destination) in('RTF'),1,0)) | |
into :_listing separated by '',:_html separated by '',:_other separated by '',:_ppt separated by '',:_rtf separated by '' from sashelp.vdest; | |
select upcase(destination),upcase(style) into :_destinations separated by '|',:_styles separated by '|' | |
from sashelp.vdest | |
where upcase(destination)^in('OUTPUT' 'LISTING'); | |
%do i = 1 %to &npfoot; | |
%if &i=1 %then %let pfoot_list=%sysfunc(tranwrd(%qscan(%superq(pfoot),&i,%str(;)),^{super &i},%sysfunc(repeat(*,&i-1)))); | |
%else %let pfoot_list=&pfoot_list%str(;)%sysfunc(tranwrd(%qscan(%superq(pfoot),&i,%str(;)),^{super &i},%sysfunc(repeat(*,&i-1)))); | |
%end; | |
quit; | |
ods results; | |
ods select all; | |
ods escapechar='^'; | |
%if &_listing = 1 %then %do; | |
%do i = 1 %to %sysfunc(countw(%superq(_destinations),|)); | |
ods %scan(%superq(_destinations),&i,|) select none; | |
%end; | |
data _out_listing; | |
set _out (where=(meta^=1)); | |
array _chars_ (*) $2000. _character_; | |
do i = 1 to dim(_chars_); | |
_chars_(i)='A0A0A0'x||strip(_chars_(i)); | |
end; | |
drop factor | |
%do c=1 %to &ncolby; | |
c&c._pval | |
%end;; | |
rename factor_listing=factor | |
%do c=1 %to &ncolby; | |
c&c._pval_listing=c&c._pval | |
%end;; | |
run; | |
proc contents data=_out_listing noprint out=_outldict; | |
run; | |
proc sql noprint; | |
%local _list_cvars; | |
select upcase(name) into :_list_cvars separated by '|' from _outldict where type=2; | |
%do i = 1 %to %sysfunc(countw(%superq(_list_cvars),|,m)); | |
%local _list_%scan(%superq(_list_cvars),&i,|,m); | |
%end; | |
select %do i = 1 %to %sysfunc(countw(%superq(_list_cvars),|,m)); | |
%if &i>1 %then %do; , %end; | |
max(length(strip(%scan(%superq(_list_cvars),&i,|,m)))) | |
%end; | |
into %do i = 1 %to %sysfunc(countw(%superq(_list_cvars),|,m)); | |
%if &i>1 %then %do; , %end; | |
:_list_%scan(%superq(_list_cvars),&i,|,m) separated by '' | |
%end; | |
from _out_listing; | |
%local _list_totlength; | |
%let _list_totlength=0; | |
%do i = 1 %to &ncolby; | |
%local _list_c&i._totlength; | |
%if &i=1 %then %let _list_c&i._totlength=0; | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
%do b = 1 %to %sysfunc(countw(%superq(_c&i._bylist),%str( ))); | |
%let _list_c&i._b%scan(%superq(_c&i._bylist),&b)_npct=%sysfunc(max(%length(%qscan(%superq(_bylvls),%qscan(%superq(_c&i._bylist),&b),|,m))+2, | |
%length((N=%superq(r1_c&i._b%scan(%superq(_c&i._bylist),&b)_n)))+2,%superq(_list_c&i._b%scan(%superq(_c&i._bylist),&b)_npct)+2)); | |
%if %sysevalf(%superq(c&i._b%scan(%superq(_c&i._bylist),&b)_switch)=1,boolean) %then | |
%let _list_c&i._totlength=%sysevalf(&&_list_c&i._totlength + %superq(_list_c&i._b%scan(%superq(_c&i._bylist),&b)_npct)); | |
%end; | |
%let _list_c&i._m_npct=%sysfunc(max(%length(Missing)+2,%length((N=%superq(r1_c&i._miss_n)))+2,%superq(_list_c&i._m_npct)+2)); | |
%if &by_printmiss =2 or (%sysevalf(%superq(c&i._m_switch)=1,boolean) and (&by_incmiss=1 or &by_printmiss=1)) %then | |
%let _list_c&i._totlength=%sysevalf(&&_list_c&i._totlength + %superq(_list_c&i._m_npct)); | |
%end; | |
%let _list_c&i._t_npct=%sysfunc(max(%length(Total)+2,%length((N=%superq(r1_c&i._n)))+2,%superq(_list_c&i._t_npct)+2)); | |
%if &showtotal=1 or %sysevalf(%superq(by)=,boolean) %then | |
%let _list_c&i._totlength=%sysevalf(&&_list_c&i._totlength + %superq(_list_c&i._t_npct)); | |
%let _list_c&i._pval=%sysfunc(max(%length(P-value)+2,%superq(_list_c&i._pval)+2)); | |
%if (&showpval=1 and &nby>1) or &showpval=2 %then | |
%let _list_c&i._totlength=%sysevalf(&&_list_c&i._totlength + %superq(_list_c&i._pval)); | |
%let _list_totlength=%sysevalf(&&_list_c&i._totlength + &_list_totlength); | |
%if &i ^= &ncolby %then %let _list_totlength=%sysevalf(&_list_totlength + 4); | |
%end; | |
%if %sysevalf(%superq(rowby)^=,boolean) %then %do; | |
%let _list_rowby=%sysfunc(max(%length(%superq(rowbylabel))+2,%superq(_list_rowby)+2)); | |
%let _list_totlength=%sysevalf(&_list_rowby + &_list_totlength); | |
%end; | |
%let _list_factor=%sysevalf(&_list_factor+2); | |
%let _list_totlength=%sysevalf(&_list_totlength + &_list_factor); | |
alter table _out_listing | |
modify %do i = 1 %to %sysfunc(countw(%superq(_list_cvars),|,m)); | |
%if &i>1 %then %do; , %end; | |
%scan(%superq(_list_cvars),&i,|,m) char(%superq(_list_%scan(%superq(_list_cvars),&i,|,m))) | |
%end;; | |
quit; | |
options linesize=%sysfunc(max(64,%sysfunc(min(256,&_list_totlength)))) nocenter; | |
proc report data=_out_listing nowd split='~' spanrows spacing=0 missing; | |
columns | |
/*Table Title*/ | |
("%sysfunc(tranwrd(%superq(title),`,~))~%sysfunc(repeat(-,&_list_totlength-1))" | |
/*Variables for later*/ | |
(rowby varnum varlevel header meta factor) | |
/*Start COLBY Label*/ | |
%if %sysevalf(%superq(colby)^=,boolean) and %sysevalf(%superq(showcollabel)=1,boolean) %then %do; | |
("&colbylabel" | |
%end; | |
%do c = 1 %to &ncolby; | |
/*Add a space between COLBY levels*/ | |
%if &c>1 %then %do; | |
(dummy&c) | |
%end; | |
/*Add Column level headers*/ | |
%if %sysevalf(%superq(colby)^=,boolean) %then %do; | |
("%scan(%superq(_colbylvls),&c,|,m)~%sysfunc(repeat(-,&&_list_c&c._totlength-1))" | |
%end; | |
%if %sysevalf(%qupcase(&total_col_pos)=START,boolean) %then %do; c&c._t_npct %end; | |
/*Print BY variable headers*/ | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
%if %sysevalf(%superq(showbylabel)=1,boolean) %then %do; ("&bylabel" %end; | |
c&c._m_npct | |
%end; | |
/*Print result variables*/ | |
%if %sysevalf(%superq(by)^=,boolean) %then %do b = 1 %to %sysfunc(countw(%superq(_c&c._bylist))); | |
c&c._b%scan(%superq(_c&c._bylist),&b)_npct | |
%end; | |
%if %sysevalf(%superq(showbylabel)=1,boolean) and %sysevalf(%superq(by)^=,boolean) %then %do; ) %end; | |
%if %sysevalf(%qupcase(&total_col_pos)=END,boolean) %then %do; c&c._t_npct %end; | |
/*Print P-value and close By Header parenthasis*/ | |
%if (%sysevalf(%superq(by)^=,boolean) and &nby>1) or &showpval=2 %then %do; | |
c&c._pval | |
%end; | |
/*Close COLBY header parenthases*/ | |
%if %sysevalf(%superq(colby)^=,boolean) %then %do; | |
) | |
%end; | |
/*End C loop*/ | |
%end; | |
/*Close COLBY Label parenthases*/ | |
%if %sysevalf(%superq(colby)^=,boolean) and %sysevalf(%superq(showcollabel)=1,boolean) %then %do; | |
) | |
%end; | |
/*Closes title parenthases*/ | |
); | |
/*Subtitle*/ | |
define factor / display "&subtitleheader~%sysfunc(repeat(-,&_list_factor-1))" id; | |
/*Set up indent for compute block*/ | |
define varnum / order order=data noprint;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
compute before varnum; | |
%if %qupcase(&split)=LINE %then %do; | |
x="%sysfunc(repeat(-,&_list_totlength-1))"; | |
if varnum in(0 1) then len=0; | |
else len=length(x); | |
line @1 x $varying. len; | |
%end; | |
%if %sysevalf(%superq(rowby)^=,boolean) %then %do; | |
x="%sysfunc(repeat(-,&_list_totlength-1))"; | |
if varnum ^=1 then len2=0; | |
else len2=length(x); | |
line @1 x $varying. len2; | |
%end; | |
endcomp; | |
define varlevel / display noprint;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
define header / display noprint;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
define meta / display noprint;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
/*Set up whether ROWBY is shown or not*/ | |
%if %sysevalf(%superq(rowby)^=,boolean) %then %do; | |
define rowby / order order=data "&rowbylabel~%sysfunc(repeat(-,&_list_rowby-1))" missing id; | |
compute before rowby; | |
line @1 "%sysfunc(repeat(-,&_list_totlength-1))"; | |
endcomp; | |
%end; | |
%else %do; | |
define rowby / order order=data noprint missing;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
%end; | |
/*Print each Column Subgroup analysis*/ | |
%do c = 1 %to &ncolby; | |
/*If BY variable present, print all subgroup distributions*/ | |
%if %sysevalf(%superq(by)^=,boolean) %then %do b = 1 %to %sysfunc(countw(%superq(_c&c._bylist))); | |
define c&c._b%scan(%superq(_c&c._bylist),&b)_npct / display center | |
%if %sysevalf(%superq(rowby)=,boolean) %then %do; | |
"%scan(%superq(_bylvls),%scan(%superq(_c&c._bylist),&b),|,m)~(N=%superq(r1_c&c._b%scan(%superq(_c&c._bylist),&b)_n))~%sysfunc(repeat(-,%superq(_list_c&c._b%scan(%superq(_c&c._bylist),&b)_npct)-1))" | |
%end; | |
%else %do; | |
"%scan(%superq(_bylvls),%scan(%superq(_c&c._bylist),&b),|,m)~%sysfunc(repeat(-,%superq(_list_c&c._b%scan(%superq(_c&c._bylist),&b)_npct)-1))" | |
%end; | |
%if %sysevalf(%superq(c&c._b%scan(%superq(_c&c._bylist),&b)_switch)=0,boolean) %then %do; noprint %end;; | |
%end; | |
/*Print distribution across missing by group*/ | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
define c&c._m_npct / display | |
%if %sysevalf(%superq(rowby)=,boolean) %then %do; | |
"Missing~(N=%superq(r1_c&c._miss_n))~%sysfunc(repeat(-,&&_list_c&c._m_npct-1))" | |
%end; | |
%else %do; | |
"Missing~%sysfunc(repeat(-,&&_list_c&c._m_npct-1))" | |
%end; | |
center | |
%if &by_printmiss ^=2 %then %do;/*Value if 2 tells SAS to always print the missing column even if no values*/ | |
%if %sysevalf(%superq(c&c._m_switch)=0,boolean) %then %do; noprint %end; /*No values in the missing column*/ | |
%else %if &by_incmiss=0 and &by_printmiss=0 %then %do; noprint %end; /*If there are missing values, but requested to be suppressed and not included as a value of by*/ | |
%end;; | |
%end; | |
/*Print distribution across all patients*/ | |
define c&c._t_npct / display | |
%if %sysevalf(%superq(rowby)=,boolean) %then %do; | |
"Total~(N=%superq(r1_c&c._n))~%sysfunc(repeat(-,&&_list_c&c._t_npct-1))" | |
%end; | |
%else %do; | |
"Total~%sysfunc(repeat(-,&&_list_c&c._t_npct-1))" | |
%end; | |
center | |
%if &showtotal=0 and %sysevalf(%superq(by)^=,boolean) %then %do; noprint %end;; /*Overrides SHOWTOTAL when no BY variable specified*/ | |
/*Print P-values if BY variable specified*/ | |
%if (%sysevalf(%superq(by)^=,boolean) and &nby>1) or &showpval=2 %then %do; | |
define c&c._pval / display "P-value~%sysfunc(repeat(-,&&_list_c&c._pval-1))" center style={cellwidth=&pvalwidth} | |
%if &showpval=0 %then %do; noprint %end;;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
%end; | |
/*Sets up DUMMY variable to create space between column headers*/ | |
%if &c>1 %then %do; | |
define dummy&c / computed " ~%sysfunc(repeat(-,4-1))" width=4; | |
%end; | |
%end; | |
/*Print p-values and footnotes after table*/ | |
compute after / style={just=l}; | |
line @1 "%sysfunc(repeat(-,&_list_totlength-1))"; | |
/*Prints p-value footnotes*/ | |
%if (&showpval=2 or (&showpval=1 and %sysevalf(%superq(by)^=,boolean))) and &npfoot>0 %then %do; | |
line @4 "&pfoot_list"; | |
%end; | |
/*Print Footnotes*/ | |
%do i = 1 %to %sysfunc(max(1,%sysfunc(countw(%superq(footnote),`,m)))); | |
line @4 "%scan(%superq(footnote),&i,`,m) "; | |
%end; | |
endcomp; | |
where meta^=1; | |
run; | |
options &_center; | |
proc datasets nolist nodetails; | |
%if &debug=0 %then %do; | |
delete _outldict _out_listing ; | |
%end; | |
quit; | |
ods select all; | |
%end; | |
%if &_other = 1 or &_ppt = 1 or &_rtf=1 or &_html=1 or %sysevalf(%superq(outdoc)^=,boolean) %then %do; | |
%if &_listing=1 %then %do; | |
ODS LISTING CLOSE; | |
%end; | |
%do k = 1 %to %sysfunc(countw(%superq(_destinations),|)); | |
%if %sysevalf(%qupcase(%qscan(%superq(_destinations),&k,|))=POWERPOINT,boolean) %then %do; | |
ods powerpoint style=_tablenppt; | |
%end; | |
%else %if %sysevalf(%qupcase(%qscan(%superq(_destinations),&k,|))=EXCEL,boolean) %then %do; | |
ods excel options(flow='tables' sheet_name="&excel_sheetname" frozen_rowheaders="%sysevalf(1+%sysevalf(%superq(rowby)^=,boolean))" | |
frozen_headers="%sysevalf(%sysevalf(%superq(colby)^=,boolean)*(1+&showcollabel) + | |
%sysevalf(%superq(by)^=,boolean)*(&showbylabel) + 2)") style=_tablen; | |
%end; | |
%else %if %sysevalf(%qupcase(%qscan(%superq(_destinations),&k,|))^=RTF,boolean) %then %do; | |
ods %scan(%superq(_destinations),&k,|) style=_tablen; | |
%end; | |
%end; | |
%local _rloop; | |
%if &_other=1 %then %let _rloop=OTHER; | |
%if &_ppt=1 and %sysevalf(%superq(_rloop)=,boolean) %then %let _rloop=PPT; | |
%else %if &_ppt=1 %then %let _rloop=&_rloop|PPT; | |
%if &_rtf=1 and %sysevalf(%superq(_rloop)=,boolean) %then %let _rloop=RTF; | |
%else %if &_rtf=1 %then %let _rloop=&_rloop|RTF; | |
%if &_HTML=1 and %sysevalf(%superq(_rloop)=,boolean) %then %let _rloop=HTML; | |
%else %if &_HTML=1 %then %let _rloop=&_rloop|HTML; | |
%do rloop = 1 %to %sysfunc(countw(&_rloop,|)); | |
%if %sysevalf(%scan(%superq(_rloop),&rloop,|)=OTHER,boolean) %then %do; | |
%if &_ppt=1 %then %do; | |
ods POWERPOINT exclude all; | |
%end; | |
%if &_rtf=1 %then %do; | |
ods RTF exclude all; | |
%end; | |
%if &_html=1 %then %do; | |
ods HTML exclude all; | |
%end; | |
%end; | |
%else %if %sysevalf(%scan(%superq(_rloop),&rloop,|)=RTF,boolean) %then %do; | |
ods RTF select all; | |
%if %sysevalf(%qupcase(&orientation)^=%qupcase(&_orientation),boolean) %then %do; | |
ods rtf; | |
%end; | |
%do k = 1 %to %sysfunc(countw(%superq(_destinations),|)); | |
%if %sysevalf(%qupcase(%qscan(%superq(_destinations),&k,|))^=RTF,boolean) %then %do; | |
ods %scan(%superq(_destinations),&k,|) exclude all; | |
%end; | |
%end; | |
%end; | |
%else %if %sysevalf(%scan(%superq(_rloop),&rloop,|)=HTML,boolean) %then %do; | |
ods HTML select all; | |
%do k = 1 %to %sysfunc(countw(%superq(_destinations),|)); | |
%if %sysevalf(%qupcase(%qscan(%superq(_destinations),&k,|))^=HTML,boolean) %then %do; | |
ods %scan(%superq(_destinations),&k,|) exclude all; | |
%end; | |
%end; | |
%end; | |
%else %do; | |
ods POWERPOINT select all; | |
ods POWERPOINT style=_tablenppt; | |
%do k = 1 %to %sysfunc(countw(%superq(_destinations),|)); | |
%if %sysevalf(%qupcase(%qscan(%superq(_destinations),&k,|))^=POWERPOINT,boolean) %then %do; | |
ods %scan(%superq(_destinations),&k,|) exclude all; | |
%end; | |
%end; | |
%end; | |
%local _hbtmbrd _htwidth; | |
%if %sysevalf(%scan(%superq(_rloop),&rloop,|)=RTF,boolean) %then %let _hbtmbrd=^S={borderbottomstyle=solid borderbottomwidth=0.1 borderbottomcolor=black}; | |
%else %let _hbtmbrd=; | |
%if %sysevalf(%scan(%superq(_rloop),&rloop,|)=HTML,boolean) %then %let _htwidth=1; | |
%else %let _htwidth=0.1; | |
proc report data=_out nowd split='~' spanrows missing | |
%if %sysevalf(%scan(%superq(_rloop),&rloop,|)^=PPT,boolean) %then %do; | |
style(header)={%if %sysevalf(%scan(%superq(_rloop),&rloop,|)=HTML,boolean) %then %do; | |
borderstyle=none borderwidth=1 | |
%if &borderdisplay>=2 %then %do; borderstyle=solid bordercolor=black %end; | |
%end; | |
background=white fontsize=&headersize color=black fontfamily="&font" fontweight=&headerweight vjust=bottom} | |
style(column)={%if %sysevalf(%scan(%superq(_rloop),&rloop,|)=HTML,boolean) %then %do; | |
borderstyle=none borderwidth=1 | |
%if &borderdisplay>=2 %then %do; borderstyle=solid bordercolor=black %end; | |
%end; | |
background=white fontsize=&datasize color=black fontfamily="&font" fontweight=&dataweight vjust=top} | |
style(lines)={%if %sysevalf(%scan(%superq(_rloop),&rloop,|)=HTML,boolean) %then %do; | |
borderstyle=none borderwidth=1 | |
%if &borderdisplay>=2 %then %do; borderstyle=solid bordercolor=black %end; | |
%end; | |
background=white fontsize=&datasize color=black fontfamily="&font" fontweight=&dataweight} | |
style(report)={color=black | |
%if %sysevalf(%scan(%superq(_rloop),&rloop,|)=RTF,boolean) and &borderdisplay=1 %then %do; | |
cellspacing=0 rules=groups frame=void cellpadding=0 borderspacing=0 | |
%end; | |
%else %if %sysevalf(%scan(%superq(_rloop),&rloop,|)=HTML,boolean) %then %do; | |
borderstyle=none borderwidth=1 | |
%if &borderdisplay>=2 %then %do; borderstyle=solid bordercolor=black %end; | |
%end;} | |
%end;; | |
columns | |
/*Variables for later*/ | |
(rowby indent vartype varnum varlevel header meta factor) | |
/*Start COLBY Label*/ | |
%if %sysevalf(%superq(colby)^=,boolean) and %sysevalf(%superq(showcollabel)=1,boolean) %then %do; | |
title=collabel, ( | |
%end; | |
%do c = 1 %to &ncolby; | |
/*Add a space between COLBY levels*/ | |
%if &c>1 %then %do; | |
%if %sysevalf(%superq(by)^=,boolean) and %sysevalf(%superq(showbylabel)=1,boolean) %then %do; | |
title=dummy_title&c, | |
%end; | |
(footnote=dummy&c) | |
%end; | |
/*Add Column level headers*/ | |
%if %sysevalf(%superq(colby)^=,boolean) %then %do; | |
title=colval&c,( | |
%end; | |
%if %sysevalf(%qupcase(&total_col_pos)=START,boolean) %then %do; c&c._t_npct %end; | |
/*Print BY variable headers*/ | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
%if %sysevalf(%superq(showbylabel)=1,boolean) %then %do; ("&bylabel" %end; | |
c&c._m_npct | |
%end; | |
/*Print result variables*/ | |
%if %sysevalf(%superq(by)^=,boolean) %then %do b = 1 %to %sysfunc(countw(%superq(_c&c._bylist))); | |
c&c._b%scan(%superq(_c&c._bylist),&b)_npct | |
%end; | |
%if %sysevalf(%superq(showbylabel)=1,boolean) and %sysevalf(%superq(by)^=,boolean) %then %do; ) %end; | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; ("^_" %end; | |
%if %sysevalf(%superq(colby)^=,boolean) %then %do; _dummy&c %end; | |
%if %sysevalf(%qupcase(&total_col_pos)=END,boolean) %then %do; c&c._t_npct %end; | |
/*Print P-value and close By Header parenthasis*/ | |
%if (%sysevalf(%superq(by)^=,boolean) and &nby>1) or &showpval=2 %then %do; | |
c&c._pval | |
%end; | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; ) %end; | |
/*Close COLBY header parenthases*/ | |
%if %sysevalf(%superq(colby)^=,boolean) %then %do; | |
) | |
%end; | |
/*End C loop*/ | |
%end; | |
/*Close COLBY Label parenthases*/ | |
%if %sysevalf(%superq(colby)^=,boolean) and %sysevalf(%superq(showcollabel)=1,boolean) %then %do; | |
) | |
%end; | |
/*Closes title parenthases*/ | |
_last_; | |
/*Last is for compute block*/ | |
define _last_ / computed noprint; | |
/*Subtitle*/ | |
define factor / display "&_hbtmbrd.&subtitleheader." id | |
style(column)={cellwidth=&subtitlewidth leftmargin=0.05in} style(header)={just=left}; | |
/*Column By Headers*/ | |
%if %sysevalf(%superq(colby)^=,boolean) and %sysevalf(%superq(showcollabel)=1,boolean) %then %do; | |
define collabel / across missing "&colbylabel" | |
style(header)={%if &borderdisplay=1 %then %do; borderbottomstyle=none %end; just=center}; | |
%end; | |
%if %sysevalf(%superq(colby)^=,boolean) %then %do c = 1 %to &ncolby; | |
define colval&c / across missing "%scan(%superq(_colbylvls),&c,|,m)" | |
style(header)={borderbottomstyle=solid borderbottomwidth=&_htwidth borderbottomcolor=black just=center} ; | |
%if &c>1 and %sysevalf(%superq(by)^=,boolean) and %sysevalf(%superq(showbylabel)=1,boolean) %then %do; | |
define dummy_title&c / across missing '^_' | |
style(header)={%if &borderdisplay=1 %then %do; borderbottomstyle=none %end; borderbottomwidth=&_htwidth}; | |
%end; | |
%end; | |
/*Set up indent for compute block*/ | |
define indent / display noprint;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
define vartype / display noprint;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
define varnum / display noprint;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
define varlevel / display noprint;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
define header / display noprint;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
define meta / display noprint;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
/*Set up whether ROWBY is shown or not*/ | |
%if %sysevalf(%superq(rowby)^=,boolean) %then %do; | |
define rowby / order order=data "&_hbtmbrd.&rowbylabel" style(column)={leftmargin=0.05in cellwidth=&rowbywidth} missing id; | |
%end; | |
%else %do; | |
define rowby / order order=data noprint missing;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
%end; | |
/*Print each Column Subgroup analysis*/ | |
%do c = 1 %to &ncolby; | |
/*If BY variable present, print all subgroup distributions*/ | |
%if %sysevalf(%superq(by)^=,boolean) %then %do b = 1 %to %sysfunc(countw(%superq(_c&c._bylist))); | |
define c&c._b%scan(%superq(_c&c._bylist),&b)_npct / display | |
%if %sysevalf(%superq(rowby)=,boolean) %then %do; | |
"&_hbtmbrd.%scan(%superq(_bylvls),%scan(%superq(_c&c._bylist),&b),|,m)~(N=%superq(r1_c&c._b%scan(%superq(_c&c._bylist),&b)_n))" | |
%end; | |
%else %do; | |
"&_hbtmbrd.%scan(%superq(_bylvls),%scan(%superq(_c&c._bylist),&b),|,m)" | |
%end; | |
center style(column)={cellwidth=&datawidth} | |
%if %sysevalf(%superq(c&c._b%scan(%superq(_c&c._bylist),&b)_switch)=0,boolean) %then %do; noprint %end;; | |
%end; | |
/*Print distribution across missing by group*/ | |
%if %sysevalf(%superq(by)^=,boolean) %then %do; | |
define c&c._m_npct / display | |
%if %sysevalf(%superq(rowby)=,boolean) %then %do; | |
"&_hbtmbrd.Missing~(N=%superq(r1_c&c._miss_n))" | |
%end; | |
%else %do; | |
"&_hbtmbrd.Missing" | |
%end; | |
center style(column)={cellwidth=&datawidth} | |
%if &by_printmiss ^=2 %then %do;/*Value if 2 tells SAS to always print the missing column even if no values*/ | |
%if %sysevalf(%superq(c&c._m_switch)=0,boolean) %then %do; noprint %end; /*No values in the missing column*/ | |
%else %if &by_incmiss=0 and &by_printmiss=0 %then %do; noprint %end; /*If there are missing values, but requested to be suppressed and not included as a value of by*/ | |
%end;; | |
%end; | |
/*Print distribution across all patients*/ | |
define c&c._t_npct / display | |
%if %sysevalf(%superq(rowby)=,boolean) %then %do; | |
"&_hbtmbrd.Total~(N=%superq(r1_c&c._n))" | |
%end; | |
%else %do; | |
"&_hbtmbrd.Total" | |
%end; | |
center style(column)={cellwidth=&datawidth} | |
%if &showtotal=0 and %sysevalf(%superq(by)^=,boolean) %then %do; noprint %end;; /*Overrides SHOWTOTAL when no BY variable specified*/ | |
/*Print P-values if BY variable specified*/ | |
%if (%sysevalf(%superq(by)^=,boolean) and &nby>1) or &showpval=2 %then %do; | |
define c&c._pval / display "&_hbtmbrd.P-value" center style(column)={cellwidth=&pvalwidth} | |
%if &showpval=0 %then %do; noprint %end;;/*NOPRINT initializes variable without printing. Can still refer to it*/ | |
%end; | |
/*Sets up DUMMY variable to create space between column headers*/ | |
%if %sysevalf(%superq(colby)^=,boolean) %then %do; | |
define _dummy&c / computed "&_hbtmbrd. " style(column)={cellwidth=0.1in } noprint; | |
%end; | |
%if &c>1 %then %do; | |
define dummy&c / display "&_hbtmbrd. " style(column)={cellwidth=0.1in}; | |
%end; | |
%end; | |
/*Set up indents and shading with compute block*/ | |
compute _last_; | |
count+1; | |
%if &shading=1 %then %do; | |
shade+1; | |
%end; | |
%else %if &shading=2 %then %do; | |
if varlevel=.l then shade+1; | |
%end; | |
%else %do; | |
shade=1; | |
%end; | |
%if %qupcase(&split)=LINE %then %do; | |
if varlevel=.l then call define(_row_,"style/merge","style={bordertopstyle=solid bordertopwidth=&_htwidth bordertopcolor=black}"); | |
%end; | |
if count=1 then call define(_row_,"style/merge","style={bordertopstyle=solid bordertopcolor=black bordertopwidth=&_htwidth}"); | |
/*Indents when indent=1, otherwise bolds text for label*/ | |
if indent=1 then call define("factor","style/merge","style={leftmargin=0.12in indent=0.12in}"); | |
else call define("factor","style/merge","style={fontweight=bold}"); | |
if mod(shade,2)=0 then call define(_row_,"style/merge","style={background=greyef}"); | |
if ^missing(rowby) and "%qupcase(&split)"^="LINE" then do; | |
call define(_row_,"style/merge","style={bordertopstyle=solid bordertopwidth=&_htwidth bordertopcolor=black borderbottomstyle=solid borderbottomwidth=&_htwidth borderbottomcolor=black}"); | |
call define("rowby","style/merge","style={borderbottomstyle=none borderbottomwidth=&_htwidth borderbottomcolor=black}"); | |
end; | |
%if %superq(borderdisplay)=4 %then %do; | |
if varlevel ^=.l then do; | |
if mod(shade,2)=0 then call define(_row_,"style/merge","style={bordertopstyle=hidden borderbottomstyle=hidden bordertopwidth=0 borderbottomwidth=0 bordertopcolor=greyef borderbottomcolor=greyef}"); | |
else call define(_row_,"style/merge","style={bordertopstyle=hidden borderbottomstyle=hidden bordertopwidth=0 borderbottomwidth=0 bordertopcolor=white borderbottomcolor=white}"); | |
end; | |
else if varlevel=.l then do; | |
if mod(shade,2)=0 then call define(_row_,"style/merge","style={bordertopstyle=solid borderbottomstyle=hidden bordertopwidth=&_htwidth borderbottomwidth=0 bordertopcolor=black borderbottomcolor=greyef}"); | |
else call define(_row_,"style/merge","style={bordertopstyle=solid borderbottomstyle=hidden bordertopwidth=&_htwidth borderbottomwidth=0 bordertopcolor=black borderbottomcolor=white}"); | |
end; | |
%end; | |
endcomp; | |
/*Print title before table*/ | |
compute before _page_/ | |
style={leftmargin=0.06in borderbottomwidth=1 borderbottomcolor=black borderbottomstyle=solid | |
%if &borderdisplay=1 or &borderdisplay=3 or &borderdisplay=4 %then %do; | |
bordertopstyle=hidden borderleftstyle=hidden borderrightstyle=hidden | |
bordertopwidth=&_htwidth borderleftwidth=&_htwidth borderrightwidth=&_htwidth | |
bordertopcolor=white borderleftcolor=white borderrightcolor=white | |
%end; | |
%else %if &borderdisplay=2 %then %do; | |
bordertopstyle=solid borderleftstyle=solid borderrightstyle=solid | |
bordertopwidth=&_htwidth borderleftwidth=&_htwidth borderrightwidth=&_htwidth | |
bordertopcolor=black borderleftcolor=black borderrightcolor=black | |
%end; | |
vjust=bottom fontsize=&titlesize fontweight=&titleweight | |
just=&titlealign color=black background=white}; | |
%do i = 1 %to %sysfunc(max(1,%sysfunc(countw(%superq(title),`,m)))); | |
line @1 "%scan(%superq(title),&i,`,m)"; | |
%end; | |
endcomp; | |
/*Print p-values and footnotes after table*/ | |
compute after / style={leftmargin=0.06in bordertopstyle=solid bordertopwidth=1 bordertopcolor=black vjust=top | |
%if &borderdisplay=1 or &borderdisplay=3 or &borderdisplay=4 %then %do; | |
borderbottomstyle=hidden borderleftstyle=hidden borderrightstyle=hidden | |
borderbottomwidth=&_htwidth borderleftwidth=&_htwidth borderrightwidth=&_htwidth | |
borderbottomcolor=white borderleftcolor=white borderrightcolor=white | |
%end; | |
%else %if &borderdisplay=2 %then %do; | |
borderbottomstyle=solid borderleftstyle=solid borderrightstyle=solid | |
borderbottomwidth=&_htwidth borderleftwidth=&_htwidth borderrightwidth=&_htwidth | |
borderbottomcolor=black borderleftcolor=black borderrightcolor=black | |
%end; | |
fontsize=&footnotesize fontfamily="&font" fontweight=&footnoteweight just=&footnotealign color=black}; | |
/*Prints p-value footnotes*/ | |
%if (&showpval=2 or (&showpval=1 and %sysevalf(%superq(by)^=,boolean))) and &npfoot>0 %then %do; | |
line @1 "&pfoot"; | |
%end; | |
/*Print Footnotes*/ | |
%if ^((&showpval=2 or (&showpval=1 and %sysevalf(%superq(by)^=,boolean))) and &npfoot>0) or | |
%sysevalf(%superq(footnote)^=,boolean) %then %do i = 1 %to %sysfunc(max(1,%sysfunc(countw(%superq(footnote),`,m)))); | |
line "%scan(%superq(footnote),&i,`,m) "; | |
%end; | |
endcomp; | |
where meta^=1; | |
run; | |
%end; | |
ods select all; | |
%do k = 1 %to %sysfunc(countw(%superq(_destinations),|)); | |
ods %scan(%superq(_destinations),&k,|) style=%scan(%superq(_styles),&k,|); | |
%end; | |
%if %sysevalf(%superq(outdoc)^=,boolean) %then %do; | |
ods &destination close; | |
%end; | |
%if &_listing=1 %then %do; | |
ODS LISTING; | |
%end; | |
%else %if &_listing=0 %then %do; | |
ODS LISTING CLOSE; | |
%end; | |
%end; | |
options nonotes orientation=&_orientation; | |
%if &_rtf2=1 and %sysevalf(%qupcase(&orientation)^=%qupcase(&_orientation),boolean) %then %do; | |
ods rtf; | |
%end; | |
/*Output report dataset*/ | |
%if %sysevalf(%superq(out)^=,boolean) %then %do; | |
data &out; | |
set _out; | |
run; | |
%end; | |
%errhandl: | |
proc datasets nolist nodetails; | |
%if &debug=0 %then %do; | |
delete _temp _combined _out; | |
%end; | |
quit; | |
/**Reload previous Options**/ | |
ods path &_odspath; | |
options mergenoby=&_mergenoby &_notes &_qlm linesize=&_linesize msglevel=&_msglevel &_mprint; | |
%put TABLEN has finished processing, runtime: %sysfunc(putn(%sysevalf(%sysfunc(TIME())-&_starttime.),mmss8.4)); | |
%mend; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment