업무 중 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 |
댓글