[SAS 프로그래밍 팁] ODS 템플릿 수정 기법

데이터시각화, SAS프로그래밍, ODS템플릿


이번 블로그를 통해 ODS 템플릿을 효율적으로 수정할 수 있는 SAS 프로그래밍 기법, 일명 ‘커펠드 템플릿 수정 기법(Kuhfeld’s Template Modification Technique; TMT)’을 소개하고자 합니다. 다섯 단계만 거치면 20줄 미만의 SAS 코드만으로 이 기법을 구현할 수 있는데요. 방법은 간단하지만 ODS 템플릿을 동적으로 수정하고, 즉시 수정된 템플릿을 호출해 새로운 그래프나 테이블을 생성할 수 있습니다.



커펠드 템플릿 수정 기법(Kuhfeld’s Template Modification Technique)

템플릿 수정 기법(TMT)은 워렌 커펠드(Warren Kuhfeld)가 2016년 ‘ODS 그래픽을 이용한 고도의 맞춤형 그래프(Highly Customized Graphs Using ODS Graphics)’ 보고서를 통해 소개한 몇 가지 고급 기법들 중 하나입니다. 해당 자료는 슬라이드로도 확인할 수 있습니다. TMT는 SAS가 제공하는 템플릿을 수정하는 DATA _NULL_ 프로그램으로 CALL EXECUTE를 사용해 템플릿을 바로 컴파일하고, 즉시 수정된 템플릿을 호출해 새로운 그래프를 도출합니다. (보고서 12페이지, 슬라이드 14페이지 참고)


2016년 처음 워렌의 발표를 들었을 때 어마어마한 정보량에 압도당한 기분이었습니다. 서로 연결된 모든 ‘나무들’ 때문에 숲을 볼 수 없었죠. 하지만 GTL 템플릿에만 집중하면 그래프 사용자 정의를 쉽게 이해할 수 있습니다. 옵션 값 변경 등 템플릿을 간단하게 수정할 수 있는 다섯 단계는 다음과 같습니다.


1. ODS 검색 경로에 Private item store를 추가한 후 수정된 템플릿을 저장합니다.

2. 기존 템플릿을 임시 텍스트 파일로 기록합니다.

3. 한 번에 한 줄씩 기존 템플릿을 읽는 DATA 단계를 실행합니다. 그리고 각 줄에 변경하고자 하는 옵션이 포함되어 있는지 확인합니다. 만약 포함되어 있다면 줄을 수정해 템플릿의 동작을 변경합니다.

4. 수정된 템플릿을 개인 항목 저장소로 컴파일(compile)합니다.

5. PROC SGRENDER를 호출해 새로운 템플릿을 이용해 그래프를 렌더링(render)합니다. 


이 글은 간추린 버전이며, 상세한 내용은 SAS/STAT 설명서의 ‘ODS 그래픽 템플릿 수정(ODS Graphics Template Modification)’ 챕터를 참조해주세요.


커펠드의 예시 대부분은 TMT를 이용해 SAS와 함께 배포되는 ODS 템플릿을 수정합니다. 이러한 템플릿은 복잡할 수 있으며, 종종 조건부 로직을 포함합니다. 보다 간단한 예시를 위해 다음 섹션에서는 히트-맵(heat map)을 이용해 동일 그리드 상에 반응 변수(response variable)를 표시하는 간단한 템플릿을 만들어보겠습니다.



<예시> 색상 램프를 지정하는 템플릿

GTL을 이용해 그래프를 만드는 프로그래머는 일반적으로 동적 변수(dynamic variables)와 런타임 매크로 변수(run-time macro variables)를 접하게 됩니다. 템플릿에 정보를 하드 코딩(hard-coding)하는 대신 런타임에 옵션을 지정할 수 있는데요. 그렇지만 설명서에는 ‘동적 변수 ... 명령문 또는 옵션 키워드를 확인할 수 없습니다.(dynamic variables ... cannot resolve to statement or option keywords.)’라고 적혀있습니다. 특히 GTL은 런타임에서 색상 램프 변경을 지원하지 않으며, 템플릿에 하드 코딩된 색상 램프가 사용됩니다. (만약 SAS 9.4M3을 사용한다면 PROC SGPLOT의 HEATMAPPARM 명령문으로 런타임에서 색상 램프를 지정할 수 있습니다.)


