본문 바로가기
Data_Analysis/SAS

[SAS] 자주 쓰는 기능 정리

by Classic! 2021. 9. 8.

들어가는 말

CSS 컨설팅 프로젝트로 SAS를 처음 접하는 팀원 분들이 많으실 듯합니다. 개인적으로는 SAS라는 프로그램이 최근 널리 사용되는 오픈소스 Python이나 R에 비해 생소할뿐더러, 인터넷에 관련 정보도 적어 공부하기 쉽지 않았습니다. 그리고 프로젝트 투입 전에는 프로젝트에 필요한 SAS 공부의 범위와 깊이를 가늠하지 못해 막막하기도 했습니다. 이후, 프로젝트를 하면서 '자주 쓰는 기능을 미리 알고 집중적으로 공부했더라면' 하는 아쉬움이 들었고, 이러한 부분을 정리하여 공유한다면 첫 프로젝트를 앞둔 컨설팅 팀원분들께 도움이 되지 않을까 하는 생각으로 글을 쓰게 되었습니다.

 

이번 글에서는 프로젝트에서 자주 쓰는 기능에 대한 간략한 설명과 함께, 프로젝트에서 언제, 어떻게 주로 사용하는지 덧붙였습니다. 세세하게 많은 내용을 담기보다, 꼭 필요한 내용을 소개하는 것에 초점을 두고 기술했습니다. 보다 자세한 설명과 예제는 SAS 튜토리얼 및 가이드를 참고 바랍니다.

 


 

[DATA STEP]

1. SET 

- 기존에 만든 테이블을 활용하여 새로운 테이블을 만들 때 사용합니다.

- SET 뒤에 2개 이상의 테이블명을 기재하면 테이블의 상하 결합하여 새로운 테이블을 생성합니다.

/* set : 테이블 수직 결합 */
DATA TEMP_TOT;
SET TEMP0 TEMP1 TEMP2 ;   /* TEMP0,TEMP1,TEMP2 테이블 이어 붙여 TEMP_TOT 테이블 생성 */
RUN;

SET

 

2. OBS

- 테이블의 행 수를 지정할 때 사용합니다.

- FIRSTOBS로 시작행을, OBS로 마지막 행을 지정하여 일부 행을 추출할 수 있습니다.   

- OBS는 대용량 데이터에 대한 로직을 작성할 때 유용합니다. 대용량 데이터 전체를 사용하여 로직을 작성하면 매 처리과정마다 코드의 결과를 확인하는데 시간이 오래 걸립니다. 이 때, OBS로 대용량 데이터에서 일부만 추출하여 로직을 작성하면 훨씬 빠르게 결과를 확인할 수 있습니다. 그리고 로직에 이상이 없다면 OBS를 지우고 전체 데이터에 로직을 한번에 실행하면 시간을 절약할 수 있습니다.

/* OBS 예시 */
DATA TEMP_TOT;
SET TEMP0(OBS=100);  /* TEMP0 테이블에서 100행까지만 불러오기 */
RUN;

/* OBS with firstobs */
DATA TEMP_TOT;
SET TEMP0(FIRSTOBS = 100 OBS=200);  /* TEMP0 테이블에서 100행부터 200행까지 불러오기 */
RUN;

 

3. KEEP

- 새로 생성하는 데이터 셋에 필요한 변수만 포함시켜 파일 크기를 줄이고, 효율적으로 데이터를 처리할 수 있습니다.

- 거꾸로 DROP 을 사용하여 불필요한 변수를 포함시키지 않는 방법도 있습니다.

/* KEEP : 특정 변수만 불러오기 */
DATA TEMP_TOT;
SET TEMP0(KEEP = COL1 COL2 COL3);
RUN;

/* SET 밖에 써도 동일한 결과 산출 */
DATA TEMP_TOT;
SET TEMP0;
KEEP COL1 COL2 COL3;
RUN;

 

4. WHERE

- 새로 생성하는 데이터 셋에 조건에 해당하는 행만 남깁니다.

- 또다른 조건문인 IF문과 함께 사용하는 경우, 코드 위치와 무관하게 WHERE 절이 우선 수행되고 IF절은 그다음으로 수행됩니다. 

/* where : 조건을 만족하는 행만 가져오기 */
DATA TEMP_TOT;
SET TEMP0(WHERE =(CO1 =1));   /* COL1의 값이 1인 행만 추출 */
RUN;

