본문 바로가기
Data_Analysis/SAS

[SAS] 반복문 활용

by Classic! 2021. 2. 27.

업무 중 2억 행이 넘는 자료를 처리할 때가 있습니다.

파일이 상당히 크다 보니 가장 오래된 날짜, 가장 최근 날짜를 확인하는 간단한 작업도 한 번에 처리할 수 없다고 뜨기도 합니다.

그래서 파일을 행별로 분할하여 동일한 작업을 처리하도록 했습니다.

이 과정에서 제가 사용했던 방법을 소개하고자 합니다. 더 좋은 방법이 있다면 댓글로 추천 부탁드립니다.

 

아래 예제 코드는 데이터에서 날짜의 최대/최솟값 탐색을 목적으로 작성했습니다.


1. 데이터 셋 한번에 사용

1) 데이터 셋을 한번에 불러들여 2) 테이블의 인덱스로 최소/최대 날짜 확인하는 방법입니다.

스크롤을 내려가며 결과를 직접 확인해야 한다는 점에서 세련되지 못하다고 생각할 수 있지만,

처리되는 속도가 빠르고 코드가 가장 짧고 단순합니다. 단지 데이터만 확인하는 1회성 작업에 적절합니다.

/* 데이터 셋팅 */
data work.init;set mylib.init;run;

/* 날짜를 기준으로 빈도 테이블 생성 */
proc freq data=init noprint;
  tables stday /nopercent nocol norow nocum nofreq out = _n_;
run;

 

 

2. 데이터 셋 분할 & sql

1) 데이터 셋을 분할하여 2) sql로 최대/최소 날짜만 출력하는 방법입니다.

앞서 언급한 것처럼 일괄적인 데이터를 처리가 어려운 경우가 있어 데이터를 분할하여 처리했습니다.

또한, 분할한 데이터의 결과를 하나하나 확인하는 것이 번거로워 sql로 각 테이블의 최대/최솟값만 산출하도록 했습니다.

 

data work.init;set init(firstobs=1 obs=10000000);run;
data work.init2;set init(firstobs=10000000 obs=20000000);run;
data work.init3;set init(firstobs=20000000 obs=30000000);run;
data work.init4;set init(firstobs=30000000 obs=40000000);run;


proc sql;
	create table temp as
	select max(stday),min(stday)
	from init1	
	;	
quit;

proc sql;
	create table temp as
	select max(stday),min(stday)
	from init2
	;	
quit;

proc sql;
	create table temp as
	select max(stday),min(stday)
	from init3
	;	
quit;

proc sql;
	create table temp as
	select max(stday),min(stday)
	from init4
	;	
quit;

 

3. 루프문으로 자료 분할 & sql

반복문의 구조는아래와 같습니다.

/* 3. 매크로 */
%macro split_data (); 

  %do i=1 %to 10; /* 반복문 시작 */
   
   
   %if i=1 %then 
    %do;
    /* 1번째 자료 처리 */
    %end;
   
   %else;
    %do	 
    /* 나머지 자료 처리 */
    %end;	   	

  %end; /* 반복문 종료 */
%mend split_data ;

/* 매크로 호출 */
%split_data();

 

 

반복문 구조로 작성한 코드는 아래와 같습니다.

훨씬 코드가 길고 복잡해졌다는 단점이 있지만, 코드를 모듈화 하여 사용하는 경우가 있어 작성해 보았습니다.


/* 3. 매크로 */

/* 파일이름, 변수명, 1회 실행 시 데이터 길이 ,반복 횟수 */
%macro split_data (filename,varname,len,loop_n); 

/* local 변수 : 매크로 안에서만 유효한 변수 */
  %local firstobs; 
  %local obs;

  /* 반복문 시작 */
  %do i=1 %to &loop_n.;     

    %let firstobs=%eval(&len.*(&i.-1)+1);
    %let obs=%eval(&len.*&i.); /* 매크로 변수는 문자형. EVAL함수를 써야 연산 가능 */
	
	/*로그 창에 반복문이 몇 행째 돌고 있는지 출력함. 삭제해도 무방*/
    %put &firstobs.;   
    %put &obs.;
    
	/* 첫번째 테이블 조각 */
	%if i=1 %then 
      	%do;
	  proc sql;
	   create table temp_base as
	   select min(&varname.) as min, max(&varname.)as max
	   from &filename.(keep=&varname. firstobs=&start. obs=&end.)
	   ;
	  quit;
	 %end;
      
	/* 이후 이어붙일 테이블 조각. temp_1은 계속 내용이 바뀜 */
	%else;
	 %do
	  proc sql;
	   create table temp_1 as
	   select min(&varname.) as min, max(&varname.)as max
	   from &filename.(keep=&varname. firstobs=&start. obs=&end.)
	   ;
	  quit;
	 %end;	 
	
    /* 첫번째 테이블에 temp_1 이어붙이기 */
    proc append base=temp_base data=temp_1; run;
  	
  %end;
  
  /* 저장 공간 효율을 위해 TEMP1 테이블은 삭제 */
  proc delete data=temp_1;run;

  /* 각 테이블의 최대/최소값 중 최대/최소값 뽑기 */
  proc sql;
	create table result as
	select min(min), max(max)
	from temp_base
	;
  quit;


%mend split_data ;


/* 매크로 호출 */
%split_data(init, stday, 10000000,5);

3번 코드가 상당히 길어져 현재 call symput()을 활용하여 좀 더 가독성 높고 효율적인 코드를 작성 중입니다.

이후 코드를 완성하면 업데이트하도록 하겠습니다. 

 

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

[SAS] 자주 쓰는 기능 정리  (2) 2021.09.08
[SAS] RETAIN  (0) 2021.04.19
[SAS] PROC FREQ  (1) 2021.02.09
[SAS] PROC TABULATE  (0) 2021.01.28
[SAS] 범주형 자료분석  (2) 2021.01.07

댓글