실망하지 마세요! 커펠드 TMT를 통해 런타임에서 색상 램프를 수정할 수 있습니다. 아래 GTL은 ‘HEATMAP’이라는 이름의 템플릿을 정의합니다. 이 템플릿은 HEATMAPPARM 명령문을 사용하고, COLORMODEL= option을 현재 ODS 스타일에서 ‘ThreeColorRamp’로 하드 코딩합니다. 템플릿은 ‘SAS에서 기본 열 지도 만들기(creating a basic heat map in SAS)’ 블로그를 참고했습니다.


/* Construct example template: a basic heat map with continuous color ramp */
proc template; 
define statgraph HEATMAP;
dynamic _X _Y _Z;           /* dynamic variables */
 begingraph;
 layout overlay;
    heatmapparm x=_X y=_Y colorresponse=_Z /  /* specify variables at run time */
       name="heatmap" primary=true xbinaxis=false ybinaxis=false
       colormodel = THREECOLORRAMP;           /* <== hard-coded color ramp */
    continuouslegend "heatmap";
  endlayout;
endgraph;
end;
run;


PROC TEMPLATE 단계가 실행되면 HEATMAP 템플릿이 ODS 검색 경로에 의해 결정되는 위치에 저장됩니다. 이때 검색 경로를 표시하기 위해 ODS 경로 보기(ods path show;)를 실행할 수 있고, proc 템플릿을 실행해(proc template; list HEATMAP; run;) HEATMAP 템플릿이 저장된 위치를 확인할 수 있습니다.


아래의 DATA 단계는 균일한 그리드에 (x, y) 데이터를 정의하고, z를 x와 y의 3차 함수로 정의합니다. 열 지도는 3차 함수의 대략적인 등고선도(contour plot)를 보여줍니다.


/* Construct example data: A cubic function z = f(x,y) on regular grid */
do x = -1 to 1 by 0.05;
   do y = -1 to 1 by 0.05;
      z = x**3 - y**2 - x + 0.5;
      output;
   end;
end;
run;
 
/* visualize the data using the built-in color ramp */
proc sgrender data=Cubic template=Heatmap; 
   dynamic _X='X' _Y='Y' _Z='Z';
run;


데이터시각화, SAS프로그래밍, ODS템플릿


지금부터는 커펠드 TMT를 이용해 HEATMAP 템플릿과 동일하지만 다른 색상 램프를 사용하는 새로운 템플릿을 작성하는 방법을 보여드리겠습니다. 커펠드 기법은 기존 템플릿을 한 줄씩 복사하지만 ‘THREECOLORRAMP’ 텍스트를 새로운 사용자 정의 색상 램프를 정의하는 텍스트로 교체합니다.


하단의 프로그램에서 대문자는 기존 템플릿의 이름, 새로운 템플릿의 이름, 새로운 색상 램프의 값을 표현합니다. 각 애플리케이션은 DATA _NULL_ 단계에서 고유한 로직을 필요로 하지만 대부분의 소문자 용어는 TMT를 위한 ‘표준 문안(boilerplate)’입니다.



1 단계: ODS 검색 경로 앞에 개인 항목 저장소 추가

PROC TEMPLATE은 ODS 검색 경로의 첫 번째 (기록 가능한; writable) 항목 저장소에 템플릿을 기록합니다. PROC SGRENDER는 지정된 이름의 템플릿을 찾을 때까지 ODS 검색 경로를 조사하는데요. 첫 번째 단계는 아래의 명령문과 같이 검색 경로 앞에 개인 항목 저장소를 추가하는 것입니다.


/* 1. Modify the search path for ODS. Prepend an item store in WORK */
ods path (prepend) work.modtemp(update);