/* SET 밖에 써도 동일한 결과 산출 */
DATA TEMP_TOT;
SET TEMP0;
WHERE CO1 =1;
RUN;

 

 

[프로시저]

1. PROC CONTENTS

- PROC CONTENTS 프로시저는 테이블 길이, 변수 목록, 변수의 자료형 등의 정보를 출력합니다. 

- 주로 변수에 대한 정보 파악하는 데 사용하며, 아래 옵션을 함께 이용하면 편리합니다.

/* 기본 */
PROC CONTENTS DATA = SASHELP.HEART ; RUN ;

/*옵션 추가*/
PROC CONTENTS DATA = SASHELP.HEART POSITION VARNUM SHORT; RUN ;

 

PROC CONTENTS 옵션
VARNUM  컬럼 리스트 출력
POSITION  컬럼 리스트에서 컬럼 순서대로 출력
SHORT  변수 리스트, 인덱스 리스트 위주의 정보만 출력

 

2. PROC MEANS

- PROC MEANS 프로시저로 수치형 변수의 기술 통계량을 간단히 확인할 수 있습니다. 

- PROC MEANS 와 함께 PROC UNIVARIATE, PROC SUMMARY 도 변수의 값을 파악할 때 유용하게 씁니다. 

- 특정 기술 통계량의 옵션을 지정하여 사용자가 원하는 기술 통계량 값만 출력 가능합니다.

- 키워드를 지정하지 않으면 기본적인 5개 기술 통계량 (관측치 수, 평균, 표준편차, 최솟값, 최댓값) 제공합니다.

 

/* 통계량 옵션 미 지정 */ 
PROC MEANS DATA= BANKCHURN_REVOLV_NOT_ZERO; 
  /* Total_Revolving_Bal 변수의 기술 통계량을 Gender 별로 산출 */
  CLASS Gender; 
  VAR Total_Revolving_Bal; 
  OUTPUT OUT=MEANS_OF_Revolv; 
RUN;

 

VAR COL_1 : COL_1의 기술 통계량 산출합니다. (VAR _NUMERIC_ ; 로 쓰면 모든 수치형 변수에 대해  값 산출)  

CLASS COL_2 : COL_2의 값을 하나의 그룹으로, 각 그룹에 대한 COL_1의 기술 통계량을 산출.

 

예시) 성별에 따른 Total_Revolving_Bal의 기본통계량 산출

기본 통계량 출력

 

기술 통계량 옵션
N 개수
MEDIAN  중위수
MEAN  평균 
NMISS  결측값 수
CV  변동계수
P1 P5 P25 P50 P75 P95 P99 백분위 값(1% 5% 25% 50% 75% 95% 99%)
MIN 최소값
MAX 최대값
STD 표준편차
VAR  분산

 

3. PROC SQL

- RDBMS에서 사용하는 SQL을 SAS에서도 사용할 수 있도록 하는 프로시저입니다. 대부분의 데이터는 SQL로 처리(데이터 생성, 집계, 수정, 삭제 등)할 수 있어 가장 많이 쓰는 프로시저 중 하나입니다.

- SAS의 SQL도 ORACLE/MySQL 문법과 유사하나 차이점도 존재합니다. 가령, MySQL과 SAS SQL에서 DISTINCT 사용 방법이 다릅니다. SAS SQL에서는 SELECT 뒤에 DISTINCT 를 입력하면 추출하는 모든 행에 대해 중복인 행을 제거합니다. 중복을 제거할 특정 컬럼 앞에 DISTINCT를 쓰는 MySQL과 다릅니다. 

 

/* SAS SQL) DISTINCT : 모든 컬럼에 대해 중복제거 */
PROC SQL;
  CREATE TABLE TEMP AS
  SELECT DISTINCT 		/* SELECT 다음, 컬럼명 입력 전에 DISTINCT 입력 */
  고객번호, 결제일자
  FROM 고객카드정보
;QUIT;

 

- SQL에서 CASE WHEN 구문도 매우 자주 사용하니, 알아두시면 좋습니다.  조건에 맞는 케이스를 추출하여 집계 함수(SUM, COUNT, MAX 등)와 함께 쓰거나, 조건에 맞게 새로운 칼럼에 값을 설정할 수 있습니다.

