├── Compute_CAS_CASL.sas ├── Create_Email_Message.txt ├── Getting Started with PROC Python.sas ├── Getting Started with the Python Editor.py ├── Import_HOME_EQUITY.sas ├── Import_LOAN_CUSTOMERS.py ├── LICENSE ├── Prepare_Home_Equity_Data.flw ├── Print Sample (final).step ├── PrintSample.sas ├── README.md ├── SUPPORT.md ├── Score_HOME_EQUITY.txt ├── Train_HOME_EQUITY.txt ├── Use the Python SWAT Package on the SAS Viya Platform.ipynb ├── _Load_Quick_Start_Data.sas ├── country_lookup.csv ├── customer.csv ├── home_equity.csv └── mortgage_rates.xlsx /Compute_CAS_CASL.sas: -------------------------------------------------------------------------------- 1 | /*******************************************************************************/ 2 | /* Copyright © 2022, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. */ 3 | /* SPDX-License-Identifier: Apache-2.0 */ 4 | /*******************************************************************************/ 5 | 6 | /***************************/ 7 | /* Create work.home_equity */ 8 | /***************************/ 9 | 10 | %let fileName = %scan(&_sasprogramfile,-1,'/'); 11 | %let path = %sysfunc(tranwrd(&_sasprogramfile, &fileName,)); 12 | %include "&path/_Load_Quick_Start_Data.sas"; 13 | 14 | 15 | /******************************************************/ 16 | /* Scenario 1: SAS Program Executed on Compute Server */ 17 | /******************************************************/ 18 | 19 | title "Compute Server Program"; 20 | 21 | libname mydata "c:\mydata"; 22 | 23 | data mydata.home_equity; 24 | length LOAN_OUTCOME $ 7; 25 | set work.home_equity; 26 | if Value ne . and MortDue ne . then LTV=MortDue/Value; 27 | CITY=propcase(City); 28 | if BAD=0 then LOAN_OUTCOME='Paid'; 29 | else LOAN_OUTCOME='Default'; 30 | label LTV='Loan to Value Ratio' 31 | LOAN_OUTCOME='Loan Outcome'; 32 | format LTV percent6.; 33 | run; 34 | 35 | proc contents data=mydata.home_equity; 36 | run; 37 | title; 38 | 39 | proc freq data=mydata.home_equity; 40 | tables Loan_Outcome Reason Job; 41 | run; 42 | 43 | proc means data=mydata.home_equity noprint; 44 | var Loan DebtInc LTV; 45 | output out=home_equity_summary; 46 | run; 47 | 48 | 49 | /*************************************************************************/ 50 | /* Scenario 2: SAS Program Executed on CAS Server with CAS-Enabled Steps */ 51 | /*************************************************************************/ 52 | 53 | cas mySession; 54 | 55 | /* Option #1: Load Data into Memory via CASUTIL Step */ 56 | proc casutil; 57 | load data=work.home_equity outcaslib="casuser" casdata="home_equity"; 58 | quit; 59 | 60 | /* Option #2: Load Data into Memory via DATA Step */ 61 | * Assign librefs to all caslibs; 62 | caslib _all_ assign; 63 | 64 | * Assign libref CASUSER to corresponding caslib; 65 | *libname casuser cas caslib=casuser; 66 | 67 | title "CAS-Enabled PROCS"; 68 | data casuser.home_equity; 69 | length LOAN_OUTCOME $ 7; 70 | set work.home_equity; 71 | if Value ne . and MortDue ne . then LTV=MortDue/Value; 72 | CITY=propcase(City); 73 | if BAD=0 then LOAN_OUTCOME='Paid'; 74 | else LOAN_OUTCOME='Default'; 75 | label LTV='Loan to Value Ratio' 76 | LOAN_OUTCOME='Loan Outcome'; 77 | format LTV percent6.; 78 | run; 79 | 80 | proc contents data=casuser.home_equity; 81 | run; 82 | 83 | proc freqtab data=casuser.home_equity; 84 | tables Loan_Outcome Reason Job; 85 | run; 86 | 87 | proc mdsummary data=casuser.home_equity; 88 | var Loan MortDue Value DebtInc; 89 | output out=casuser.home_equity_summary; 90 | run; 91 | 92 | cas mySession terminate; 93 | 94 | 95 | /************************************************************/ 96 | /* Scenario 3: SAS Program Executed on CAS Server with CASL */ 97 | /************************************************************/ 98 | 99 | cas mySession; 100 | 101 | title "CASL Results"; 102 | proc cas; 103 | * Create dictionary to reference home_equity table in Casuser; 104 | tbl={name='home_equity', caslib='casuser'}; 105 | * Create CASL variable named DS to store DATA step code. Both 106 | input and output tables must be in-memory; 107 | source ds; 108 | data casuser.home_equity; 109 | length LOAN_OUTCOME $ 7; 110 | set casuser.home_equity; 111 | if Value ne . and MortDue ne . then LTV=MortDue/Value; 112 | CITY=propcase(City); 113 | if BAD=0 then LOAN_OUTCOME='Paid'; 114 | else LOAN_OUTCOME='Default'; 115 | label LTV='Loan to Value Ratio' 116 | LOAN_OUTCOME='Loan Outcome'; 117 | format LTV percent6.; 118 | run; 119 | endsource; 120 | * Drop home_equity from casuser if it exists; 121 | table.dropTable / name=tbl['name'], caslib=tbl['caslib'], quiet=true; 122 | * Load home_equity.sas7bdat to casuser; 123 | upload path="&path/home_equity.sas7bdat" 124 | casout={caslib="casuser", name="home_equity", replace="true"}; 125 | * Execute DATA step code; 126 | dataStep.runCode / code=ds; 127 | * List home_equity column attributes, similar to PROC CONTENTS; 128 | table.columnInfo / 129 | table=tbl; 130 | * Generate frequency report, similar to PROC FREQ; 131 | simple.freq / 132 | table=tbl, 133 | inputs={'Loan_Outcome', 'Reason', 'Job'}; 134 | * Generate summary table, similar to PROC MEANS; 135 | simple.summary / 136 | table=tbl, 137 | input={'Loan', 'MortDue', 'Value', 'DebtInc'}, 138 | casOut={name='orders_sum', replace=true}; 139 | quit; 140 | title; 141 | 142 | cas mySession terminate; 143 | -------------------------------------------------------------------------------- /Create_Email_Message.txt: -------------------------------------------------------------------------------- 1 | ''' List all output parameters as comma-separated values in the "Output:" docString. Do not specify "None" if there is no output parameter.''' 2 | ''' List all Python packages that are not built-in packages in the "DependentPackages:" docString. Separate the package names with commas on a single line. ''' 3 | ''' DependentPackages: ''' 4 | 5 | def execute (RESULTFLAG,RESULTREASON): 6 | 'Output:MESSAGE' 7 | if RESULTFLAG == -1: 8 | message_part_1 = "Dear Applicant, \n We are writing to inform you of your recent home equity loan application. Unfortunately you do not meet our criteria for loan approval for the following reason(s): " 9 | else: 10 | message_part_1 = "Dear Applicant, \n We are writing to inform you of your recent home equity loan application. " 11 | 12 | MESSAGE = message_part_1 + RESULTREASON 13 | return MESSAGE 14 | -------------------------------------------------------------------------------- /Getting Started with PROC Python.sas: -------------------------------------------------------------------------------- 1 | * Python code to access and prepare the data *; 2 | proc python; 3 | submit; 4 | 5 | ## Packages and Options 6 | import pandas as pd 7 | import numpy as np 8 | pd.set_option('display.max_columns', None) 9 | 10 | 11 | ## Access Data 12 | df_raw = pd.read_csv(r'https://support.sas.com/documentation/onlinedoc/viya/exampledatasets/home_equity.csv') 13 | 14 | 15 | ## Prepare Data 16 | df = (df_raw 17 | .fillna(df_raw[df_raw.select_dtypes(include = np.number).columns.to_list()].mean()) ## Fill all numeric missing values with the mean 18 | .fillna(df_raw[df_raw.select_dtypes(include = object).columns.to_list()].mode().iloc[0]) ## Fill all character missing values with the mode 19 | .assign(DIFF = lambda _df: _df.MORTDUE - _df.VALUE, ## Difference between mortgage due and value 20 | LOAN_STATUS = lambda _df: _df.BAD.map({1:'Default', 0:'Repaid'}) ## Map values of 1 and 0 with the values Default and Repaid 21 | ) 22 | .rename(columns=lambda colName:colName.lower().replace("_","")) ## Lowercase column names and remove underscores 23 | ) 24 | 25 | 26 | ## Preview the dataframe and number of missing values 27 | print(df.head(5)) 28 | print(df.isna().sum()) 29 | 30 | 31 | ## Write the DataFrame as a SAS data set in the WORK library 32 | SAS.df2sd(df, 'work.home_equity_compute_sas') 33 | 34 | endsubmit; 35 | quit; 36 | 37 | 38 | * Connect to the CAS Server *; 39 | cas conn; 40 | 41 | * Drop and then load data to the CAS server *; 42 | proc casutil; 43 | * Drop the global scope CAS table if it exists *; 44 | droptable casdata='home_equity_cas_sas' incaslib="casuser" quiet; 45 | 46 | * Send the SAS data set to the CAS server and promote the table *; 47 | load data=work.home_equity_compute_sas casout="home_equity_cas_sas" outcaslib="casuser" promote; 48 | 49 | * View in-memory CAS tables *; 50 | list tables; 51 | quit; 52 | 53 | * Terminate the CAS connection *; 54 | cas conn terminate; -------------------------------------------------------------------------------- /Getting Started with the Python Editor.py: -------------------------------------------------------------------------------- 1 | ## Packages and Options 2 | import pandas as pd 3 | import numpy as np 4 | pd.set_option('display.max_columns', None) 5 | 6 | 7 | ## Access Data 8 | df_raw = pd.read_csv(r'https://support.sas.com/documentation/onlinedoc/viya/exampledatasets/home_equity.csv') 9 | 10 | 11 | ## Prepare Data 12 | df = (df_raw 13 | .fillna(df_raw[df_raw.select_dtypes(include = np.number).columns.to_list()].mean()) ## Fill all numeric missing values with the mean 14 | .fillna(df_raw[df_raw.select_dtypes(include = object).columns.to_list()].mode().iloc[0]) ## Fill all character missing values with the mode 15 | .assign(DIFF = lambda _df: _df.MORTDUE - _df.VALUE, ## Difference between mortgage due and value 16 | LOAN_STATUS = lambda _df: _df.BAD.map({1:'Default', 0:'Repaid'}) ## Map values of 1 and 0 with the values Default and Repaid 17 | ) 18 | .rename(columns=lambda colName:colName.lower().replace("_","")) ## Lowercase column names and remove underscores 19 | ) 20 | 21 | 22 | ## Preview the dataframe and number of missing values 23 | print(df.head(5)) 24 | print(df.isna().sum()) 25 | 26 | 27 | ## 28 | ## Load the DataFrame to different locations in SAS Viya 29 | ## 30 | 31 | # Load the DataFrame to the compute server as a SAS data set 32 | SAS.df2sd(df, 'work.home_equity_compute_py') 33 | 34 | 35 | ## Create a string with SAS code to connect to the CAS server, delete the global table if it exists, and then load data to CAS 36 | ## NOTE: You can also use the Python SWAT package to accomplish the same tasks below using all Python. 37 | 38 | prepareLoadingToCAS = ''' 39 | * Connect to the CAS Server *; 40 | cas conn; 41 | 42 | * Drop and load data to the CAS server *; 43 | proc casutil; 44 | * Drop the global scope CAS table if it exists *; 45 | droptable casdata='home_equity_cas_py' incaslib="casuser" quiet; 46 | 47 | * Send the SAS data set to the CAS server and promote the table *; 48 | load data=work.home_equity_compute_py casout="home_equity_cas_py" outcaslib="casuser" promote; 49 | 50 | * View in-memory CAS tables *; 51 | list tables; 52 | quit; 53 | ''' 54 | 55 | # Submit the above SAS code 56 | SAS.submit(prepareLoadingToCAS) -------------------------------------------------------------------------------- /Import_HOME_EQUITY.sas: -------------------------------------------------------------------------------- 1 | /*******************************************************************************/ 2 | /* Copyright © 2022, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. */ 3 | /* SPDX-License-Identifier: Apache-2.0 */ 4 | /*******************************************************************************/ 5 | 6 | 7 | /*********************************************/ 8 | /* Read the home_equity.csv sample data from */ 9 | /* the SAS Support Example Data website */ 10 | /* and create WORK.HOME_EQUITY. */ 11 | /*********************************************/ 12 | 13 | filename data TEMP; 14 | 15 | proc http 16 | method="GET" 17 | url="https://support.sas.com/documentation/onlinedoc/viya/exampledatasets/home_equity.csv" 18 | out=data; 19 | run; 20 | 21 | /* Import edu_hmeq.csv and create WORK.HOME_EQUITY */ 22 | proc import file="data" dbms=csv out=work.t_home_equity replace; 23 | guessingrows=5960; 24 | run; 25 | 26 | data work.home_equity; 27 | set work.t_home_equity; 28 | label APPDATE="Loan Application Date" 29 | BAD="Loan Status" 30 | CITY="City" 31 | CLAGE="Age of Oldest Credit Line (months)" 32 | CLNO="Number of Credit Lines" 33 | DEBTINC="Debt to Income Ratio" 34 | DELINQ="Number of Delinquent Credit Lines" 35 | DEROG="Number of Derogatory Reports" 36 | DIVISION="Division" 37 | JOB="Job Category" 38 | LOAN="Amount of Loan Request" 39 | MORTDUE="Amount Due on Existing Mortgage" 40 | NINQ="Number of Recent Credit Inquiries" 41 | REASON="Loan Purpose" 42 | REGION="Region" 43 | STATE="State" 44 | VALUE="Value of Current Property" 45 | YOJ="Years at Present Job"; 46 | format APPDATE date9. 47 | CLAGE comma8.1 48 | LOAN MORTDUE VALUE dollar12. 49 | DEBTINC 8.1 50 | BAD CITY CLNO DELINQ DEROG DIVISION JOB NINQ REASON REGION STATE YOJ; 51 | informat _all_; 52 | run; 53 | 54 | proc datasets lib=work nolist; 55 | delete t_home_equity; 56 | run; 57 | 58 | proc contents data=work.home_equity; 59 | run; 60 | 61 | filename data clear; 62 | 63 | /*****************************************************************************/ 64 | /* Create a default CAS session and create SAS librefs for existing caslibs */ 65 | /* so that they are visible in the SAS Studio Libraries tree. */ 66 | /*****************************************************************************/ 67 | 68 | cas; 69 | libname casuser cas caslib="casuser"; 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /Import_LOAN_CUSTOMERS.py: -------------------------------------------------------------------------------- 1 | ## Copyright © 2022, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. 2 | ## SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | ## Packages and Options 6 | import pandas as pd 7 | 8 | ## Access Data 9 | df = pd.read_csv(r'https://support.sas.com/documentation/onlinedoc/viya/exampledatasets/loan_customers.csv') 10 | 11 | SAS.df2sd(df, 'work.loan_customers') -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Print Sample (final).step: -------------------------------------------------------------------------------- 1 | {"creationTimeStamp":"2024-07-11T22:47:21.544Z","modifiedTimeStamp":"2024-07-12T20:27:20.305Z","createdBy":"student","modifiedBy":"student","name":"Print Sample (final).step","displayName":"Print Sample (final).step","localDisplayName":"Print Sample (final).step","properties":{},"links":[{"method":"GET","rel":"self","href":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65","uri":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65","type":"application/vnd.sas.data.flow.step"},{"method":"GET","rel":"alternate","href":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65","uri":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65","type":"application/vnd.sas.data.flow.step.summary"},{"method":"GET","rel":"up","href":"/dataFlows/steps","uri":"/dataFlows/steps","type":"application/vnd.sas.collection","itemType":"application/vnd.sas.data.flow.step.summary"},{"method":"PUT","rel":"update","href":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65","uri":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65","type":"application/vnd.sas.data.flow.step","responseType":"application/vnd.sas.data.flow.step"},{"method":"DELETE","rel":"delete","href":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65","uri":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65"},{"method":"POST","rel":"copy","href":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65/copy","uri":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65/copy","responseType":"application/vnd.sas.data.flow.step"},{"method":"GET","rel":"transferExport","href":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65","uri":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65","responseType":"application/vnd.sas.transfer.object"},{"method":"PUT","rel":"transferImportUpdate","href":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65","uri":"/dataFlows/steps/0bd7eb03-aa36-47bb-8e84-66531242ad65","type":"application/vnd.sas.transfer.object","responseType":"application/vnd.sas.summary"}],"metadataVersion":0.0,"version":2,"type":"code","flowMetadata":{"inputPorts":[{"name":"Table","displayName":"Table","localDisplayName":"Table","minEntries":1,"maxEntries":1,"defaultEntries":0,"type":"table"}],"outputPorts":[]},"ui":"{\n\t\"showPageContentOnly\": true,\n\t\"pages\": [\n\t\t{\n\t\t\t\"id\": \"Data\",\n\t\t\t\"type\": \"page\",\n\t\t\t\"label\": \"Data\",\n\t\t\t\"children\": [\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"Table\",\n\t\t\t\t\t\"type\": \"inputtable\",\n\t\t\t\t\t\"label\": \"Select input table:\",\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"visible\": \"\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"varlist\",\n\t\t\t\t\t\"type\": \"columnselector\",\n\t\t\t\t\t\"label\": \"Select columns to print:\",\n\t\t\t\t\t\"include\": null,\n\t\t\t\t\t\"order\": false,\n\t\t\t\t\t\"columntype\": \"a\",\n\t\t\t\t\t\"max\": null,\n\t\t\t\t\t\"min\": null,\n\t\t\t\t\t\"visible\": \"\",\n\t\t\t\t\t\"table\": \"Table\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"id\": \"Options\",\n\t\t\t\"label\": \"Options\",\n\t\t\t\"type\": \"page\",\n\t\t\t\"children\": [\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"numRows\",\n\t\t\t\t\t\"type\": \"numstepper\",\n\t\t\t\t\t\"label\": \"Number of rows to print:\",\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"integer\": true,\n\t\t\t\t\t\"min\": 1,\n\t\t\t\t\t\"max\": null,\n\t\t\t\t\t\"stepsize\": 5\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"selection\",\n\t\t\t\t\t\"type\": \"radiogroup\",\n\t\t\t\t\t\"label\": \"Selection method:\",\n\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"value\": \"FIRST\",\n\t\t\t\t\t\t\t\"label\": \"First N rows\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"value\": \"RANDOM\",\n\t\t\t\t\t\t\t\"label\": \"Random sample\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"visible\": \"\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"rsMethod\",\n\t\t\t\t\t\"type\": \"dropdown\",\n\t\t\t\t\t\"label\": \"Rnadom sample method:\",\n\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"value\": \"SRS\",\n\t\t\t\t\t\t\t\"label\": \"Simple random sample (without replacement)\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"value\": \"URS\",\n\t\t\t\t\t\t\t\"label\": \"Unrestricted random sample (with replacement)\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"visible\": [\n\t\t\t\t\t\t\"$selection\",\n\t\t\t\t\t\t\"=\",\n\t\t\t\t\t\t\"RANDOM\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"syntaxversion\": \"1.3.0\",\n\t\"values\": {\n\t\t\"Table\": {\n\t\t\t\"library\": \"SASHELP\",\n\t\t\t\"table\": \"HOMEEQUITY\"\n\t\t},\n\t\t\"varlist\": [],\n\t\t\"numRows\": 20,\n\t\t\"selection\": {\n\t\t\t\"value\": \"FIRST\",\n\t\t\t\"label\": \"First N rows\"\n\t\t},\n\t\t\"rsMethod\": {\n\t\t\t\"value\": \"SRS\",\n\t\t\t\"label\": \"Simple random sample (without replacement)\"\n\t\t}\n\t}\n}","templates":{"SAS":"/* Selection options are FIRST (first rows) or RANDOM (random sample) */\n\n/* GET TOTAL ROW COUNT FROM TABLE */\n\t\n\tproc sql noprint;\n\t select count(*) format=comma15. into :N from &table;\n\tquit;\n\n/* SELECT FIRST &numRows ROWS */\n%if &selection=FIRST %then %do;\n\ttitle1 color=\"#545B66\" \"Sample from &table\";\n\ttitle2 height=3 \"First &numRows of &N Rows\";\n\tdata sample;\n\t set &table(obs=&numRows keep=&varlist);\n\trun;\n%end;\n\n/* SELECT RANDOM SAMPLE OF &numRows ROWS */\n\n%else %do;\n\ttitle1 color=\"#545B66\" \"Sample from &table\";\n\ttitle2 height=3 \"Random Sample &numRows of &N Rows\";\n\t\n\tproc surveyselect data=&table(keep=&varlist) \n\t method=&rsMethod n=&numRows\n\t out=sample noprint;\n\trun; \n%end; \n\n/* PRINT SAMPLE */\n\n\tfootnote height=3 \"Created %sysfunc(today(),nldatew.) at %sysfunc(time(), nltime.)\";\n\tproc print data=sample noobs;\n\trun;\n\ttitle;\n\tfootnote;\n/* SAS templated code goes here */"}} 2 | -------------------------------------------------------------------------------- /PrintSample.sas: -------------------------------------------------------------------------------- 1 | /* Selection options are FIRST (first rows) or RANDOM (random sample) */ 2 | %let selection=FIRST; 3 | 4 | /* GET TOTAL ROW COUNT FROM TABLE */ 5 | 6 | proc sql noprint; 7 | select count(*) format=comma15. into :N from sashelp.homeequity; 8 | quit; 9 | 10 | /* SELECT FIRST 20 ROWS */ 11 | %if &selection=FIRST %then %do; 12 | title1 color="#545B66" "Sample from SASHELP.HOMEEQUITY"; 13 | title2 height=3 "First 20 of &N Rows"; 14 | data sample; 15 | set sashelp.homeequity(obs=20 keep=Bad Loan MortDue Value); 16 | run; 17 | %end; 18 | 19 | /* SELECT RANDOM SAMPLE OF 20 ROWS */ 20 | 21 | %else %do; 22 | title1 color="#545B66" "Sample from SASHELP.HOMEEQUITY"; 23 | title2 height=3 "Random Sample 20 of &N Rows"; 24 | 25 | proc surveyselect data=sashelp.homeequity(keep=Bad Loan MortDue Value) 26 | method=srs n=20 27 | out=sample noprint; 28 | run; 29 | %end; 30 | 31 | /* PRINT SAMPLE */ 32 | 33 | footnote height=3 "Created %sysfunc(today(),nldatew.) at %sysfunc(time(), nltime.)"; 34 | proc print data=sample noobs; 35 | run; 36 | title; 37 | footnote; 38 | 39 | /* END */ 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SAS Viya Quick Start Videos and Supporting Files 2 | 3 | ## Overview 4 | 5 | [The SAS Viya Quick Start video series](https://video.sas.com/category/videos/sas-viya-quick-start) provides tutorials for many of the SAS Viya applications. The videos are designed to allow users to follow along in the software to enhance their learning experience. This repository provides the files referenced in the videos so that you can configure your environment to follow along. 6 | 7 | ### Quick Start Video Series 8 | 9 | The following videos are included in the Quick Start series: 10 | - [SAS Viya and the Analytics Life Cycle](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6325462141112/sas-viya-and-the-analytics-life-cycle?autoStart=true) 11 | - [Discover Information Assets with SAS Information Catalog](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6326134225112/discover-information-assets-with-sas-information-catalog?autoStart=true) 12 | - [Manage Data with SAS Data Explorer](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6332731378112/manage-data-with-sas-data-explorer?autoStart=true) 13 | - [Explore and Visualize Data with SAS Visual Analytics](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6323595794112/explore-and-visualize-data-with-sas-visual-analytics?autoStart=true) 14 | - [Develop SAS Code with SAS Studio](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6325460656112/develop-sas-code-with-sas-studio?autoStart=true) 15 | - [Build Flows with SAS Studio](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6325462242112/build-flows-with-sas-studio?autoStart=true) 16 | - [Create Custom Steps with SAS Studio](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6347011003112/create-custom-steps-with-sas-studio?autoStart=true) 17 | - [Git Integration with SAS Studio](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6358959868112/git-integration-with-sas-studio?autoStart=true) 18 | - [Build Models with SAS Model Studio](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6326334754112/build-models-with-sas-model-studio?autoStart=true) 19 | - [Manage Models with SAS Model Manager](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6326134528112/manage-models-with-sas-model-manager?autoStart=true) 20 | - [Build Decisions with SAS Intelligent Decisioning](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6364412742112/build-decisions-with-sas-intelligent-decisioning?autoStart=true) 21 | - [Accelerate Code in SAS Cloud Analytic Services](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6326133063112/accelerate-code-with-sas-cloud-analytic-services?autoStart=true) 22 | - [Share and Collaborate with SAS Drive](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6332187252112/share-and-collaborate-with-sas-drive?autoStart=true) 23 | - [Use Python Code with SAS Studio](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6332185094112/use-python-code-in-sas-studio?autoStart=true) 24 | - [Use the Python SWAT Package on the SAS Viya Platform](https://video.sas.com/detail/videos/sas-viya-quick-start/video/6332198984112/use-the-python-swat-package-on-the-sas-viya-platform?autoStart=true) 25 | 26 | ### Installation 27 | 28 | 1. Visit https://github.com/sassoftware/sas-viya-quick-start and click **Code** > **Download ZIP**. 29 | 2. Unzip the files to your local machine. By default, the files will be in a folder named **sas-viya-quick-start-main**. 30 | 3. In SAS Viya, select the Applications menu in the upper left corner and select **Develop Code and Flows**. SAS Studio launches. 31 | 4. In the Navigation pane on the left, select the **Explorer** icon. 32 | 5. Expand ![image](https://github.com/sassoftware/sas-viya-quick-start/assets/22669486/d8c5b592-25ba-4b81-9e9e-795cb5efcee2). Navigate to your preferred location for storing the files. You must have write access. Right-click on the desired folder and select **New folder**. Name the folder **quick-start**. 33 | * Your environment may have a different label other than **Files**, but the icon will look the same. 34 | * If you create the **quick-start** folder under **SAS Content** rather than **Files**, the SAS programs will not run successfully. 35 | * The file location demonstrated in the videos is **Files** > **data** > **quick-start**. 36 | 6. Select the new **quick-start** folder and click the **Upload** button. 37 | 7. Click **Add**, then navigate to the files you unzipped on your local machine. Press **Ctrl+A** to select all the files, then click **Open** > **Upload**. 38 | 8. In the Explorer, expand the **quick-start** folder and double-click the **_Load_Quick_Start_Data.sas** program to open it. 39 | 9. Do not make any changes to the code. Click **Run**. Confirm the **HOME_EQUITY** and **CUSTOMER** tables are listed in the Table Information report. 40 | NOTE: As you follow along in your environment, the **HOME_EQUITY** and **CUSTOMER** tables will be in the **Casuser** caslib. 41 | 42 | ## Contributing 43 | 44 | We do not accept contributions for this project. 45 | 46 | ## License 47 | 48 | This project is licensed under the [Apache 2.0 License](LICENSE). 49 | 50 | ## Additional Resources 51 | 52 | **Required**. Include any additional resources that users may need or find useful when using your software. Additional resources might include the following: 53 | 54 | * *Link to videos on SAS Video Portal (once posted)* 55 | * [SAS Viya Community](https://communities.sas.com/t5/SAS-Viya/ct-p/viya) 56 | * [SAS Viya Learning and Support](https://support.sas.com/en/software/sas-viya.html) 57 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | ## Support 2 | 3 | We use GitHub for tracking bugs and feature requests. Please submit a GitHub issue or pull request for support. -------------------------------------------------------------------------------- /Score_HOME_EQUITY.txt: -------------------------------------------------------------------------------- 1 | ## Copyright © 2022, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. 2 | ## SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | import pickle 6 | import numpy as np 7 | import pandas as pd 8 | 9 | with open(settings.pickle_path + dm_pklname, 'rb') as f: 10 | imputer = pickle.load(f) 11 | ohe = pickle.load(f) 12 | model = pickle.load(f) 13 | 14 | def score_method(DELINQ, DEROG, JOB, NINQ, REASON, CLAGE, CLNO, DEBTINC, LOAN, MORTDUE, VALUE, YOJ): 15 | "Output: P_BAD0, P_BAD1, I_BAD" 16 | record = pd.DataFrame([[DELINQ, DEROG, JOB, NINQ, REASON, CLAGE, CLNO, DEBTINC, LOAN, MORTDUE, VALUE, YOJ]],\ 17 | columns=['DELINQ', 'DEROG', 'JOB', 'NINQ', 'REASON', 'CLAGE', 'CLNO', 'DEBTINC', 'LOAN', 'MORTDUE', 'VALUE', 'YOJ']) 18 | 19 | dm_class_input = ["DELINQ", "DEROG", "JOB", "NINQ", "REASON"] 20 | dm_interval_input = ["CLAGE", "CLNO", "DEBTINC", "LOAN", "MORTDUE", "VALUE", "YOJ"] 21 | 22 | rec_intv = record[dm_interval_input] 23 | rec_intv_imp = imputer.transform(rec_intv) 24 | 25 | rec_class = record[dm_class_input].applymap(str) 26 | rec_class_ohe = ohe.transform(rec_class).toarray() 27 | 28 | rec = np.concatenate((rec_intv_imp, rec_class_ohe), axis=1) 29 | rec_pred_prob = model.predict_proba(rec) 30 | rec_pred = model.predict(rec) 31 | 32 | return float(rec_pred_prob[0][0]), float(rec_pred_prob[0][1]), float(rec_pred[0]) 33 | -------------------------------------------------------------------------------- /Train_HOME_EQUITY.txt: -------------------------------------------------------------------------------- 1 | ## Copyright © 2022, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. 2 | ## SPDX-License-Identifier: Apache-2.0 3 | 4 | import numpy as np 5 | from sklearn.impute import SimpleImputer 6 | from sklearn.preprocessing import OneHotEncoder 7 | from sklearn import ensemble 8 | import pickle 9 | 10 | # Enable compact pritning of numpy arrays 11 | np.set_printoptions(suppress=True, precision=2) 12 | 13 | #---------- 14 | # Prepare data for training 15 | #---------- 16 | # Get interval inputs 17 | trainX_intv = dm_traindf[dm_interval_input] 18 | # Get class inputs, convert data to str (missing becomes nan str) 19 | trainX_class = dm_traindf[dm_class_input].applymap(str) 20 | 21 | # Impute interval missing values to median 22 | intv_imputer = SimpleImputer(strategy='median') 23 | intv_imputer = intv_imputer.fit(trainX_intv) 24 | trainX_intv_imp = intv_imputer.transform(trainX_intv) 25 | 26 | # One-hot encode class inputs, unknown levels are set to all 0s 27 | class_ohe = OneHotEncoder(handle_unknown="ignore") 28 | class_ohe = class_ohe.fit(trainX_class) 29 | trainX_class_ohe = class_ohe.transform(trainX_class).toarray() 30 | 31 | # Concatenate interval and class input arrays 32 | trainX = np.concatenate((trainX_intv_imp, trainX_class_ohe), axis=1) 33 | trainy = dm_traindf[dm_dec_target] 34 | #print(trainX) 35 | #print(trainy) 36 | 37 | #---------- 38 | # Train a model 39 | #---------- 40 | # Fit Random Forest model w/ training data 41 | params = {'n_estimators': 100, 'max_depth': 20, 'min_samples_leaf': 5} 42 | dm_model = ensemble.RandomForestClassifier(**params) 43 | dm_model.fit(trainX, trainy) 44 | #print(dm_model) 45 | 46 | #---------- 47 | # Create dm_scoreddf 48 | #---------- 49 | fullX_intv = dm_inputdf[dm_interval_input] 50 | fullX_intv_imp = intv_imputer.transform(fullX_intv) 51 | 52 | fullX_class = dm_inputdf[dm_class_input].applymap(str) 53 | fullX_class_ohe = class_ohe.transform(fullX_class).toarray() 54 | 55 | fullX = np.concatenate((fullX_intv_imp, fullX_class_ohe), axis=1) 56 | 57 | # Score full data: posterior probabilities 58 | dm_scoreddf_prob = pd.DataFrame(dm_model.predict_proba(fullX), columns=dm_predictionvar) 59 | 60 | # Score full data: class prediction 61 | dm_scoreddf_class = pd.DataFrame(dm_model.predict(fullX), columns=[dm_classtarget_intovar]) 62 | 63 | # Column merge posterior probabilities and class prediction 64 | dm_scoreddf = pd.concat([dm_scoreddf_prob, dm_scoreddf_class], axis=1) 65 | print('***** 5 rows from dm_scoreddf *****') 66 | print(dm_scoreddf.head(5)) 67 | print(dm_input) 68 | print(', '.join(dm_input)) 69 | 70 | #---------- 71 | # Results 72 | #---------- 73 | # Save VariableImportance to CSV 74 | full_input_vars = dm_interval_input + list(class_ohe.get_feature_names_out()) 75 | varimp = pd.DataFrame(list(zip(full_input_vars, dm_model.feature_importances_)), columns=['Variable Name', 'Importance']) 76 | varimp.to_csv(dm_nodedir + '/rpt_var_imp.csv', index=False) 77 | 78 | #---------- 79 | # Build composite pickle file 80 | #---------- 81 | with open(dm_pklpath, 'wb') as f: 82 | pickle.dump(intv_imputer, f) 83 | pickle.dump(class_ohe, f) 84 | pickle.dump(dm_model, f) 85 | -------------------------------------------------------------------------------- /Use the Python SWAT Package on the SAS Viya Platform.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Use the Python SWAT Package on the SAS Viya Platform" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import swat\n", 17 | "import pandas as pd\n", 18 | "import numpy as np\n", 19 | "import os\n", 20 | "import sys\n", 21 | "import warnings\n", 22 | "warnings.filterwarnings(\"ignore\")\n", 23 | "pd.set_option('display.max_columns', None)\n", 24 | "\n", 25 | "print(f'Python version:{sys.version.split(\"|\")[0]}')\n", 26 | "print(f'swat version:{swat.__version__}')\n", 27 | "print(f'pandas version:{pd.__version__}')\n", 28 | "print(f'numpy version:{np.__version__}')" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "## 1. Connect to the CAS Server\n", 36 | "**To connect to the CAS server, you need:**\n", 37 | "- the host name, \n", 38 | "- the port number, \n", 39 | "- authentication\n", 40 | "\n", 41 | "**Be aware that connecting to the CAS server can be implemented in various ways, so you might need to see your system administrator about how to make a connection. Please follow company policy regarding authentication.**" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "######## SAS VIYA ON AZURE MARKETPLACE CONNECTION #################################################\n", 51 | "casport = 5570\n", 52 | "cashost = 'sas-cas-server-default-client'\n", 53 | "conn = swat.CAS(cashost, casport, password=os.environ.get('ACCESS_TOKEN'))\n", 54 | "###################################################################################################\n", 55 | "\n", 56 | "######## EXTERNAL JUPYTERHUB ACCESS USING BINARY PROTOCOL###################\n", 57 | "#cashost =''\n", 58 | "#conn = swat.CAS(cashost, casport, '<##user##>', '<##password##>')\n", 59 | "############################################################################\n", 60 | "\n", 61 | "#######################EXTERNAL JUPYTERHUB ACCESS USING HTTP PROTOCOL ##############################################################################\n", 62 | "#conn = swat.CAS('https://<##prefix##>.<##region##>.cloudapp.azure.com/cas-shared-default-http', username='<##user##>', password ='<##password##>')\n", 63 | "####################################################################################################################################################" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": null, 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [ 72 | "type(conn)" 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "metadata": {}, 78 | "source": [ 79 | "Test the CAS connection and view the SAS Viya version." 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "metadata": {}, 86 | "outputs": [], 87 | "source": [ 88 | "conn.about()['About']['Viya Version']" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": {}, 94 | "source": [ 95 | "## 2. Explore the Available Data on the CAS Server " 96 | ] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "### a. View Available Caslibs" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": null, 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [ 111 | "conn.caslibInfo()" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "### b. View Available Data Source Files" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "conn.fileInfo(caslib = 'samples')" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": null, 133 | "metadata": {}, 134 | "outputs": [], 135 | "source": [ 136 | "conn.fileInfo(caslib = 'casuser')" 137 | ] 138 | }, 139 | { 140 | "cell_type": "markdown", 141 | "metadata": {}, 142 | "source": [ 143 | "### c. View Available CAS Tables" 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": null, 149 | "metadata": {}, 150 | "outputs": [], 151 | "source": [ 152 | "conn.tableInfo(caslib = 'samples')" 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": null, 158 | "metadata": {}, 159 | "outputs": [], 160 | "source": [ 161 | "conn.tableInfo(caslib = 'casuser')" 162 | ] 163 | }, 164 | { 165 | "cell_type": "markdown", 166 | "metadata": {}, 167 | "source": [ 168 | "## 3. Load Data into Memory on the CAS Server (Client Side)" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": null, 174 | "metadata": {}, 175 | "outputs": [], 176 | "source": [ 177 | "conn.read_csv(r'https://support.sas.com/documentation/onlinedoc/viya/exampledatasets/home_equity.csv', ## Client-side file to load into memory\n", 178 | " casout = {'name':'home_equity', ## Output in-memory CAS table information\n", 179 | " 'caslib':'casuser', \n", 180 | " 'replace':True})" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": null, 186 | "metadata": {}, 187 | "outputs": [], 188 | "source": [ 189 | "conn.tableInfo(caslib = 'casuser')" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": {}, 195 | "source": [ 196 | "## 4. Explore the CAS Table" 197 | ] 198 | }, 199 | { 200 | "cell_type": "markdown", 201 | "metadata": {}, 202 | "source": [ 203 | "### a. Reference the CAS table" 204 | ] 205 | }, 206 | { 207 | "cell_type": "code", 208 | "execution_count": null, 209 | "metadata": {}, 210 | "outputs": [], 211 | "source": [ 212 | "castbl = conn.CASTable('home_equity', caslib = 'casuser')\n", 213 | "\n", 214 | "display(type(castbl), castbl)" 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "execution_count": null, 220 | "metadata": {}, 221 | "outputs": [], 222 | "source": [ 223 | "castbl.tableDetails()" 224 | ] 225 | }, 226 | { 227 | "cell_type": "markdown", 228 | "metadata": {}, 229 | "source": [ 230 | "### b. Preview the CAS Table" 231 | ] 232 | }, 233 | { 234 | "cell_type": "markdown", 235 | "metadata": {}, 236 | "source": [ 237 | "You can execute the SWAT head method on a CASTable object to return five rows to your Python client. The head method executes in the CAS server, and the CAS server returns five rows to the Python client as a SASDataFrame object." 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": null, 243 | "metadata": {}, 244 | "outputs": [], 245 | "source": [ 246 | "df = castbl.head()\n", 247 | "\n", 248 | "display(type(df), df)" 249 | ] 250 | }, 251 | { 252 | "cell_type": "markdown", 253 | "metadata": {}, 254 | "source": [ 255 | "### c. Basic CAS Table Exploration" 256 | ] 257 | }, 258 | { 259 | "cell_type": "markdown", 260 | "metadata": {}, 261 | "source": [ 262 | "View the number of rows and columns in a CAS table." 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": null, 268 | "metadata": {}, 269 | "outputs": [], 270 | "source": [ 271 | "castbl.shape" 272 | ] 273 | }, 274 | { 275 | "cell_type": "markdown", 276 | "metadata": {}, 277 | "source": [ 278 | "Show CAS table column information." 279 | ] 280 | }, 281 | { 282 | "cell_type": "code", 283 | "execution_count": null, 284 | "metadata": {}, 285 | "outputs": [], 286 | "source": [ 287 | "castbl.columnInfo()" 288 | ] 289 | }, 290 | { 291 | "cell_type": "markdown", 292 | "metadata": {}, 293 | "source": [ 294 | "Find the count of unique values in a CAS table using the SWAT package value_counts method. The CAS server summarizes the data and return a series to the Python client." 295 | ] 296 | }, 297 | { 298 | "cell_type": "code", 299 | "execution_count": null, 300 | "metadata": {}, 301 | "outputs": [], 302 | "source": [ 303 | "df = (castbl ## CAS table\n", 304 | " .JOB ## CAS table column\n", 305 | " .value_counts() ## SWAT package value_counts method\n", 306 | ")\n", 307 | "\n", 308 | "\n", 309 | "## Display the type and value of the df object\n", 310 | "display(type(df), df)\n", 311 | "\n", 312 | "\n", 313 | "## Plot the Series on the Python client using Pandas\n", 314 | "df.plot(kind='bar', figsize=(8,6));" 315 | ] 316 | }, 317 | { 318 | "cell_type": "markdown", 319 | "metadata": {}, 320 | "source": [ 321 | "### d. Execute SQL in the CAS Server" 322 | ] 323 | }, 324 | { 325 | "cell_type": "code", 326 | "execution_count": null, 327 | "metadata": {}, 328 | "outputs": [], 329 | "source": [ 330 | "## Load the fedSQL action set to execute SQL in CAS.\n", 331 | "conn.loadActionSet('fedSQL')\n", 332 | "\n", 333 | "## Store a simple SQL query\n", 334 | "myQuery = '''\n", 335 | " select Reason, count(*) as TotalCount\n", 336 | " from casuser.home_equity\n", 337 | " group by Reason\n", 338 | " order by TotalCount desc\n", 339 | "'''\n", 340 | "\n", 341 | "## Execute the query in the CAS server\n", 342 | "cr = conn.execDirect(query = myQuery)\n", 343 | "\n", 344 | "display(type(cr), cr)" 345 | ] 346 | }, 347 | { 348 | "cell_type": "code", 349 | "execution_count": null, 350 | "metadata": {}, 351 | "outputs": [], 352 | "source": [ 353 | "cr['Result Set']" 354 | ] 355 | }, 356 | { 357 | "cell_type": "markdown", 358 | "metadata": {}, 359 | "source": [ 360 | "## 5. Prepre the CAS Table" 361 | ] 362 | }, 363 | { 364 | "cell_type": "code", 365 | "execution_count": null, 366 | "metadata": {}, 367 | "outputs": [], 368 | "source": [ 369 | "castbl.head()" 370 | ] 371 | }, 372 | { 373 | "cell_type": "markdown", 374 | "metadata": {}, 375 | "source": [ 376 | "### a. Create CAS Table Columns" 377 | ] 378 | }, 379 | { 380 | "cell_type": "markdown", 381 | "metadata": {}, 382 | "source": [ 383 | "Create two new columns in the CAS table." 384 | ] 385 | }, 386 | { 387 | "cell_type": "code", 388 | "execution_count": null, 389 | "metadata": {}, 390 | "outputs": [], 391 | "source": [ 392 | "castbl.eval('DIFF = VALUE - MORTDUE')\n", 393 | "castbl.eval(\"LOAN_STATUS = ifc(BAD=0,'Paid','Default')\")" 394 | ] 395 | }, 396 | { 397 | "cell_type": "markdown", 398 | "metadata": {}, 399 | "source": [ 400 | "View the CASTable object." 401 | ] 402 | }, 403 | { 404 | "cell_type": "code", 405 | "execution_count": null, 406 | "metadata": {}, 407 | "outputs": [], 408 | "source": [ 409 | "display(castbl)" 410 | ] 411 | }, 412 | { 413 | "cell_type": "code", 414 | "execution_count": null, 415 | "metadata": {}, 416 | "outputs": [], 417 | "source": [ 418 | "castbl.params" 419 | ] 420 | }, 421 | { 422 | "cell_type": "markdown", 423 | "metadata": {}, 424 | "source": [ 425 | "Execute the head method on the CASTable object. Notice that the new columns were created." 426 | ] 427 | }, 428 | { 429 | "cell_type": "code", 430 | "execution_count": null, 431 | "metadata": {}, 432 | "outputs": [], 433 | "source": [ 434 | "castbl.head()" 435 | ] 436 | }, 437 | { 438 | "cell_type": "markdown", 439 | "metadata": {}, 440 | "source": [ 441 | "### b. Create a New CAS Table" 442 | ] 443 | }, 444 | { 445 | "cell_type": "markdown", 446 | "metadata": {}, 447 | "source": [ 448 | "Create a new CAS table that contains the two new columns from above." 449 | ] 450 | }, 451 | { 452 | "cell_type": "code", 453 | "execution_count": null, 454 | "metadata": {}, 455 | "outputs": [], 456 | "source": [ 457 | "castbl.copyTable(casout={'name':'home_equity_final', \n", 458 | " 'caslib':'casuser', \n", 459 | " 'label':'home_equity with two new calculated columns'})" 460 | ] 461 | }, 462 | { 463 | "cell_type": "markdown", 464 | "metadata": {}, 465 | "source": [ 466 | "Confirm that the table is available." 467 | ] 468 | }, 469 | { 470 | "cell_type": "code", 471 | "execution_count": null, 472 | "metadata": {}, 473 | "outputs": [], 474 | "source": [ 475 | "conn.tableInfo(caslib = 'casuser')" 476 | ] 477 | }, 478 | { 479 | "cell_type": "markdown", 480 | "metadata": {}, 481 | "source": [ 482 | "Reference and preview the new **HOME_EQUITY_FINAL** CAS table." 483 | ] 484 | }, 485 | { 486 | "cell_type": "code", 487 | "execution_count": null, 488 | "metadata": {}, 489 | "outputs": [], 490 | "source": [ 491 | "final_castbl = conn.CASTable('HOME_EQUITY_FINAL', caslib = 'casuser')\n", 492 | "final_castbl.head()" 493 | ] 494 | }, 495 | { 496 | "cell_type": "markdown", 497 | "metadata": {}, 498 | "source": [ 499 | "### c. Save the CAS Table to the Data Source\n", 500 | "Save a CAS table to a caslib's data source. This is simalar to saving a DataFrame back to disk using a to_ method in pandas." 501 | ] 502 | }, 503 | { 504 | "cell_type": "code", 505 | "execution_count": null, 506 | "metadata": {}, 507 | "outputs": [], 508 | "source": [ 509 | "save_file_types = ['parquet', 'sashdat', 'csv']\n", 510 | "\n", 511 | "for ftype in save_file_types:\n", 512 | " final_castbl.save(name = f'home_equity_final.{ftype}', caslib = 'casuser')" 513 | ] 514 | }, 515 | { 516 | "cell_type": "markdown", 517 | "metadata": {}, 518 | "source": [ 519 | "View the newly saved files in the **Casuser** caslib." 520 | ] 521 | }, 522 | { 523 | "cell_type": "code", 524 | "execution_count": null, 525 | "metadata": {}, 526 | "outputs": [], 527 | "source": [ 528 | "conn.fileInfo(caslib = 'casuser')" 529 | ] 530 | }, 531 | { 532 | "cell_type": "markdown", 533 | "metadata": {}, 534 | "source": [ 535 | "## 6. Session-Scope versus Global-Scope Tables\n", 536 | "By default, when you load a table into memory, the table has session scope. This means that the table is available only to the session that it was created in. For ad hoc data access and analysis, session-scope tables are preferred because session-scope tables do not require access control checks or any form of locking for concurrent access.\n", 537 | "\n", 538 | "The only disadvantage to a session-scope table is that no other sessions can access the same table. For example, if you want shared access to a single copy of an in-memory table, then a session-scope table does not work. In that case, a global-scope table can provide the shared access.\n", 539 | "\n", 540 | "**Session-scope tables**\n", 541 | "- Best used for general purpose programming.\n", 542 | "- Typically provide better performance than global-scope tables because concurrency locks are not used.\n", 543 | "\n", 544 | "**Global-scope tables**\n", 545 | "- Best used for tables that are accessed by a large number of users, especially other SAS Viya visual interfaces.\n", 546 | "- A global-scope table cannot be replaced. You must drop it and load the replacement data." 547 | ] 548 | }, 549 | { 550 | "cell_type": "markdown", 551 | "metadata": {}, 552 | "source": [ 553 | "### a. Session-Scope Tables" 554 | ] 555 | }, 556 | { 557 | "cell_type": "code", 558 | "execution_count": null, 559 | "metadata": {}, 560 | "outputs": [], 561 | "source": [ 562 | "conn.tableInfo(caslib = 'casuser')" 563 | ] 564 | }, 565 | { 566 | "cell_type": "markdown", 567 | "metadata": {}, 568 | "source": [ 569 | "View the data source files in the **Casuser** caslib. Notice the parquet file is available." 570 | ] 571 | }, 572 | { 573 | "cell_type": "code", 574 | "execution_count": null, 575 | "metadata": {}, 576 | "outputs": [], 577 | "source": [ 578 | "conn.fileInfo(caslib = 'casuser')" 579 | ] 580 | }, 581 | { 582 | "cell_type": "markdown", 583 | "metadata": {}, 584 | "source": [ 585 | "### b. Global-Scope Tables" 586 | ] 587 | }, 588 | { 589 | "cell_type": "markdown", 590 | "metadata": {}, 591 | "source": [ 592 | "Load the server side parquet file into memory and promote it to global scope. This enables other SAS Viya applications and users who have access to the caslib to access the CAS table." 593 | ] 594 | }, 595 | { 596 | "cell_type": "code", 597 | "execution_count": null, 598 | "metadata": {}, 599 | "outputs": [], 600 | "source": [ 601 | "conn.loadTable(path = 'home_equity_final.parquet', caslib = 'casuser', ## Input file to load into memory\n", 602 | " casout = {'name':'home_equity_final_global', ## Output CAS table information\n", 603 | " 'caslib':'casuser', \n", 604 | " 'promote':True}) " 605 | ] 606 | }, 607 | { 608 | "cell_type": "markdown", 609 | "metadata": {}, 610 | "source": [ 611 | "View available CAS tables. Notice that the Global value is 1." 612 | ] 613 | }, 614 | { 615 | "cell_type": "code", 616 | "execution_count": null, 617 | "metadata": {}, 618 | "outputs": [], 619 | "source": [ 620 | "conn.tableInfo(caslib = 'casuser')" 621 | ] 622 | }, 623 | { 624 | "cell_type": "markdown", 625 | "metadata": {}, 626 | "source": [ 627 | "### c. Open SAS Visual Analytics and Access the CAS Table" 628 | ] 629 | }, 630 | { 631 | "cell_type": "markdown", 632 | "metadata": {}, 633 | "source": [ 634 | "View available CAS tables in SAS Visual Analytics." 635 | ] 636 | }, 637 | { 638 | "cell_type": "markdown", 639 | "metadata": {}, 640 | "source": [ 641 | "### d. Drop a Global-Scope Table" 642 | ] 643 | }, 644 | { 645 | "cell_type": "code", 646 | "execution_count": null, 647 | "metadata": {}, 648 | "outputs": [], 649 | "source": [ 650 | "# ## Terminate the connection to the CAS server\n", 651 | "conn.terminate()\n", 652 | "\n", 653 | "## Reconnect to the CAS server\n", 654 | "conn = swat.CAS(cashost, casport, password=os.environ.get('ACCESS_TOKEN'))\n", 655 | "\n", 656 | "## View available CAS tables in the Casuser caslib\n", 657 | "conn.tableInfo(caslib = 'casuser')" 658 | ] 659 | }, 660 | { 661 | "cell_type": "markdown", 662 | "metadata": {}, 663 | "source": [ 664 | "Drop a CAS table." 665 | ] 666 | }, 667 | { 668 | "cell_type": "code", 669 | "execution_count": null, 670 | "metadata": {}, 671 | "outputs": [], 672 | "source": [ 673 | "conn.dropTable('home_equity_final_global', caslib = 'casuser')" 674 | ] 675 | }, 676 | { 677 | "cell_type": "markdown", 678 | "metadata": {}, 679 | "source": [ 680 | "### e. Delete a Data Source File" 681 | ] 682 | }, 683 | { 684 | "cell_type": "code", 685 | "execution_count": null, 686 | "metadata": {}, 687 | "outputs": [], 688 | "source": [ 689 | "deleteDataSourceFiles = ['home_equity_final.parquet', 'home_equity_final.sashdat', 'home_equity_final.csv']\n", 690 | "\n", 691 | "for file in deleteDataSourceFiles:\n", 692 | " conn.deleteSource(source = file, caslib = 'casuser')" 693 | ] 694 | }, 695 | { 696 | "cell_type": "markdown", 697 | "metadata": {}, 698 | "source": [ 699 | "## 7. Terminate the CAS Connection\n", 700 | "When you are done, it's best practice to terminate your CAS connection." 701 | ] 702 | }, 703 | { 704 | "cell_type": "code", 705 | "execution_count": null, 706 | "metadata": {}, 707 | "outputs": [], 708 | "source": [ 709 | "conn.terminate()" 710 | ] 711 | }, 712 | { 713 | "cell_type": "markdown", 714 | "metadata": {}, 715 | "source": [ 716 | " " 717 | ] 718 | } 719 | ], 720 | "metadata": { 721 | "kernelspec": { 722 | "display_name": "Python 3 (ipykernel)", 723 | "language": "python", 724 | "name": "python3" 725 | }, 726 | "language_info": { 727 | "codemirror_mode": { 728 | "name": "ipython", 729 | "version": 3 730 | }, 731 | "file_extension": ".py", 732 | "mimetype": "text/x-python", 733 | "name": "python", 734 | "nbconvert_exporter": "python", 735 | "pygments_lexer": "ipython3", 736 | "version": "3.8.16" 737 | } 738 | }, 739 | "nbformat": 4, 740 | "nbformat_minor": 4 741 | } 742 | -------------------------------------------------------------------------------- /_Load_Quick_Start_Data.sas: -------------------------------------------------------------------------------- 1 | /*******************************************************************************/ 2 | /* Copyright © 2022, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. */ 3 | /* SPDX-License-Identifier: Apache-2.0 */ 4 | /*******************************************************************************/ 5 | 6 | 7 | /*********************************************************/ 8 | /* Run this program to load the HOME_EQUITY and CUSTOMER */ 9 | /* table used the SAS Viya Quick Start Videos. */ 10 | /*********************************************************/ 11 | 12 | %macro loadQuickStart; 13 | /* Create copy of HOMEEQUITY in quick-start folder */ 14 | 15 | %let fileName = %scan(&_sasprogramfile,-1,'/'); 16 | %let path = %sysfunc(tranwrd(&_sasprogramfile, &fileName,)); 17 | libname outlib "&path"; 18 | 19 | %if %sysfunc(exist(sashelp.homeequity)) %then %do; 20 | %put NOTE: HOME_EQUITY in-memory table loaded from SASHELP.HOMEEQUITY; 21 | data outlib.home_equity work.home_equity; 22 | set sashelp.homeequity; 23 | run; 24 | %end; 25 | 26 | %else %do; 27 | 28 | %put NOTE: HOME_EQUITY in-memory table loaded from home_equity.csv; 29 | 30 | /* Import home_equity.csv and create HOMEEQUITY.sas7bdat in quick-start folder */ 31 | proc import file="&path/home_equity.csv" dbms=csv out=outlib.home_equity replace; 32 | guessingrows=5960; 33 | run; 34 | 35 | proc datasets lib=outlib memtype=data nolist; 36 | modify home_equity; 37 | label APPDATE="Loan Application Date" 38 | BAD="Loan Status" 39 | CITY="City" 40 | CLAGE="Age of Oldest Credit Line (months)" 41 | CLNO="Number of Credit Lines" 42 | DEBTINC="Debt to Income Ratio" 43 | DELINQ="Number of Delinquent Credit Lines" 44 | DEROG="Number of Derogatory Reports" 45 | DIVISION="Division" 46 | JOB="Job Category" 47 | LOAN="Amount of Loan Request" 48 | MORTDUE="Amount Due on Existing Mortgage" 49 | NINQ="Number of Recent Credit Inquiries" 50 | REASON="Loan Purpose" 51 | REGION="Region" 52 | STATE="State" 53 | VALUE="Value of Current Property" 54 | YOJ="Years at Present Job"; 55 | format APPDATE date9. 56 | CLAGE comma8.1 57 | LOAN MORTDUE VALUE dollar12. 58 | DEBTINC 8.1 59 | BAD CITY CLNO DELINQ DEROG DIVISION JOB NINQ REASON REGION STATE YOJ; 60 | attrib _all_ informat=; 61 | quit; 62 | proc copy out=work in=outlib; 63 | select home_equity; 64 | run; 65 | 66 | %end; 67 | 68 | /* Import customer.csv and create CUSTOMER.sas7bdat in quick-start folder */ 69 | proc import file="&path/customer.csv" dbms=csv out=outlib.customer replace; 70 | guessingrows=10000; 71 | run; 72 | 73 | /* Load and promote HOME_EQUITY and CUSTOMER into memory in the CASUSER caslib. */ 74 | /* Save HOME_EQUITY.sashdat in the CASUSER caslib so it is saved on disk. */ 75 | 76 | cas mysession; 77 | proc casutil; 78 | droptable casdata="home_equity" incaslib="casuser" quiet; 79 | droptable casdata="customer" incaslib="casuser" quiet; 80 | droptable casdata="country_lookup" incaslib="casuser" quiet; 81 | 82 | load data=outlib.home_equity outcaslib="casuser" casout="home_equity" promote; 83 | load data=outlib.customer outcaslib="casuser" casout="customer" promote; 84 | load file="&path/country_lookup.csv" outcaslib="casuser" casout="country_lookup"; 85 | 86 | save casdata="home_equity" incaslib="casuser" casout="home_equity" outcaslib="casuser" replace; 87 | save casdata="customer" incaslib="casuser" casout="customer.parquet" outcaslib="casuser" replace; 88 | save casdata="country_lookup" incaslib="casuser" casout="country_lookup.csv" outcaslib="casuser" replace; 89 | 90 | droptable casdata="country_lookup" incaslib="casuser" quiet; 91 | 92 | list tables incaslib="casuser"; 93 | quit; 94 | cas mysession terminate; 95 | 96 | libname outlib clear; 97 | 98 | %mend loadQuickStart; 99 | 100 | %loadQuickStart -------------------------------------------------------------------------------- /country_lookup.csv: -------------------------------------------------------------------------------- 1 | Country_Key,Country_Name 2 | AD,Andorra 3 | AE,United Arab Emirates 4 | AF,Afghanistan 5 | AG,Antigua/Barbuda 6 | AI,Anguilla 7 | AL,Albania 8 | AM,Armenia 9 | AN,Netherlands Antilles 10 | AO,Angola 11 | AQ,Antarctica 12 | AR,Argentina 13 | AS,American Samoa 14 | AT,Austria 15 | AU,Australia 16 | AW,Aruba 17 | AZ,Azerbaijan 18 | BA,Bosnia/Herzegovina 19 | BB,Barbados 20 | BD,Bangladesh 21 | BE,Belgium 22 | BF,Burkina Faso 23 | BG,Bulgaria 24 | BH,Bahrain 25 | BI,Burundi 26 | BJ,Benin 27 | BM,Bermuda 28 | BN,Brunei 29 | BO,Bolivia 30 | BR,Brazil 31 | BS,Bahamas 32 | BT,Bhutan 33 | BV,Bouvet Island 34 | BW,Botswana 35 | BY,Belarus 36 | BZ,Belize 37 | CA,Canada 38 | CC,Cocos Islands 39 | CD,Congo 40 | CF,Central African Rep. 41 | CG,Congo 42 | CH,Switzerland 43 | CI,Ivory Coast 44 | CK,Cook Islands 45 | CL,Chile 46 | CM,Cameroon 47 | CN,China 48 | CO,Colombia 49 | CR,Costa Rica 50 | CU,Cuba 51 | CV,Cape Verde 52 | CX,Christmas Island 53 | CY,Cyprus 54 | CZ,Czech Republic 55 | DA,Germany 56 | DE,Germany 57 | DJ,Djibouti 58 | DK,Denmark 59 | DM,Dominica 60 | DO,Dominican Republic 61 | DZ,Algeria 62 | EC,Ecuador 63 | EE,Estonia 64 | EG,Egypt 65 | EH,Western Sahara 66 | ER,Eritrea 67 | ES,Spain 68 | ET,Ethiopia 69 | FI,Finland 70 | FJ,Fiji 71 | FK,Falkland Islands 72 | FM,Micronesia 73 | FO,Faroe Islands 74 | FR,France 75 | GA,Gabon 76 | GB,United Kingdom 77 | GD,Grenada 78 | GE,Georgia 79 | GF,French Guiana 80 | GH,Ghana 81 | GI,Gibraltar 82 | GL,Greenland 83 | GM,Gambia 84 | GN,Guinea 85 | GP,Guadeloupe 86 | GQ,Equatorial Guinea 87 | GR,Greece 88 | GT,Guatemala 89 | GU,Guam 90 | GW,Guinea-Bissau 91 | GY,Guyana 92 | HK,Hong Kong 93 | HM,Heard/Mcdonald 94 | HN,Honduras 95 | HR,Croatia 96 | HT,Haiti 97 | HU,Hungary 98 | ID,Indonesia 99 | IE,Ireland 100 | IL,Israel 101 | IN,India 102 | IO,British Indian Ocean 103 | IQ,Iraq 104 | IR,Iran 105 | IS,Iceland 106 | IT,Italy 107 | JM,Jamaica 108 | JO,Jordan 109 | JP,Japan 110 | KE,Kenya 111 | KG,Kyrgyzstan 112 | KH,Cambodia 113 | KI,Kiribati 114 | KM,Comoros 115 | KN,Saint Kitts/Nevis 116 | KP,"Korea, North" 117 | KR,"Korea, South" 118 | KW,Kuwait 119 | KY,Cayman Islands 120 | KZ,Kazakhstan 121 | LA,Laos 122 | LB,Lebanon 123 | LC,St. Lucia 124 | LI,Liechtenstein 125 | LK,Sri Lanka 126 | LR,Liberia 127 | LS,Lesotho 128 | LT,Lithuania 129 | LU,Luxembourg 130 | LV,Latvia 131 | LY,Libya 132 | MA,Morocco 133 | MC,Monaco 134 | MD,Moldova 135 | MG,Madagascar 136 | MH,Marshall Islands 137 | MK,Macedonia 138 | ML,Mali 139 | MM,Myanmar 140 | MN,Mongolia 141 | MO,Macau 142 | MP,Northern Mariana Islands 143 | MQ,Martinique 144 | MR,Mauritania 145 | MS,Montserrat 146 | MT,Malta 147 | MU,Mauritius 148 | MV,Maldives 149 | MW,Malawi 150 | MX,Mexico 151 | MY,Malaysia 152 | MZ,Mozambique 153 | NA,Namibia 154 | NC,New Caledonia 155 | NE,Niger 156 | NF,Norfolk Island 157 | NG,Nigeria 158 | NI,Nicaragua 159 | NL,Netherlands 160 | NO,Norway 161 | NP,Nepal 162 | NR,Nauru 163 | NU,Niue 164 | NZ,New Zealand 165 | OM,Oman 166 | PA,Panama 167 | PE,Peru 168 | PF,French Polynesia 169 | PG,Papua New Guinea 170 | PH,Philippines 171 | PK,Pakistan 172 | PL,Poland 173 | PM,St. Pierre/Miquelon 174 | PN,Pitcairn Islands 175 | PR,Puerto Rico 176 | PS,Gaza Strip 177 | PT,Portugal 178 | PW,Palau 179 | PY,Paraguay 180 | QA,Qatar 181 | RE,Reunion 182 | RO,Romania 183 | RU,Russia 184 | RW,Rwanda 185 | SA,Saudi Arabia 186 | SB,Solomon Islands 187 | SC,Seychelles 188 | SD,Sudan 189 | SE,Sweden 190 | SG,Singapore 191 | SH,St. Helena 192 | SI,Slovenia 193 | SJ,Svalbard 194 | SK,Slovakia 195 | SL,Sierra Leone 196 | SM,San Marino 197 | SN,Senegal 198 | SO,Somalia 199 | SR,Suriname 200 | ST,Sao Tome/Principe 201 | SV,El Salvador 202 | SY,Syria 203 | SZ,Swaziland 204 | TC,Turks/Caicos Islands 205 | TD,Chad 206 | TF,French Southern Terr. 207 | TG,Togo 208 | TH,Thailand 209 | TJ,Tajikistan 210 | TK,Tokelau 211 | TM,Turkmenistan 212 | TN,Tunisia 213 | TO,Tonga 214 | TP,East Timor 215 | TR,Turkey 216 | TT,Trinidad and Tobago 217 | TV,Tuvalu 218 | TW,Taiwan 219 | TZ,Tanzania 220 | UA,Ukraine 221 | UG,Uganda 222 | US,United States 223 | UY,Uruguay 224 | UZ,Uzbekistan 225 | VC,Saint Vincent/Grenadines 226 | VE,Venezuela 227 | VG,British Virgin Islands 228 | VI,Virgin Islands (U.S.) 229 | VN,Vietnam 230 | VU,Vanuatu 231 | WF,Wallis/Futuna Islands 232 | WS,Samoa 233 | XX,Zaire 234 | YE,Yemen 235 | YT,Mayotte 236 | YU,Yugoslavia 237 | ZA,South Africa 238 | ZM,Zambia 239 | ZW,Zimbabwe 240 | -------------------------------------------------------------------------------- /mortgage_rates.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sassoftware/sas-viya-quick-start/8f52dce9ba41bb330fdd035caa905113cc4a1f99/mortgage_rates.xlsx --------------------------------------------------------------------------------