ODS PATH 명령문을 이용해 수정된 템플릿을 원하는 이름으로 WORK.MODTEMP에 저장할 수 있습니다. ‘WORK.TEMPLAT’는 SAS 설명서에서 일반적으로 사용되는 이름입니다. ODS 경로에 이미 WORK.TEMPLAT가 있을 수 있으므로 다른 이름을 사용하겠습니다. 한 가지, WORK의 항목 저장소는 SAS가 종료될 때 삭제된다는 사실을 참고해주세요. SAS/STAT 설명서에서 템플릿 검색 경로에 대한 자세한 정보를 확인할 수 있습니다.



2 단계: 기존 템플릿을 임시 텍스트 파일에 기록

HEATMAP 템플릿의 소스 코드를 일반 텍스트 파일에 기록해야 SAS DATA 단계에서 읽을 수 있습니다. FILENAME 명령문을 이용해 하드 코딩될 위치(예: filename t "C:/temp/tmplt.txt";)를 지정할 수 있지만 보다 이식성이 뛰어난(portable) SAS keyword TEMP를 추천합니다. TEMP 키워드는 SAS가 운영 체제 및 파일 시스템으로부터 독립적인 위치에 임시 파일 이름을 생성하도록 합니다.


/* 2. Write body of existing template to text file */
filename _tmplt TEMP;             /* create temporary file and name */
proc template;
   source HEATMAP / file=_tmplt;  /* write template source to text file */
run;


FILE= option을 생략하면 템플릿 소스가 SAS 로그에 기록됩니다. 텍스트 파일에는 HEATMAP 템플릿의 본문(body)만 포합됩니다.



3/4단계: 기존 템플릿으로부터 새로운 템플릿 만들기

다음 단계에서는 기존 템플릿을 한 줄씩 읽고 수정합니다. INDEX and FIND family of functions, the PRXCHANGE function (which uses regular expressions), the TRANWRD function 등 다양한 SAS 문자 기능(SAS character functions)을 이용해 각 텍스트 줄에 어떤 키워드가 있는지 탐색할 수 있습니다.


이 예시의 목표는 ‘THREECOLORRAMP’라는 단어를 다른 문자열로 교체하는 것인데요. TRANWRD 함수는 문자열이 발견되면 이를 대체합니다. 반면 해당 단어가 발견되지 않으면 그 줄은 바뀌지 않습니다. 따라서 기존 템플릿의 모든 줄에서 TRANWRD 함수를 호출하는 것이 안전합니다.


CALL EXECUTE 함수를 사용해 템플릿의 수정 가능한 각 줄을 큐(queue)에 배치할 수 있습니다. 이 큐는 DATA 단계가 완료될 때 실행되는데요. 그렇지만 텍스트 파일은 PROC TEMPLATE 명령문으로 시작하거나 RUN 명령문으로 끝나지 않습니다. 따라서 템플릿을 컴파일하기 위해 실행 큐에 다음과 같은 명령문을 추가해야 합니다.


/* one possible way to specify a new color ramp */
%let NEWCOLORRAMP = (blue cyan yellow red);
 
/* 3. Read old template; make modifications.
   4. Use CALL EXECUTE to compile (modified) template with a new name. */
data _null_;                       /* Modify graph template to replace default color ramp */
   infile _tmplt end=eof;          /* read from text file; last line sets EOF flag to true */
   input;                          /* read one line at a time */
   if _n_ = 1 then 
       call execute('proc template;');      /* add 'PROC TEMPLATE;' before */
 
   if findw(_infile_, 'define statgraph') then
      _infile_ = "define statgraph NEWHEATMAP;";  /* optional: assign new template name */
   /* use TRANWRD to make substitutions here */
   _infile_ = tranwrd(_infile_, 'THREECOLORRAMP', "&NEWCOLORRAMP"); /* replace COLORMODEL= option */
 
   call execute(_infile_);                  /* push line onto queue; compile after DATA step */
   if eof then call execute('run;');        /* add 'RUN;' at end */
run;