/* CASE WHEN 구문 예시 1 : AMX/COUNT/SUM(CASE WHEN 조건 THEN 결과1 ELSE 결과2 END) */
PROC SQL;
CREATE TABLE TEMP AS 
SELECT DISTINCT 
     COL1
   , SUM(CASE WHEN TARGET = 1 THEN 1 ELSE 0 END)	AS 불량 
   , SUM(CASE WHEN TARGET = 0 THEN 1 ELSE 0 END)	AS 우량
FROM TEMP0
GROUP BY 1
;QUIT;


/* CASE WHEN 구문 예시 2 : CASE WHEN 조건1 THEN 결과1 
                                WHEN 조건2 THEN 결과2 
                                WHEN 조건3 THEN 결과3 ELSE 결과4 END */                 
PROC SQL;
CREATE TABLE TEMP AS 
SELECT 
     COL1
   , CASE WHEN		    사용금액 <= 0   THEN '미이용' 
   	  	  WHEN 0  < 사용금액 <= 10  THEN '저이용' 
   	  	  WHEN 10 < 사용금액 <= 150 THEN '일반이용' ELSE '우수이용' END) AS 이용고객분류
FROM TEMP0
;QUIT;

 

- SAS에서만 사용하는 함수 및 옵션 등을 SAS SQL에서 적용할 수 있습니다.

PROC SQL;
CREATE TABLE TEMP AS 
SELECT DISTINCT 
     고객번호
   , CATS(카드등록년월,'01')	/* CATS 함수 >> SAS에서만 쓰는 함수 */
   , COUNT(연체여부 = 'N')	 /* CASE WHEN 구문 대신 조건만 입력 */	
FROM 고객카드정보(WHERE =(AGE > 25))   /* WHERE =(조건) >> SAS 문법*/
GROUP BY 1,2
;QUIT;

** cats(문자열) : 문자열의 앞뒤 공백을 제거 후 문자열 결합

 

- 또한, COUNT 함수를 쓸 때 COUNT(변수명)은 결측값을 제외한 값을 집계하고, COUNT(*)는 결측값을 포함하여 행의 수를 집계하므로 각각 결과가 다름을 유의해야 합니다.

PROC SQL;
SEELECT 
      COUNT(*)     /*결측값 포함하여 행의 수 연산*/
    , COUNT(COL1)  /*결측값 제외하고 행의 수를 연산*/
FROM TEMP0
;QUIT;

 

- 전산에서도 SQL을 사용하므로 분석 코드도 SQL로 작성하면 전산요건정의서 작성 시 편리합니다.

- 다만, SQL은 비교적 처리 속도가 느려 대용량 데이터를 다룰 때는 DATA STEP이나 프로시저를 사용합니다.

 

4. PROC FREQ

- PROC FREQ 는 데이터 테이블의 빈도를 조회하는 프로시저입니다. 
- 아래와 같이 TABLES 다음에 입력한 각각의 변수에 대해 빈도, 백분율 값을 산출합니다.

/* 2개 이상의 변수를 나란히 쓸 경우 각각의 테이블 출력 */
PROC FREQ DATA=SASHELP.HEART; 
  TABLES Status Smoking_Status; 
RUN;

 

- PROC FREQ 는 주로 빈도를 확인하기 위해 사용하기 때문에 빈도 외 수치를 없애는 옵션을 알고 있으면 유용합니다.

PROC FREQ DATA=SASHELP.HEART; 
  TABLES Status / NOCOL NOROW NOCUM NOPERCENT MISSING; 
RUN;

 

PROC FREQ 옵션
NOCOL 열백분율 값 제외
NOROW 행백분율 값 제외
NOCUM 누적 합계 제외
NOPERCENT 백분율 값 제외
MISSING 또는 MISSPRINT 결측값 표시

 

- 또한, TABLES 다음에 변수 1* 변수 2 형태로 입력하면 두 변수에 대한 교차 빈도 값을 산출합니다.

PROC FREQ DATA=SASHELP.HEART; 
  TABLES Smoking_Status*Status; 
RUN;

교차빈도표

** 결과 해석

Smoking_Status의 Heavy (16-25)행과 Status의 Alive 열이 교차하는 결과를 예로 들어 해석해봅시다.

- 빈도 :  Heavy 이면서 Alive인 빈도

- 백분율 : 전체 관측수 중에서 Heavy&Alive인 비율 =603/5173

- 행 백분율 : Smoking_Status가 Heavy인 데이터 중에서 Status가 Alive인 비율 = 603/1046

- 칼럼 백분율 : Status가 Alive인 데이터 중에서 Smoking_Status가 Heavy인 비율 = 603/3202

 

 

5. PROC SORT

- PROC SORT 는 주로 데이터 정렬 및 중복제거를 위해 사용합니다.

/* 1. Status 컬럼을 기준으로 내림차순 정렬 */
PROC SORT DATA = SASHELP.HEART; BY DESCENDING Status; RUN;

/* 2. Status 컬럼을 기준으로 오름차순 정렬(기본=오름차순) */
PROC SORT DATA = SASHELP.HEART; BY Status; RUN;

/* 3. 모든 컬럼을 기준으로 오름차순 정렬(기본=오름차순) */
PROC SORT DATA = SASHELP.HEART; BY _ALL_; RUN;

 

- PROC SORT는 데이터의 중복을 제거하기 위해 더 자주 이용합니다. 

/* 1. 특정 열을 기준으로 중복제거 */
PROC SORT DATA = SASHELP.HEART 
  OUT = SASHELP.HEART_1 		/* 중복 제거된 데이터를 별도 테이블로 생성 */
  DUPOUT = SASHELP.HEART_2      /* 중복이 있는 데이터를 별도 테이블로 생성 */
  NODUPKEY;						/* BY 다음에 나오는 열 기준으로 중복제거 */
  BY Status ;					/* 해당 열 기준으로 정렬 및 중복제거 수행 */
RUN;

/* 2. 모든 열을 기준으로 중복제거 */
PROC SORT DATA = SASHELP.HEART 
  OUT = SASHELP.HEART_1 		/* 중복 제거된 데이터를 별도 테이블로 생성 */
  DUPOUT = SASHELP.HEART_2      /* 중복이 있는 데이터를 별도 테이블로 생성 */
  NODUPKEY;						/* BY 다음에 나오는 열 기준으로 중복제거 */
  BY _ALL_ ;					/* 해당 열 기준으로 정렬 및 중복제거 수행 */
RUN;

** SAS SQL은 SAS 프로시저나 DATA STEP에 비해 처리 속도가 느려, SQL에서 DISTINCT 를 사용하기보다 PROC SORT 로 데이터의 중복을 제거합니다.

 

 

[함수]

1. SUBSTR - 문자열/문자형 변수 추출 함수

  • SUBSTR(문자열, N1 , N2) : 문자열 또는 문자형 변수의 N1번째 문자부터 총 N2자리 문자열 추출
DATA TEMP;
BASE_DATE = '20191231';
BASE_MONTH = substr(BASE_DATE,1,6);  /* BASE_DATE의 1번째부터 총 6자리 문자열 추출 */
RUN;

/* >> BASE_MONTH = '201912' */

 

2. CATS - 문자열/문자형 변수 결합 함수

  • CATS(문자열1, 문자열2, 문자열3,...) : 문자열 또는 문자형 변수를 결합하는 함수

- 간단하게 파이프라인(문자열1||문자열2)으로 문자열 또는 문자형 변수를 결합하는 방법도 있습니다.

- ||와 달리 CATS함수는 문자열(또는 문자형 변수)의 공백을 제거한 후 결합합니다.

 

DATA TEMP;
BASE_MONTH = '201912';

/* CATS - 여백 제거 후 결합 */
BASE_DATE1 = CATS(BASE_MONTH,'01');
BASE_DATE2 = CATS(BASE_MONTH,' 01 ');  

/* || - 여백 제거하지 않고 결합 */
BASE_DATE3 = BASE_MONTH||'01';
BASE_DATE4 = BASE_MONTH||' 01 ';       

RUN;

 

3. INPUT/PUT - Type 변환 함수

  • INPUT(변수1, 숫자 형식) : 문자형 >> 숫자형으로 변수로 변환
  • PUT(변수1, 문자 형식) : 숫자형 >> 문자형으로 변수로 변환