DATA 단계에서는 기존 템플릿 소스를 복사하지만 템플릿 이름과 COLORMODEL= option을 수정합니다. CALL EXECUTE 명령문은 DATA 단계가 종료될 때 실행되는 큐로 (잠재적으로 수정된) 개별 명령문을 푸쉬(push)합니다. 결과적으로 PROC TEMPLATE은 새로운 템플릿을 컴파일하고 WORK.MODTEMP 항목 저장소에 저장합니다. TRANWRD 함수와 다른 문자열 조작(string-manipulation) 함수는 대문자와 소문자를 구별하므로 템플릿에 포함된 정확한 대문자를 사용해야 합니다. 즉, 이 기법을 사용하려면 반드시 수정하려는 템플릿의 세부 정보를 알고 있어야 합니다.


이 기법을 이용해 SAS 프로시저에서 사용되는 기본 SAS 템플릿 중 하나를 수정하는 경우 템플릿의 이름은 수정하지 마세요.



수정된 템플릿 검사하기

새로운 템플릿을 사용하기 전에 해당 템플릿이 올바른지 확인하는 것이 좋겠죠? 아래의 PROC TEMPLATE 호출은 새 템플릿의 위치와 생성 날짜를 보여줍니다. 올바르게 대체됐는지 확인할 수 있도록 로그에 템플릿 소스가 표시됩니다.


proc template;
   list NEWHEATMAP / stats=created; /* location of the modified template */
   source NEWHEATMAP;       /* confirm that substitutions were performed */
run;


데이터시각화, SAS프로그래밍, ODS템플릿



5단계: 새로운 템플릿을 이용해 그래프 렌더링하기

마지막 단계는 PROC SGRENDER 호출로 새로운 템플릿을 이용해 새로운 그래프를 만드는 것입니다.


/* 5. Render graph by using new template */
proc sgrender data=Cubic template=NEWHEATMAP; 
   dynamic _X='X' _Y='Y' _Z='Z';
run;


데이터시각화, SAS프로그래밍, ODS템플릿


그 결과 기존 색상 램프(‘ThreeColorRamp’)가 파란색, 청록색, 노란색, 빨간색의 4색 색상 램프로 교체됐음을 알 수 있습니다.



ODS 템플릿은 언제 수정할까요?

그렇다면 도대체 이 모든 복잡하고 추상적인 과정은 왜 필요할까요? 템플릿을 프로그램 편집기에 복사해 색상 램프를 변경할 수 있지 않나요? 맞습니다. 프로그램 편집기를 이용해 개인 용도로 템플릿을 수정할 수 있습니다. 그렇지만 이 프로그래밍 기법을 이용하면 다른 사람들이 사용할 수 있는 매크로, 작업(tasks), SAS/IML 기능을 기록할 수 있습니다. 예를 들어, 이 블로그에 나오는 프로그램을 색상 램프와 데이터 세트를 인수(argument)로 허용하는 %CreateHeatmap 매크로로 요약할 수 있습니다. 또 SAS/IML 프로그래머는 SAS/IML에서 HEATMAPCONT 및 HEATMAPDISC 서브루틴과 같은 모듈을 기록해 매트릭스를 시각화하기 위한 색상 램프를 지정할 수 있습니다.


규제를 받는 산업에서 SAS가 배포하는 템플릿을 수정하는 경우 이 기술은 재생산성을 보장합니다. 검토자(reviewer) 또는 감사관(auditor)은 그래프를 재생산하기 위해 프로그램을 실행할 수 있습니다.



요약

커펠드의 템플릿 수정 기법(TMT)을 이용해 ODS 템플릿을 수정하는 SAS 프로그램을 작성할 수 있습니다. 많은 AS 프로그래밍 기법을 결합한 TMT는 처음에는 이해하기 어려울 수 있는데요. 이 블로그에서는 이 기법을 다섯 가지의 간단한 단계로 분류합니다. TMT를 사용해 SAS가 배포하고 SAS 프로시저에서 사용되는 ODS 템플릿을 편집하거나 런타임에서 옵션을 변경할 수 있습니다. 블로그에서 소개된 SAS 프로그램을 다운받아 직접 활용해보세요.





저자

릭 위클린(Rick Wicklin) l SAS 전산 통계 공로 연구원(Distinguished Researcher in Computational Statistics at SAS)