DATA TMP;
/* INPUT : 문자 >>숫자 */
BASE_MONTH_NUM = INPUT('20191231' , YYYYMMN8.);     /*BASE_MONTH_NUM = 2019-12-31 */
BASE_MONTH_NUM = INPUT('20191231' , 8.);     	/*BASE_MONTH_NUM = 20191231 */

/* PUT : 숫자 >> 문자 */
BASE_MONTH_CHR0 = PUT(20191231 , $8.);     	   /*BASE_MONTH_CHR0 = '20191231' */
BASE_MONTH_CHR1 = PUT(20191231 ,  YYYYMMN8.);     /*BASE_MONTH_CHR1 = '2019-12-31' */
RUN;

 

4. INTNX/INTCK - 날짜 연산 함수

  • INTNX(interval, 기준날짜, interval 증감) : 기준날짜로부터 특정 기간 이전/후 날짜 산출

- 함수 마지막 인자로 'S','B','E' 등의 알파벳을 추가하여 특정 일(day)을 반환하도록 지정할 수 있습니다.

- 만약 알파벳을 따로 지정하지 않은 경우 'S'를 기본값으로 결과를 산출합니다.

DATA TMP;

/*기준일자 */
BASE_DATE = INPUT('20191231', YYYYMMN8.);
/*1일 전 */
BASE_DATE_1D = INTNX('DAY',BASE_DATE,-1);    
/*1개월 전 마지막 일자*/
BASE_DATE_1M_E = INTNX('MONTH',BASE_DATE,-1,'E'); 
/*1개월 전 첫 일자 */
BASE_DATE_1M_B = INTNX('MONTH',BASE_DATE,-1,'B');         		
/*1년 전 동일한 일자 */
BASE_DATE_1Y = INTNX('YEAR',BASE_DATE,-1,'S');

RUN;

** 'S'(기준날짜와 동일한 일자), 'E' (월 마지막 일자), 'B'(월의 첫 일자) 

 

  • INTCK( interval, 날짜1, 날짜2)  : 날짜 1과 날짜2 사이의 기간 산출
DATA TMP;
start= INPUT('20181130',yymmdd8.) ;
end= INPUT('20191231',yymmdd8.) ;

/* 일 단위 기간 */
interval_day=intck('day',start,end);  #396일
/* 월 단위 기간 */
interval_month=intck('month',start,end);  #13개월
/* 연 단위 기간 */
interval_year=intck('year',start,end);	#1년

run;

 

5. SUM

- 값을 더할 때 연산자 '+'나 SUM 함수를 사용합니다. SUM 함수는 SUM(변수1, 변수2, ...) 처럼 변수를 모두 나열하거나, 더할 변수가 많은 경우 SUM(시작 변수 - 마지막 변수) 형태로 간단하게 나타내는 등 다양하게 쓸 수 있습니다.

- 다만, 사용 방법마다 연산 결과가 다를 수 있음을 알아두어야 합니다.

DATA TEMP;
    A = 10;
    B = 20;
    C = 30;
    D = .;
    SUM1 = A+B+C+D;  /* >> . */
    SUM2 = SUM(A,B,C,D);  /* >> 60 */
    SUM3 = SUM(OF A-D);  /* >> 60 */
    SUM4 = SUM(0, OF A-D);  /* >> 0 */
    SUM5 = SUM(A-D);  /* >> . */
RUN;

 


마무리

자주 사용하는 기능 위주로 최대한 간결하게 작성하려다 보니 읽는 이에 따라 내용이 부족하다고 느낄 수 있을 듯합니다. 그래서 이후 SAS 사용에 대해 추가적으로 글을 쓰고자 합니다. 본편에서는 필수적인 내용을 담았다고 하면, 다음 글은 매크로, 반복문, RETAIN 등 복잡한 데이터 처리를 효율적으로 할 수 있는 방법을 중점적으로 다룰 예정입니다.

끝으로, 글의 내용 중 추가하거나 수정할 사항이 있다면 피드백 부탁드립니다. 의견을 적극 반영하여 완성도를 높여가겠습니다. 

'Data_Analysis > SAS' 카테고리의 다른 글

[SAS] 코드를 줄여주는 기능 정리  (2) 2021.09.09
[SAS] RETAIN  (0) 2021.04.19
[SAS] 반복문 활용  (1) 2021.02.27
[SAS] PROC FREQ  (1) 2021.02.09
[SAS] PROC TABULATE  (0) 2021.01.28

댓글