Úvod do SASu pro Windows - Část II.
Manipulace s datovými soubory

SAS je registrovaná ochranná známka  SAS Institute, Inc., Cary, NC, USA

(c) 2000 Michal Kulich, 1998 Oliver Schabenberger


1. Vytváření datových souborů SASu

1.1 Načítání dat po řádcích (volný formát)
1.2 Načítání dat ve sloupcovém formátu
1.3 Načítání více pozorování z jednoho řádku
1.4 Načítání dat z ASCII souborů
1.5 Načítání souborů dBase
1.6 Práce s direktoráři a vytváření trvalých datových souborů
1.7 Načítání tabulek Excelu do SASu
1.7.1 S použitím nabídky Import
1.7.2 S použitím PROC ACCESS

2. Manipulace s datovými soubory SASu

2.1 Mazání datových souborů
2.2 Vypsání názvů veličin
2.3 Vytvoření (upravené) kopie datového souboru
2.4 Vytvoření nových veličin
2.4.1 Transformace
2.4.2 Operátory
2.4.3 Logické výrazy
2.5 Přejmenovávání veličin
2.6 Mazání veličin z datového souboru
2.7 Vynechání pozorování z datového souboru
2.8 Vertikální spojování datových souborů
2.9 Horizontální spojování datových souborů
2.10 Třídění dat a použití setříděných dat
2.10.1 Příkaz BY v PROCedurách
2.10.2 Příkaz BY při spojování setříděných souborů
2.11 Formátování veličin
2.11.1 Značky (labels)
2.11.2 Formáty
2.11.3 Datum
2.12 Výpočet počtu pozorování v datovém souboru

3. Programování v datových procedurách SASu

3.1 Princip činnosti datové procedury
3.2 Přenos hodnot veličiny na další pozorování
3.3 DO bloky a smyčky
3.4 Konstrukce IF .. THEN .. ELSE
3.5 Konstrukce SELECT
3.6 Pole (array)
3.7 Funkce LAG: přístup k předchozím hodnotám veličin
3.8 Vytváření několika datových souborů v jednom DATA bloku
3.9 Konverze znakových veličin na numerické

1. Vytváření datových souborů SASu

Datové soubory SASu se vytvářejí pomocí datových procedur začínajících klíčovým slovem DATA. Každý datový soubor se skládá z pozorování a veličin. Můžeme si je představit jako matici, kde sloupcům odpovídají veličiny a řádkům pozorování. Každá veličina (tj. sloupec matice) má své jméno nejvýše osm znaků dlouhé. Pokud uživatel nestanoví jinak, datové soubory SASu se ukládají do dočasného pracovního direktoráře, který se po ukončení práce se SASem maže. V kapitole 1.6 je vysvětleno, jak vytvářet trvalé datové soubory a uschovávat je do vlastních direktorářů.

  Veličina 1 Veličina 2 Veličina 3
Pozorování 1 ---->      
Pozorování 2 ---->      
Pozorování 3 ---->      

1.1 Načítání dat po řádcích (volný formát)

Data, která se mají uschovat v datovém souboru, mohou být přímou součástí SASového programu. V takovém případě ručně vypisujeme jednotlivé hodnoty z klávesnice v PROGRAM EDITORu anebo zkopírujeme hodnoty z jiného textového souboru, například pomocí kláves Ctrl-C a Ctrl-V. Následující datová procedura ukazuje, jak vytvořit datový soubor pojmenovaný ANKETA, který má deset pozorování a sedm veličin zvaných ID, POHL, VEK, PRIJEM, R1, R2, R3. Data mohou představovat výsledky ankety mezi zákazníky, kde PRIJ značí měsíční příjem v tisících a R1 až R3 jsou ohodnocení oblíbenosti tří určitých výrobků.

DATA anketa;
INPUT id pohl $ vek prijem r1 r2 r3 ;
DATALINES;
1 F 35 17 7 2 2
17 M 50 14 5 5 3
33 F 45 6 7 2 7
49 M 24 14 7 5 7
65 F 52 9 4 7 7
81 M 44 11 7 7 7
2 F 34 17 6 5 3
18 M 40 14 7 5 2
34 F 47 6 6 5 6
50 M 35 17 5 7 5
;
RUN;

Příkaz DATA ANKETA znamená, že se bude vytvářet datový soubor jménem ANKETA. Příkaz INPUT definuje jména veličin pro datový soubor ANKETA a tím určuje i jejich počet. Znak $ za jménem veličiny POHL (všimněte si, že je oddělený mezerou) indikuje, že tato veličina je znaková, tj. obsahuje znakové řetězce a ne čísla. Příkaz DATALINES signalizuje ukončení příkazů datové procedury--následující příkaz již obsahuje konkrétní hodnoty dat oddělené mezerami, vždy jedno pozorování na každém řádku. Všimněte si, že řádky dat nejsou oddělené středníky. Všechna vstupní data se považují za jeden příkaz a středník (nepovinný) následuje až za poslední načítanou hodnotou posledního pozorování. Příkaz DATALINES má ekvivalentní formu CARDS, již lze používat zcela zámenně. Příkaz CARDS se uchoval z dob, kdy se data načítala z děrných štítků (angl. punchcards) a protože evokoval prastarý původ SASu jako děrnoštítkového programu, byl úředně přejmenován na DATALINES (i když z celého SASu ty děrné štítky ještě pořád vyloženě čiší - pozn. překl.).

Právě provedená datová procedura nevydává žádný výstup až na záznam v LOG okně, potvrzující, že v pořádku proběhla. Chceme-li si data prohlédnout, napíšeme PROC PRINT; RUN; a dostaneme výstup v OUTPUT window:

OBS    ID    POHL    VEK    PRIJEM    R1    R2    R3
  1     1     F       35      17       7     2     2
  2    17     M       50      14       5     5     3
  3    33     F       45       6       7     2     7
  4    49     M       24      14       7     5     7
  5    65     F       52       9       4     7     7
  6    81     M       44      11       7     7     7
  7     2     F       34      17       6     5     3
  8    18     M       40      14       7     5     2
  9    34     F       47       6       6     5     6
 10    50     M       35      17       5     7     5

Znakové (řetězcové) veličiny, jako například POHL, je třeba vždy identifikovat v příkazu INPUT znakem $ za jejich jménem. Opomenutí tohoto znaku by mělo za následek načtení chybějícího pozorování namísto každé znakové hodnoty v domněle numerické proměnné. Data ANKETA by pak vypadala takto:

PROC PRINT; RUN;
OBS    ID    POHL    VEK    PRIJEM    R1    R2    R3
  1     1      .      35      17       7     2     2
  2    17      .      50      14       5     5     3
  3    33      .      45       6       7     2     7
  4    49      .      24      14       7     5     7
  5    65      .      52       9       4     7     7
  6    81      .      44      11       7     7     7

a tak dále.

1.2 Načítání dat ve sloupcovém formátu

Někdy je nutné sdělit SASu něco víc o umístění jednotlivých načítaných hodnot na řádce. Taková potřeba například nastane, načítáme-li řetězcovou veličinu, jejíž hodnoty nemají stejnou délku anebo obsahují uvnitř mezery.

DATA tahle;
  INPUT jmeno $1-25  vek mesto $34-48 stat $ ;
  DATALINES;
Josef Hromádka               33  Hrochův Týnec   CZ
Wolfgang T. Schalken      37     Bonn            DE
;
RUN;
PROC PRINT DATA=tahle; RUN;
OBS           JMENO            VEK    MESTO           STAT
 1     Josef Hromádka           33    Hrochův Týnec    CZ
 2     Wolfgang T. Schalken     37    Bonn             DE

Příkaz INPUT definuje veličiny JMENO, VEK, MESTO a STAT. Specifikace $1-25 za názvem veličiny JMENO znamená, že JMENO je znaková veličina, jejíž hodnoty jsou uloženy ve sloupcích 1 až 25 každé datové řádky. Znaková veličina MESTO se načítá ze sloupců 34 až 48. VEK je numerická veličina, jejíž hodnoty jsou umístěny kdekoli mezi hodnotami pro JMENO a MESTO, tj. nekde ve sloupcích 26-33.  STAT je znaková veličina a její hodnoty se mohou nalézat kdekoli od sloupce 49 dále.

Kdybychom specifikaci $34-48 pro veličinu MESTO nahradili pouhým označením $ pro znakovou veličinu, data by se načetla následovně:

DATA tahle;
  INPUT jmeno $1-25  vek mesto $ stat $ ;
  DATALINES;
Josef Hromádka               33  Hrochův Týnec   CZ
Wolfgang T. Schalken      37     Bonn            DE
;
RUN;
PROC PRINT DATA=tahle; RUN;
OBS           JMENO            VEK    MESTO           STAT
 1     Josef Hromádka           33    Hrochův         Týnec
 2     Wolfgang T. Schalken     37    Bonn            DE

Jelikož mezera v datovém řádku odděluje hodnoty jednotlivých veličin, SAS nalezne nejprve řetězec 'Hrochův' a přiřadí ho veličině MESTO. 'Týnec' pak musí být hodnota pro veličinu STAT. Zbytek řádku se ignoruje, protože již pro něj nezbývají žádné veličiny.

1.3 Načítání více pozorování z jednoho řádku

Datové řádky mohou obsahovat více hodnot, než kolik je potřeba pro jedno pozorování. Přebývající hodnoty se normálně ignorují (viz předchozí odstavec). Pokud ale příkaz INPUT končí specifikací @@, jednotlivé hodnoty se načítají a přiřazují veličinám sekvenčně, bez ohledu na datové řádky. Například následující dvě datové procedury vytvářejí tentýž datový soubor. První:

DATA xyz;
  INPUT x y z;
  DATALINES;
1  1  12.4
1  2  11.3
1  3   1.4
2  1   2.1
2  2  19.4
2  3  10.0
;
RUN;

a druhá:

DATA xyz;
  INPUT x y z @@;
  DATALINES;
1  1  12.4 1  2  11.3 1  3   1.4
2  1   2.1 2  2  19.4 1  3  10.0
;
RUN;

Bez specifikace @@ by druhá procedura vytvořila pouhá dvě pozorování z prvních tří hodnot na každém řádku.

1.4 Načítání dat z ASCII souborů

Načítání dat přímo z ASCII souborů je výhodnější než vypisování hodnot přímo do SASového programu, zvláště u velkých souborů. K načtení ASCII souboru slouží příkaz INFILE předcházející příkaz INPUT  uvnitř datové procedury. Struktura a význam příkazu INPUT se přitom nemění, příkaz DATALINES nebo CARDS není třeba uvádět. Struktura načítaného ASCII souboru je úplně stejná, jako by byl jeho obsah uveden přímo v datové proceduře po příkazu DATALINES.

Příkaz INFILE specifikuje ASCII soubor, který se má načíst. Je možné ho použít dvěma způsoby. Buď přímo uvést jméno i s celou cestou, např.

DATA ctiascii;
  INFILE 'c:\mujdir\data\soubor.txt';
  INPUT vykon rozpeti trida $;
RUN;

nebo nejprve přiřadit souboru nějakou vnitřní SASovou přezdívku (fileref) příkazem FILENAME a tu pak používat místo celého jména, např.

FILENAME vykdata 'c:\mujdir\data\soubor.txt';
DATA ctiascii;
  INFILE vykdata;
  INPUT vykon rozpeti trida $;
RUN;

Jestliže hodnoty v ASCII souboru nejsou odděleny mezerami, ale jinými oddělovacími znaky, můžeme použít parametr DELIMITER příkazu INFILE. Podobným způsobem můžeme vynechat některá pozorování ze začátku ASCII souboru a určit, kolik pozorování celkem chceme načíst (parametry FIRSTOBS a OBS). Například

FILENAME vykdata 'c:\mujdir\data\soubor.txt';
DATA ctiascii;
  INFILE vykdata DELIMITER=',' FIRSTOBS=12 OBS=100;
  INPUT vykon rozpeti trida $;
RUN;

načte 100 pozorování z ASCII souboru c:\mujdir\data\soubor.txt počínaje pozorováním č. 12 a předpokládá, že jednotlivé hodnoty jsou odděleny čárkami namísto mezerami (což platí například pro *.prn soubory z Excelu).

1.5 Načítání souborů dBase

Ačkoli dBase již nepatří mezi nejpoužívanější databázová prostředí, její datový formát se stále používá a mnohé softwarové balíky jsou schopny číst a psát data ve formátu dBase. Datový soubor dBase lze snadno předělat na SASový datový soubor pomocí procedury DBF. Stačí napsat

FILENAME inf 'c:\temp\mydata.dbf';
PROC DBF DB4=inf OUT=dbdata; RUN;

a výsledkem je SASový datový soubor dbdata. Parametr DB4 procedury DBF uvádí přezdívku (fileref) databázového souboru, který má být ve formátu dBaseIV. Pro formát dBaseIII+ použijte místo toho DB3, pro formát dBaseV použijte DB5.

1.6 Práce s direktoráři a vytváření trvalých datových souborů

SAS automaticky ukládá všechny vytvořené datové soubory do dočasného pracovního direktoráře, který po skončení práce maže. Tento direktorář bývá umístěn někde pod \sas\saswork\ a datové soubory SASu se v něm uschovávají pod jménem, s jakým byly vytvořeny, s koncovkou .sd2. Chceme-li uschovávat své datové soubory pro další práci, abychom je nemuseli znovu vytvářet při příštím spuštění SASu, musíme je uschovat v jiném direktoráři, který si sami zvolíme.

SAS nazývá direktoráře knihovnami. Chceme-li pracovat s konkrétním direktorářem, v SASu jej definujeme jako novou knihovnu, jíž přiřadíme její vnitřní jméno. K jednotlivým souborům se pak v SASu přistupuje dvousložkovým jménem, kde první složka určuje knihovnu (direktorář) a druhá složka jméno vlastního souboru. Tak například dočasný pracovní direktorář má v SASu jméno WORK a všechny soubory v něm uložené se jmenují WORK.SOUBOR. Vytvoříme-li data XYZ procedurou

DATA xyz;
  INPUT x y z;
  DATALINES;
1  1  12.4
1  2  11.3
1  3   1.4
2  1   2.1
2  2  19.4
2  3  10.0
;
RUN;

SAS bude nazývat vytvořený soubor WORK.XYZ. Ke všem souborům v knihovně WORK je ovšem možné také přistupovat bez uvedení jména knihovny, takže my můžeme ve svých programech uvádět buď DATA=xyz nebo DATA=work.xyz.

Potřebujeme-li pracovat s jiným direktorářem, ukládat do něj permanentní soubory a znovu je načítat, musíme tomuto direktoráři přiřadit vnitřní SASové jméno příkazem LIBNAME. Tomuto vnitřnímu jménu se v SASu říká libref a není to vlastně nic jiného než odkaz na direktorář:

LIBNAME broukdir 'c:\vyzkum\data\brouci';

Chceme-li nyní vytvořit datový soubor a uschovat ho v direktoráři c:\vyzkum\data\brouci (neboli v knihovně BROUKDIR), napíšeme:

DATA broukdir.br1;
  INPUT larva kukla imago;
  DATALINES;
15.3  12.8  24.6
11.5  10.8  21.9
...
;
RUN;

Tento soubor můžeme dále libovolně používat pod jménem broukdir.br1. Jeho jméno na disku jest c:\vyzkum\data\brouci\br1.sd2.

1.7 Načítání tabulek Excelu do SASu

Tabulky Excelu mohou být načteny do SASu několika různými způsoby, z nichž uvádíme dva.

1.7.1 S použitím nabídky Import

Z hlavního menu zvolíme File/Import. Objeví se okno, kde si zvolíme formát dat, která se mají zkonvertovat (např. Excel 5.0) a postupně doplníme potřebnou informaci. Konverse proběhne nejsnáze, jestliže má excelovská tabulka podobnou stavbu jako SASový soubor (veličiny, pozorování) a obsahuje v prvním řádku jména proměnných, pokud možno vyhovující konvencím SASu (max. osm znaků, bez mezer, začíná písmenem). SAS je schopen předělat jména veličin, které jeho konvencím nevyhovují. Po ukončení konverse je třeba zkontrolovat výsledná data (PROC PRINT).

Pozor: Ačkoli nabídka Import obsahuje volbu pro Excel 7.0 (Excel97), tabulky zapsané v tomto formátu nebudou správně zkonvertovány. Pro import do SASu je třeba tabulky ukládat ve formátu Excel 5.0 (Excel 95) nebo Excel 4.0.

1.7.2 S použitím PROC ACCESS

Tato metoda konverse je nejvšestrannější a nejméně průhledná. Vyžaduje nainstalovaný modul SAS/ACCESS. Pokud se po spuštění

PROC ACCESS; RUN;

objeví okno, je tento modul k disposici. Před použitím modulu ACCESS musíme zvolit pracovní direktorář pro soubory potřebné ke konversi a přiřadit mu libref.

Konversní program používající PROC ACCESS můžeme napsat třeba takto:

LIBNAME convert 'c:\mujdir\sas\konverse';
PROC ACCESS DBMS=xls;
   CREATE convert.xlsa.access;
   PATH = 'c:\mujdir\excel\data\soyref95.xls';
   SCANTYPE  = yes;
   WORKSHEET = ref95;
   GETNAMES  = yes;
   ASSIGN    = yes;
   UNIQUE    = yes;
   CREATE convert.xlsv.view;
   SELECT all;
RUN;
DATA soybean; SET convert.xlsv; RUN;
PROC DATASETS LIBRARY=convert; DELETE xlsv / MEMTYPE=view;
                               DELETE xlsa / MEMTYPE=access;
RUN; QUIT;
PROC PRINT DATA=soybean; RUN;

Tento program načte excelovskou tabulku c:\mujdir\excel\data\soyref95.xls a zkonvertuje ji v SASový datový soubor SOYBEAN. Data se berou z listu REF95. Argumenty GETNAMES, ASSIGN a UNIQUE specifikují, že jména veličin se mají brát z prvního řádku tabulky a upravit, aby byla jednoznačná. Nakonec se mažou pracovní soubory pomocí procedury DATASETS.

2. Manipulace s datovými soubory SASu

2.1 Mazání datových souborů

Datový soubor můžeme v SASu smazat pomocí PROC DATASETS. Vymažme nyní dva soubory SOUB1 a SOUB2 z dočasného pracovního direktoráře (knihovna WORK):

PROC DATASETS LIBRARY=work;
  DELETE soub1 soub2;
RUN;

Chceme-li vymazat všechny soubory v daném direktoráři, napíšeme

PROC DATASETS LIBRARY=mojedir;
  DELETE ALL;
RUN;

kde MOJEDIR je dříve definovaný libref daného direktoráře (třeba LIBNAME mojedir c:\vyzkum\data\stara';).

2.2 Vypsání názvů veličin

Chceme-li vědět, jaké veličiny obsahuje daný datový soubor, zdali jsou numerické nebo znakové a jak jsou formátovány, spustíme proceduru CONTENTS. Použití je prosté:

PROC CONTENTS DATA=anketa; RUN;

Pokud potřebujeme názvy veličin uchovat k pozdějšímu zpracování, zapíšeme výstup z procedury CONTENTS do datového souboru.

PROC CONTENTS DATA=anketa NOPRINT OUT=veliciny; RUN;
PROC PRINT DATA=veliciny; RUN;

Argument NOPRINT zabrání textovému výstupu na obrazovku při provedení procedury CONTENTS. Výsledky jsou zapsány v datovém souboru VELICINY, bohužel v poněkud nepřehledném stavu.

2.3 Vytvoření (upravené) kopie datového souboru

Manipulace s daty a úpravy datových souborů můžeme provádět v okamžiku vytváření datového souboru (viz kapitola 1) anebo později již jednou vytvořený soubor modifikovat. Obojí se provádí v rámci datové procedury DATA.

Předpokládejme nyní, že máme existující datový soubor MOJEDATA, který chceme upravit. Program vypadá takto:

DATA mojedata;
  SET mojedata;
  < příkazy >
RUN;

Příkaz SET mojedata znamená, že SAS má načíst datový soubor MOJEDATA. Poté provede úpravy podle zadaných příkazů a výsledek je uschován zase pod jménem MOJEDATA (jméno vytvářeného souboru jest dáno úvodním příkazem DATA mojedata). Původní obsah souboru MOJEDATA je tedy přepsán, ale pouze pokud celá procedura DATA proběhne úspěšně. Pokud dojde k běhové či syntaktické chybě, původní soubor zůstává nezměněn.

Jestliže chceme uschovat modifikovaný soubor pod jiným jménem, napíšeme

DATA novadata;
  SET mojedata;
  < příkazy >
RUN;

Výsledek je uložen v nově vytvořeném souboru NOVADATA. Zase platí, že v případě chyby se žádný soubor nevytvoří.

2.4 Vytvoření nových veličin

Důležitá vysvětlující poznámka k fungování datových procedur:Vnitřek datové procedury, tj. všechny příkazy, které definují a upravují hodnoty jednotlivých veličin, ve skutečnosti funguje jako jeden velký zamlčený for-cyklus, který běží přes všechna pozorování a pro každé z nich postupně provádí jednotlivé příkazy v daném pořadí. V okamžiku, kdy je jedna smyčka for-cyklu u konce, vyplivne se jedno pozorování do vytvářeného souboru. Proto záleží na pořadí jednotlivých příkazů v datové proceduře.

2.4.1 Transformace

SAS má vestavěnou řadu matematických funkcí, které můžeme použít k jednoduchým transformacím numerických veličin. Seznam funkcí je uveden v nápovědě, přístup k němu je však poměrně komplikovaný. Je třeba postupně zvolit Help/SAS System/SAS System Help: Main Menu/SAS Languaue/SAS Functions/Function Categories. Zde je příklad s použitím datového souboru ANKETA (10 pozorování, veličiny ID, POHL, VEK, PRIJEM, R1, R2, R3):

DATA anketa; SET anketa;
  x      = ranuni(123);     /* Náhodné číslo z R(0,1)     */
  lny    = log(prijem);     /* Přirozený logaritmus       */
  logy   = log10(prijem);   /* Dekadický logaritmus       */
  rooty  = sqrt(prijem);    /* Odmocnina                  */
  expy   = exp(prijem/10);  /* e^x                        */
  cos    = cos(x);          /* kosinus                    */
  sin    = sin(x);          /* sinus                      */
  tan    = tan(x);          /* tangens                    */
  cosz   = cos(z);          /* neproveditelná transformace*/
  z      = ranuni(0);
RUN;

Výsledný soubor, taktéž zvaný ANKETA, má 10 pozorování a 17 veličin: 7 původních ID-R3 a 10 nově přidaných. Veličina COSZ se sice vytvoří, ale obsahuje samé chybějící hodnoty. To se stalo proto, že COSZ je transformací veličiny Z, ale ta se počítá až nakonec. Proto v okamžiku výpočtu cos(z) hodnota z ještě není definována.

2.4.2 Operátory

Nejdůležtější aritmetické, logické a řetězcové operátory jsou uvedeny v následující tabulce ve skupinách podle priority. Operátory s vyšší prioritou se vykonávají dříve než operátory s nižší prioritou. Operátory patřící do téže skupiny se vykovávají zleva doprava.

Skupina Typ operátoru Operátor Popis Příklad
0   () závorky y = 3*(x+1);
1 Aritmetický ** mocnění y = x**2;
2 Aritmetický +,- unární plus, minus y = -x;
Aritmetický * násobení y = x * z;
4 Aritmetický +
-
sčítání
odčítání
y = x + 3;
z = y - 3*x;
5 Řetězcový || spojování řetězců jmeno = krestni || prijmeni;
6 Množinový in logická konstanta:
je hodnota prvem možiny?
y = x in (1,2,3,4); 
gender in ('F','M');
7 Logický =, eq rovná se if x = 12;
  Logický <>, ne není rovno if x ne 5;
  Logický >, gt je větší if sin(x) > 0.4;
  Logický <, lt je menší if cos(x) < sin(z);
  Logický >=, ge větší nebo rovno  
  Logický <=, le  menší nebo rovno  
8 Logický and logická konjunkce if (a=b) and (sin(x)>0.3);
  Logický or logická alternativa if (a=b) or (sin(x) < 0.3);
  Logický not negace if not (a=b);

2.4.3 Logické výrazy

Logické výrazy v SASu vracejí hodnotu 1 pro pravdivý výrok, 0 pro nepravdivý. Toho lze využívat například pro kategorisaci spojitých veličin. Jako příklad ukážeme, jak vytvořit ze spojité veličiny VEK věkové skupiny označené 1, 2, 3.

DATA anketa; SET anketa;
  veksk = (vek <= 25) + 2*((vek > 25) and (vek <=40)) + 3*(vek > 41);
RUN;

Pozorování s věkem do 25 let mají VEKSK=1, nad 25 let ale do 40 let mají VEKSK=2, nad 40 let VEKSK=3. Stejného výsledku lze docílit pomocí IF...THEN...ELSE:

DATA anketa; SET anketa;
  IF vek <= 25 THEN veksk = 1;
    ELSE IF vek <=40 THEN veksk = 2;
      ELSE veksk = 3;
RUN;

2.5 Přejmenovávání veličin

Přejmenovávání veličin v SASu není složité, ale nese s sebou nečekaný háček, na který je třeba dávat pozor. Jsou dva různé způsoby přejmenovávání veličin a v obou hraje roli klíčové slovo RENAME. To můžeme použít buď jako samostatný příkaz uvnitř datové procedury anebo jako argument pro příkaz SET. První způsob vypadá takto:

DATA druha;
  SET prvni;
  RENAME xstare=xnove ystare=ynove;
RUN;

A teď RENAME= jako argument:

DATA druha;
  SET prvni(RENAME=(xstare=xnove ystare=ynove));
RUN;

V obou případech musíme uvést seznam přejmenovávaných veličin ve tvaru <staré jméno>=<nové jméno>. Rozdíl mezi oběma způsoby spočívá v tom, že RENAME jako příkaz provede přejmenování až po úspěšném ukončení celé datové procedury, zatímco RENAME= jako argument přejmenovává veličiny už v okamžiku, kdy jsou kopírovány z původního datového souboru. To znamená, že pokud chceme uvnitř datové procedury s přejmenovávanými veličinami pracovat, musíme používat jejich stará jména, pokud používáme RENAME jako příkaz a jejich nová jména, pokud používáme RENAME= jako argument. Jako ilustraci uvádíme dva příklady:

DATA druha;
  SET prvni;
  RENAME xstare=xnove ystare=ynove;
  logx=log(xstare); logy=log(ystare); 
RUN;
DATA druha;
  SET prvni(RENAME=(xstare=xnove ystare=ynove));
  logx=log(xnove); logy=log(ynove);
RUN;

2.6 Mazání veličin z datového souboru

Veličiny, kterých se chceme zbavit, můžeme smazat z datového souboru buď pomocí příkazu DROP anebo argumentu DROP příkazu SET. První možnost vypadá takto:

DATA anketa;
   SET anketa;
   DROP r1 r2 r3;
RUN;

Zde je příklad na druhou možnost:

DATA anketa;
   SET anketa (DROP=r1 r2 r3);
RUN;

V obou případech smažeme veličiny R1, R2 a R3. Bývalo by bylo možné ušetřit si psaní a místo r1 r2 r3 napsat r1-r3 se stejným výsledkem.

Jemný rozdíl mezi těmito dvěma způsoby se ukáže, chceme-li mazané veličiny nejprve použít k výpočtům. Například pokud nás nezajímá R1, R2 a R3, ale pouze součet R1+R2+R3, musíme použít

DATA anketa;
   SET anketa;
   r=r1+r2+r3;
   DROP r1 r2 r3;
RUN;

Zde se totiž mazání provede až nakonec, když už jsou výpočty hotové. Druhý způsob, tj.

DATA anketa;
   SET anketa (DROP=r1 r2 r3);
   r=r1+r2+r3;
RUN;

nefunguje, neboť veličiny R1, R2 a R3 se smažou (resp. vůbec nenačtou) a R obsahuje jen chybějící hodnoty, protože součet nelze spočítat.

Pokud chceme mazat většinu veličin a ponechat jen pár, vyplatí se vyjmenovat pouze ty, které mají zůstat. Pak můžeme použít KEEP namísto DROP. Syntaxe a význam se nemění. Příklady:

DATA anketa; SET anketa; KEEP vek prijem; RUN;

anebo

DATA anketa; SET anketa (KEEP=vek prijem); RUN;

2.7 Vynechání pozorování z datového souboru

Pokud chceme zpracovávat pouze určitou podmnožinu všech pozorování definovanou pomocí dané logické podmínky, můžeme vytvořit nový zmenšený datový soubor obsahující žádanou podmnožinu a ten pak dále zpracovávat, nebo používat původní soubor a stanovit, která pozorování se mají zpracovat. Druhá alternativa využívá argument WHERE=podmínka, který můžeme přidat ke jménu souboru (do závorek) kdekoliv je to třeba. Například, chceme-li vypsat ze souboru ANKETA všechna pozorování, která mají věk nad 35 let, dáme

PROC PRINT DATA=anketa(WHERE=(vek>35));
RUN;

Podobně postupujeme při volání jakýchkoli jiných procedur.

Chceme-li raději vytvořit nový datový soubor, napíšeme dovnitř datové procedury, která pozorování se mají ponechat, resp. smazat. Například

DATA anketa2;
  SET anketa;
  IF vek>35;
RUN;

Podmínka IF stanovuje, která pozorování se mají ponechat. Místo toho můžeme popsat, která pozorování se mají vymazat. To by vypadalo takto:

DATA anketa2;
  SET anketa;
  IF vek<=35 THEN DELETE;
RUN;

Do třetice můžeme použít i argument WHERE:

DATA anketa2; SET anketa(WHERE=(vek>35)); RUN;

2.8 Vertikální spojování datových souborů

Vertikální spojování (setting) znamená v podstatě přidávání nových pozorování k původnímu souboru. Mějme dva datové soubory, jeden s n1 pozorováními a množinou veličin V1, druhý s n2 pozorováními a množinou veličin V2. Spojíme-li tyto soubory vertikálně, vznikne datový soubor o n1+n2 pozorováních, který bude mít za množinu veličin sjednocení V1 a V2. Veličiny, které jsou definovány pouze v jednom z datových souborů budou mít chybějící hodnoty pro všechna pozorování pocházející z druhého datového souboru.

Vertikální spojování se provádí několika různými způsoby. První způsob spočívá v uvedení výčtu jmen spojovaných souborů (i více než dva) v příkazu SET datové procedury. Spojený soubor pak můžeme uložit pod libovolným jménem. Jako příklad nyní spojme vertikálně dva datové soubory. Jeden má 15 pozorování a veličiny BLOK, OSETR, RUST, ROK. Druhý má 10 pozorování a veličiny BLOK, OSETR, RUST a SUM. Spojený soubor tedy bude mít 25 pozorování a 5 veličin.

DATA hrach1;
  INPUT blok osetr rust @@;
  rok = 1997;
  DATALINES;
1 1 7.84  2 1 8.69  3 1 8.11  4 1 7.74   5 1 8.35
1 2 6.78  2 2 6.69  3 2 6.95  4 2 6.41   5 2 6.64
1 3 6.79  2 3 6.79  3 3 6.79  4 3 6.43   5 3 6.61
;
RUN;

Zde je vypsáno prvních 6 pozorování souboru HRACH1:

PROC PRINT DATA=hrach1(OBS=6); RUN;
OBS    BLOK    OSETR    RUST     ROK
  1      1       1      7.84    1997
  2      2       1      8.69    1997
  3      3       1      8.11    1997
  4      4       1      7.74    1997
  5      5       1      8.35    1997
  6      1       2      6.78    1997

Vytvořme druhý soubor HRACH2:

DATA hrach2;
  INPUT blok osetr rust @@;
  sum=ranuni(545);
  DATALINES;
1 4 6.64  2 4 6.57   3 4 6.78   4 4 6.54   5 4 6.48
1 5 7.31  2 5 7.65   3 5 7.26   4 5 6.98   5 5 7.39
;
RUN;

Vypišme na ukázku jen první tři pozorování:

PROC PRINT DATA=hrach2(OBS=3); RUN;
OBS    BLOK    OSETR    RUST      SUM
  1      1       4      6.64    0.80460
  2      2       4      6.57    0.69835
  3      3       4      6.78    0.90425

Nyní spojíme HRACH1 a HRACH2 vertikálně:

DATA hrach; SET hrach1 hrach2; RUN;
PROC PRINT DATA=hrach; RUN;
OBS    BLOK    OSETR    RUST     ROK      SUM
  1      1       1      7.84    1997     .
  2      2       1      8.69    1997     .
... dalších 11 pozorování ...
 14      4       3      6.43    1997     .
 15      5       3      6.61    1997     .
 16      1       4      6.64       .    0.80460
 17      2       4      6.57       .    0.69835
... dalších 6 pozorování ...
 24      4       5      6.98       .    0.13774
 25      5       5      7.39       .    0.27877

Druhá metoda vertikálního spojování souborů používá proceduru APPEND

PROC APPEND BASE=zaklad DATA=pridej; RUN;

a třetí příkaz APPEND procedury DATASETS

PROC DATASETS LIBRARY=work;
  APPEND BASE=zaklad DATA=pridej;
RUN;

Spojený soubor je v obou příkladech uložen pod jménem ZAKLAD. V případě, že veličiny v obou souborech nejsou totožné (což zahrnuje i znakové veličiny se stejným jménem ale různou délkou), musíme přidat argument FORCE jak do PROC APPEND tak do příkazu APPEND v PROC DATASETS:

PROC APPEND BASE=zaklad DATA=pridej FORCE; RUN;
PROC DATASETS LIBRARY=work;
  APPEND BASE=zaklad DATA=pridej FORCE;
RUN;

2.9 Horizontální spojování datových souborů

Při horizontálním spojování (merging) jde o přidávání nových veličin k původnímu souboru.

Horizontální spojování se používá, máme-li potřebné veličiny rozděleny v několika souborech s (v podstatě) totožnými pozorováními. Provádí se příkazem MERGE uvnitř datové procedury. V nejjednodušším případě dvou souborů s n pozorováními a množinami veličin V1 a V2 je výsledkem horizontálního spojení soubor s n pozorováními a veličinami V1 sjednoceno s V2. Zde je příklad s daty ANKETA: Předpokládejme, že základní informace o účastnících ankety (ID, POHL, VEK, PRIJEM) jsou uschovány v datovém souboru ZAKL a údaje o preferencích jednotlivých výrobků (R1, R2, R3) v souboru PREF. Máme tedy

DATA zakl;
   INPUT id pohl $ vek prijem;
   DATALINES;
 1  F  35 17
17  M  50 14
33  F  45  6
49  M  24 14
65  F  52  9
81  M  44 11
2   F  34 17
18  M  40 14
34  F  47  6
50  M  35 17
;
DATA pref;
   INPUT r1 r2 r3 ;
   DATALINES;
7 2 2
5 5 3
7 2 7
7 5 7
4 7 7
7 7 7
6 5 3
7 5 2
6 5 6
5 7 5
;
run;

Nyní tyto dva soubory spojíme horizontálně (vedle sebe):

DATA anketa;
  MERGE zakl pref;
RUN;

Výsledkem je soubor ANKETA:

PROC PRINT DATA=anketa; RUN;
OBS    ID   POHL    VEK   PRIJEM  R1    R2    R3
  1     1     F      35     17     7     2     2
  2    17     M      50     14     5     5     3
  3    33     F      45      6     7     2     7
  4    49     M      24     14     7     5     7
  5    65     F      52      9     4     7     7
  6    81     M      44     11     7     7     7
  7     2     F      34     17     6     5     3
  8    18     M      40     14     7     5     2
  9    34     F      47      6     6     5     6
 10    50     M      35     17     5     7     5

Kdyby soubory ZAKL a PREF obsahovaly aspoň jednu společnou proměnnou, její hodnoty ve výsledném souboru ANKETA by byly vzaty ze souboru PREF, protože ten byl v seznamu souborů příkazu MERGE poslední. Obecně tedy záleží na pořadí specifikace souborů v příkazu MERGE. Kdyby měl soubor ZAKL n1 pozorování a soubor PREF n2<n1 pozorování, vyplnilo by se posledních n1-n2 pozorování ve veličinách R1-R3 chybějícími hodnotami.

Složitější příklady horizontálního spojování datových souborů jsou uvedeny v kapitole 2.10.2 Příkaz BY při spojování setříděných souborů.

2.10 Třídění dat a použití setříděných dat

Třídění dat obecně znamená seřazení pozorování podle hodnot určité veličiny (veličin). Ale pozor! Pro SAS jsou setříděná data něčím víc než seřazenými pozorováními: Můžeme mít data seřazená v určitém pořadí už od samého počátku, kdy z nich teprve vytváříme SASový soubor, ale pro SAS stejně nebudou setříděná, dokud je neproženeme třídící procedurou. Za chvíli vysvětlíme proč. Setříděná data se v SASu používají, kdykoli potřebujeme provést nějakou proceduru po skupinách podle hodnot určité veličiny. SAS toto umožňuje velmi snadno použitím příkazu BY.

Třídící procedura v SASu se nazývá PROC SORT. Její základní syntaxe je jednoduchá:

PROC SORT DATA=soubor;
   BY <seznam veličin>;
RUN;

Jméno souboru, který se má třídit, je uvedeno v argumentu DATA=. Příkaz BY uvádí seznam veličin, podle kterých se mají data třídit, oddělený mezerami. Nejprve se třídí podle hodnot první veličiny, uvnitř každé její hodnoty se třídí podle druhé veličiny, atd. Z definice se třídění provádí vzestupně podle všech veličin. Chceme-li třídit podle některé veličiny sestupně, připíšeme před její jméno v seznamu BY klíčové slovo DESCENDING. Setříděným souborem se přepíše původní datový soubor. Pokud chceme setříděný soubor raději uschovat pod jiným jménem, musíme si o to říci specifikací argumentu OUT= pro proceduru SORT: PROC SORT DATA=soubor OUT=utrid; Výsledek pak bude uložen jako datový soubor UTRID.

PROC SORT nejenom mění pořadí pozorování v datech, ale přidává do souboru nové skryté veličiny. Jsou-li například data setříděna procedurou SORT podle veličiny TRIDA, vytvoří se navíc veličiny FIRST.TRIDA a LAST.TRIDA s hodnotami 0 a 1, jež udávají jedničkou, které pozorování je první resp. poslední ve své skupině (definované hodnotami veličiny TRIDA). Tyto veličiny normálně nelze zobrazit, ale SAS s nimi počítá a uživatel k nim má přístup alespoň uvnitř datové procedury obsahující příkaz BY trida. Toto je důvod, proč je třeba procedurou SORT třídit i soubory, které jsou naprosto uspořádané.

Příklady třídění: datový soubor HRACH

DATA hrach;
  INPUT blok osetr rust @@;
  DATALINES;
1 3 6.79  2 3 6.79  3 3 6.79  4 3 6.43   5 3 6.61
1 1 7.84  2 1 8.69  3 1 8.11  4 1 7.74   5 1 8.35
1 2 6.78  2 2 6.69  3 2 6.95  4 2 6.41   5 2 6.64
1 5 7.31  2 5 7.65  3 5 7.26  4 5 6.98   5 5 7.39
1 4 6.64  2 4 6.57  3 4 6.78  4 4 6.54   5 4 6.48
;
RUN;
PROC PRINT DATA=hrach; RUN;
OBS    BLOK    OSETR    RUST
  1      1       3      6.79
  2      2       3      6.79
  3      3       3      6.79
  4      4       3      6.43
  5      5       3      6.61
  6      1       1      7.84
  7      2       1      8.69
  8      3       1      8.11
  9      4       1      7.74
 10      5       1      8.35
 11      1       2      6.78
 12      2       2      6.69
 13      3       2      6.95
 14      4       2      6.41
 15      5       2      6.64
 16      1       5      7.31
 17      2       5      7.65
 18      3       5      7.26
 19      4       5      6.98
 20      5       5      7.39
 21      1       4      6.64
 22      2       4      6.57
 23      3       4      6.78
 24      4       4      6.54
 25      5       4      6.48

Nyní setřídíme data podle ošetření a podle bloku:

PROC SORT DATA=hrach; BY osetr blok; RUN;

Zde je prvních 15 pozorování setříděného souboru včetně normálně neviditelných veličin FIRST.OSETR,  LAST.OSETR, FIRST.BLOK a LAST.BLOK, které se musejí zobrazovat trikově:

OBS    BLOK    OSETR    RUST  FIRST.OSETR LAST.OSETR FIRST.BLOK LAST.BLOK
  1      1       1      7.84       1          0          1         1
  2      2       1      8.69       0          0          1         1
  3      3       1      8.11       0          0          1         1
  4      4       1      7.74       0          0          1         1
  5      5       1      8.35       0          1          1         1
  6      1       2      6.78       1          0          1         1
  7      2       2      6.69       0          0          1         1
  8      3       2      6.95       0          0          1         1
  9      4       2      6.41       0          0          1         1
 10      5       2      6.64       0          1          1         1
 11      1       3      6.79       1          0          1         1
 12      2       3      6.79       0          0          1         1
 13      3       3      6.79       0          0          1         1
 14      4       3      6.43       0          0          1         1
 15      5       3      6.61       0          1          1         1

Veličiny FIRST.BLOK a LAST.BLOK obsahují samé jedničky, protože kombinace úrovní veličin OSETR a BLOK obsahují jediné pozorování, které je  je zároveň první i poslední.

Chceme-li setřídit hodnoty BLOK sestupně uvnitř každé úrovně veličiny OSETR, napíšeme

PROC SORT DATA=hrach; BY osetr DESCENDING blok; RUN;

Potřebujeme-li setříděná data uložit do jiného souboru, abychom si nepřepsali HRACH, použijeme

PROC SORT DATA=hrach OUT=hrach2; BY osetr blok; RUN;

Nyní si ještě ukážeme, jak použít skryté veličiny FIRST.OSETR a LAST.OSETR v datové proceduře. Naším úkolem bude vypsat první pozorování z každé úrovně veličiny OSETR:

PROC SORT DATA=hrach; BY osetr blok; RUN;
DATA jedno;
  SET hrach;
  BY osetr;
  IF first.osetr;
RUN;

Výsledkem je soubor s pěti pozorováními:

OBS    BLOK    OSETR    RUST
 1       1       1      7.84
 2       1       2      6.78
 3       1       3      6.79
 4       1       4      6.64
 5       1       5      7.31

2.10.1 Příkaz BY v PROCedurách

Příkaz BY lze použít v jakékoli vlastní PROCeduře nebo datové proceduře DATA. Jeho význam v datové proceduře je diskutován ve 2.10.2. Ve vlastní PROCeduře má BY vždycky stejný efekt: procedura se provede zvlášť pro každou kombinaci úrovní veličin uvedených v příkazu BY. Je to stejné, jako bychom předem rozdělili datový soubor na několik podskupin a pak postupně spouštěli proceduru na každé podskupině. Podmínkou použití příkazu BY je předchozí setřídění datového souboru procedurou SORT.

Příkaz BY může být umístěn kdekoli uvnitř procedury a má syntaxi

BY <seznam veličin>;

Seznam veličin, jejichž úrovně se mají kombinovat je oddělen mezerami. Datový soubor musí být předtím setříděn procedurou SORT. Seznam veličin uvedených v příkazu BY musí zahrnovat prvních několik veličin, podle kterých byl soubor setříděn, a to ve stejném pořadí, nikoli však nutně všechny. Například jestliže třídící procedura třídila podle veličin X, Y, Z, U (tj. proběhlo PROC SORT DATA=zkus; BY x y z u; RUN;) , můžeme použít následující příkazy BY:

BY x;
BY x y;
BY x y z;
BY x y z u;

ale nikoli třeba

BY y;
BY x u;

Zde je příklad použití příkazu BY: Procedura MEANS počítá popisné statistiky zadané veličiny, např. průměr, či směrodatnou odchylku. Potřebujeme-li spočítat tyto statistiky pro veličinu RUST v datovem souboru HRACH, napíšeme

PROC MEANS DATA=hrach;
  VAR rust;
RUN;

Chceme-li ale tyto statistiky zvlášť pro každé ošetření, setřídíme nejprve soubor HRACH podle veličiny OSETR a pak spustíme

PROC MEANS DATA=hrach;
  VAR rust;
  BY osetr;
RUN;

2.10.2 Příkaz BY při spojování setříděných souborů

Příkaz BY má důležitou úlohu při horizontálním spojování datových souborů. Pokud totiž chceme takto spojit dva soubory, které si navzájem neodpovídají uspořádáním jednotlivých pozorování nebo jejich počtem, musíme jednotlivá pozorování identifikovat pomocí jedné nebo několika veličin vyskytujících se v obou souborech (tzv. propojovací veličiny) a pak je správně sestavit. K tomu slouží kombinace příkazů BY a MERGE uvnitř datové procedury, kde v příkazu BY vypíšeme seznam všech propojovacích veličin. Jako vždy při použití příkazu BY musí být oba soubory uspořádány podle všech veličin, které se v příkazu BY vyskytují.

Nejjednodušší situace je spojování dvou souborů, které mají nejvýše jedno pozorování na každou kombinaci propojovacích veličin. Uvažujme následující příklad: V zemědělské studii sledujeme dvě úrovně hnojení fosforem, 0 a 25 liber na akr (veličina P), a tři úrovně vzdálenosti mezi řádky, 40, 80 a 120 cm (veličina VZD). Na každou kombinaci úrovní P a VZD máme 3 políčka identifikovana čísly 1-3 (veličina POLE). Políčka byla osázena a sklizena v roce 1996 a 1997 a bylo zaznamenáno množství sklizené plodiny v obou letech (veličiny UROD96 a UROD97). Ale data jsou ve dvou souborech, zvlášť pro rok 1996 a zvlášť pro rok 1997 a ne všechna políčka byla osázena v obou letech. Nás by zajímal rozdíl v úrodě mezi oběma roky. Proto musíme nejprve oba soubory spojit do jednoho a všechna pozorování přitom správně navázat. Zde jsou data pro oba roky:

DATA pole96;
  INPUT p vzd pole urod96;              
  DATALINES;
0   40  1 57
0   40  2 58
0   80  1 57
0   80  2 58
0   80  3 56
0  120  1 49
0  120  2 54
0  120  3 53
25  40  1 53
25  40  2 45
25  40  3 46
25  80  1 54
25  80  2 50
25  80  3 48
25 120  1 63
25 120  2 57
25 120  3 53
;
RUN;
DATA pole97;
  INPUT p vzd pole urod97;
  DATALINES;
0   40  1 35
0   40  2 28
0   40  3 29
0   80  1 38
0   80  2 29
0   80  3 27
0  120  1 10
0  120  2 25
0  120  3 34
25  40  1 24
25  40  2 24
25  40  3 17
25  80  1 25
25  80  2 31
25  80  3 29
25 120  1 44
25 120  3 28
;
RUN;

Jednotlivá pozorování jsou jednoznačně charakterisována kombinací úrovní veličin P, VZD a POLE: to jsou propojovací veličiny. Ale všimněme si, že v souboru POLE96 chybí pole č. 3 při P=0 a VZD=40 a v souboru POLE97 chybí pole č. 2 při P=25 a VZD=120. Pokud tyto soubory spojíme takto:

DATA polesp1;
  MERGE pole96 pole97;
RUN;

propojí se pozorování z obou souborů přesně v tom pořadí, v jakém jsou uvedena v obou souborech a hodnoty veličin P, VZD a POLE se vezmou ze souboru POLE97. Výsledek bude naprosto chybný. My musíme místo toho propojit pozorování, která mají stejnou kombinaci úrovní P, VZD a POLE. Proto nejprve obě data setřídíme:

PROC SORT DATA=pole96; BY p vzd pole; RUN;
PROC SORT DATA=pole97; BY p vzd pole; RUN;

a nyní použijeme MERGE s příkazem BY:

DATA polesp2;
  MERGE pole96 pole97;
  BY p vzd pole;
RUN;

Porovnejme nyní, jak vypadají ony spojené soubory:

Nesprávný:
PROC PRINT DATA=polesp1; RUN;
OBS     P     VZD    POLE     UROD96     UROD97     
  1     0      40      1        57         35
  2     0      40      2        58         28
  3     0      40      3        57         29
  4     0      80      1        58         38
  5     0      80      2        56         29
  6     0      80      3        49         27
  7     0     120      1        54         10
  8     0     120      2        53         25
  9     0     120      3        53         34
 10    25      40      1        45         24
 11    25      40      2        46         24
 12    25      40      3        54         17
 13    25      80      1        50         25
 14    25      80      2        48         31
 15    25      80      3        63         29
 16    25     120      1        57         44
 17    25     120      3        53         28
Správný:
PROC PRINT DATA=polesp2; RUN;
OBS     P     VZD    POLE     UROD96     UROD97
  1     0      40      1        57         35
  2     0      40      2        58         28
  3     0      40      3         .         29
  4     0      80      1        57         38
  5     0      80      2        58         29
  6     0      80      3        56         27
  7     0     120      1        49         10
  8     0     120      2        54         25
  9     0     120      3        53         34
 10    25      40      1        53         24
 11    25      40      2        45         24
 12    25      40      3        46         17
 13    25      80      1        54         25
 14    25      80      2        50         31
 15    25      80      3        48         29
 16    25     120      1        63         44
 17    25     120      2        57          .
 18    25     120      3        53         28
Nyní můžeme ze souboru POLESP2 správně spočítat rozdíl úrod v roce 96 a 97.

Příkaz BY je užitečný také pro spojování dvojic souborů, kde jednomu pozorování v prvním odpovídá několik pozorování ve druhém. Takové situace vznikají tehdy, obsahuje-li jeden soubor údaje specifické pro jednotlivá pozorování a jiný soubor údaje společné celým skupinám pozorování. Zde je příklad: Zkoumáme tři ošetření, každé z nich aplikujeme na 5 subjektů a děláme dvě laboratorní měření. Data vypadají takto:

DATA mereni;
  INPUT osetr subj mer1 mer2;
  DATALINES;
  1  1  -0.3  -0.2
  1  2  -0.5   2.2
  1  3  -1.1   2.4
  1  4   1.0   1.7
  1  5  -0.3   0.8
  2  1  -1.1  -2.2
  2  2  -1.4  -0.2
  2  3  -0.1  -0.1
  2  4  -0.2   0.1
  2  5  -0.1  -0.2
  3  1  -1.8   0.2
  3  2  -0.5   0.0
  3  3  -1.0  -0.3
  3  4   0.4   0.4
  3  5  -0.5   0.9
;
RUN;

Chtěli bychom měření standartisovat, tj. odečíst od každé hodnoty MER1 a MER2 průměr přes příslušnou úroveň ošetření. Průměry máme uložené ve zvláštím souboru (v praxi takový získáme třeba jako výstup z PROC MEANS):

DATA prumery;
  INPUT osetr prumer1 prumer2;
  DATALINES;
  1       -0.24      1.38
  2       -0.58     -0.52
  3       -0.68      0.24
;
RUN;

Každé pozorování ze souboru PRUMERY tedy odpovídá pěti pozorováním ze souboru MERENI. Nyní potřebujeme spojit data z obou souborů tak, abychom ke každému pozorování znali průměr jeho úrovně ošetření. Použijeme horizontální spojování s příkazem BY, propojovací veličina bude OSETR. Nejdříve musíme oba datové soubory setřídit, pak je spojíme a hned spočteme standardisovaná měření:

PROC SORT DATA=mereni; BY osetr; RUN;
PROC SORT DATA=prumery; BY osetr; RUN;
DATA stand;
  MERGE mereni prumery;
  BY osetr;
  stmer1 = mer1 - prumer1;
  stmer2 = mer2 - prumer2;
RUN;

Toto je výsledek:

OBS    OSETR    SUBJ    MER1    MER2    PRUMER1   PRUMER2    STMER1    STMER2
  1      1        1     -0.3    -0.2     -0.24      1.38      -0.06     -1.58
  2      1        2     -0.5     2.2     -0.24      1.38      -0.26      0.82
  3      1        3     -1.1     2.4     -0.24      1.38      -0.86      1.02
  4      1        4      1.0     1.7     -0.24      1.38       1.24      0.32
  5      1        5     -0.3     0.8     -0.24      1.38      -0.06     -0.58
  6      2        1     -1.1    -2.2     -0.58     -0.52      -0.52     -1.68
  7      2        2     -1.4    -0.2     -0.58     -0.52      -0.82      0.32
  8      2        3     -0.1    -0.1     -0.58     -0.52       0.48      0.42
  9      2        4     -0.2     0.1     -0.58     -0.52       0.38      0.62
 10      2        5     -0.1    -0.2     -0.58     -0.52       0.48      0.32
 11      3        1     -1.8     0.2     -0.68      0.24      -1.12     -0.04
 12      3        2     -0.5     0.0     -0.68      0.24       0.18     -0.24
 13      3        3     -1.0    -0.3     -0.68      0.24      -0.32     -0.54
 14      3        4      0.4     0.4     -0.68      0.24       1.08      0.16
 15      3        5     -0.5     0.9     -0.68      0.24       0.18      0.66

Tento postup funguje, i když propojovací veličina nemá v obou souborech totožné úrovně. Například pokud máme k disposici pouze průměry pro ošetření 1 a 2

DATA prumery;
  INPUT osetr prumer1 prumer2;
  DATALINES;
  1       -0.24      1.38
  2       -0.58     -0.52
;
RUN;

můžeme oba soubory spojit jako předtím. Chceme-li mít ve spojených datech pouze pozorování se známými průměry, použijeme argument IN= příkazu MERGE:

PROC SORT DATA=mereni; BY osetr; RUN;
PROC SORT DATA=prumery; BY osetr; RUN;
DATA stand;
  MERGE mereni prumery(IN=jetam);
  BY osetr;
  IF jetam;
  stmer1 = mer1 - prumer1;
  stmer2 = mer2 - prumer2;
RUN;

Výsledkem je prvních 10 pozorování z předchozího výstupu.

2.11 Formátování veličin

Formátováním v SASu rozumíme zobrazování názvů veličin a jejich hodnot v textových výstupech v uživatelem zvolené podobě. Tím přinutíme SAS namísto kryptografických názvů veličin jako "OSETR"  psát srozumitelné "Ošetření" a namísto kódů jako "OSETR=1" nebo "OSETR=2" psát "Radiochemická dekontaminace" nebo "Otesání sekerou". Popisky pro názvy veličin nazýváme značky (labels), pro jednotlivé hodnoty používáme formáty (formats). Formátem rovněž můžeme definovat rozdělení hodnot spojité veličiny do několika skupin a pak používat zformátovanou spojitou veličinu jako faktor. Formáty sloužící ke čtení, nikoli k zápisu, se v SASu nazývají informats.

2.11.1 Značky (labels)

Značky jsou popisné řetězce přiřazené veličinám. Zavádějí se pro vybrané veličiny během datové procedury příkazem LABEL. Následující data pocházejí z experimentu sledujícího koncentraci chlorofylu v listech trávy ostřice při různých režimech hnojení dusíkem a ošetřování podloží.

DATA ostrice;
  LABEL blok = 'Číslo pozorování'
        dusik = 'Režim hnojení dusíkem'
        osetr = 'Ošetření podloží'
        chloro = 'Chlorofyl v listech (mg/g)';
  INPUT blok dusik osetr chloro;
  DATALINES;
  1  1  1  3.8
  1  1  2  5.3
  1  1  3  5.9
  ... < a tak dále>
  2  4  3  8.6
  ;
RUN;

Chceme-li použít značky ve výstupu PROC PRINT, musíme přidat argument LABEL:

PROC PRINT DATA=ostrice LABEL; RUN;
                         Režim                    Chlorofyl
           Číslo        hnojení     Ošetření      v listech
OBS      pozorování     dusíkem      podloží       (mg/g)
  1          1             1            1            3.8
  2          1             1            2            5.3
  3          1             1            3            5.9
.... atd.

2.11.2 Formáty

Formáty řídí zobrazení jednotlivých hodnot v textovém výstupu. Mohou buď předpisovat, jakým způsobem se mají datové hodnoty vypsat (jaká délka řetězců, kolik desetinných míst u reálného čísla, formát den-měsíc-rok pro datum), nebo původní hodnoty nahrazovat pro výstup jinými. Existuje celá řada předdefinovaných formátů, viz Help/SAS System/Base SAS Documentation/Language Reference/SAS Informats and Formats. Nyní si ukážeme, jak zavádět vlastní formáty pro výpis úrovní faktorových veličin. Použijeme PROC FORMAT:

PROC FORMAT;
    VALUE dusrez
      1='Urea' 2='Amm. sulf.' 3='IBDU' 4='Urea(SC)';
    VALUE ospod
      1='2 roky' 2='5 let' 3='8 let';
RUN;

Zde jsme zavedli dva formáty zvané DUSREZ a OSPOD. Použijeme-li formát OSPOD pro zápis veličiny, která nabývá hodnot 1-3, zobrazí se místo hodnoty 1 řetězec '2 roky' atd. Formáty určené pro znakové veličiny se definují obdobně, ale jejich jména musí začínat znakem $:

VALUE $pohlf 'F'='Žena' 'M'='Muž';

Formáty se přiřazují veličinám příkazem FORMAT uvnitř datové procedury. Přiřaďme tedy formát DUSREZ veličině DUSIK a formát OSPOD veličině OSETR:

DATA ostrice;
  LABEL blok = 'Číslo pozorování'
        dusik = 'Režim hnojení dusíkem'
        osetr = 'Ošetření podloží'
        chloro = 'Chlorofyl v listech (mg/g)';
  FORMAT dusik dusrez.
         osetr ospod.;
  INPUT blok dusik osetr chloro;
  DATALINES;
  1  1  1  3.8
  1  1  2  5.3
  1  1  3  5.9
  ... < a tak dále>
  2  4  3  8.6
  ;
RUN;

Ke jménům formátů v SASových programech se povinně přidává tečka na konec, jinak by SAS předpokládal, že se jedná o jména veličin. Takto vypadá formátovaný výstup z PROC PRINT DATA=ostrice LABEL; RUN; :

                      Režim                 Chlorofyl
          Číslo      hnojení    Ošetření    v listech
OBS    pozorování    dusíkem    podloží       (mg/g)
 1          1         Urea       2 roky        3.8
 2          1         Urea       5 let         5.3
 3          1         Urea       8 let         5.9
.... atd.

V datovém souboru OSTRICE jsou samozřejmě původní hodnoty veličin DUSIK a OSETR, takže chceme-li se omezit na pozorování s režimem hnojení Urea, píšeme:

DATA urea;
  SET ostrice;
  IF dusik = 1;
RUN;

2.11.3 Datum

Datum je v SASu vnitřně representováno jako počet dní od 1. 1. 1960. Potřebujeme-li tady načíst datum do SASového souboru, musíme specifikovat vhodný in-formát, který ho automaticky přepočte. Podobně musíme použít formát při výpisu data ve srozumitelné formě. Pokud chceme použít hodnotu datové veličiny uvnitř programu, například pro výběr pozorování, nezbývá, než používat přímo vnitřní representaci. Tak například všechna pozorování, jejichž datum (čehokoli) padá mezi 12. září 1997 a 16. květen 1998, vybereme takto:

DATA cosi; SET soubor;
  IF (datum >= 13769) AND (datum <= 14015);
RUN;

Poněkud elegantněji lze téhož dosáhnout takhle:

DATA cosi; SET soubor;
  IF (datum >= '12sep1997'd) AND (datum <='16may1998'd);
RUN;

Ano, řetězec ve tvaru 'DDmmmYYYY' následovaný ihned znakem d se přeloží jako vnitřní representace tohoto dne. mmm jsou první tři písmena anglického názvu měsíce.

Nyní uveďme příklad na používání formátů a informátů s datem. Napišme datovou proceduru, která přečte datum jako DD/MM/YY a vypíše ho jednak ve vnitřním formátu a jednak jako DDmmmYY.

DATA pisdatum;
  INPUT datum ddmmyy8.;
  FORMAT datum date8.;
  sasdatum=datum;
  DATALINES
01/01/60
12/09/97
16/05/98
;
RUN;

Informát pro vstup data byl ddmmyy8., po načtení se datum přepočítá na počet dní od 1. 1. 1960 a to se zapíše do veličiny DATUM. Veličina SASDATUM obsahuje totéž. Při výpisu se ovšem pro veličinu DATUM používá formát date8., zatímco veličina SASDATUM se vypisuje tak, jak je. Zde je výsledek:

PROC PRINT DATA=pisdatum; RUN;
OBS       DATUM    SASDATUM
 1      01JAN60          0
 2      12SEP97      13769
 3      16MAY98      14015

2.12  Výpočet počtu pozorování v datovém souboru

Počet pozorování je zaznamenán v textových výstupech většiny SASových procedur. Ke stejnému účelu může posloužit i následující makro, které spočítá pozorování a výsledek uschová ve zvolené makro proměnné:

%macro nobs(data,nvysl);
  %global &nvysl;
  data _null_;
   if 0 then set &data nobs=count;
   call symput ("&nvysl",left(put(count,8.)));
   stop;
  run;
%mend nobs;

Text makra se píše do okna Program Editoru a makro se zavede pomocí Submit (F8). Chceme-li makro spustit, napíšeme jen

%nobs(anketa,npoz);
%put &npoz;

Počet pozorování souboru ANKETA se vypíše do LOG okna.

3. Programování v datových procedurách SASu

3.1 Princip činnosti datové procedury

Datová procedura SASu má většinou následující strukturu:

DATA jmeno;
  <příkazy prováděné na začátku>
  <příkazy prováděné v cyklu>
  <příkazy prováděné na konci>
<případně DATALINES; následované hodnotami>
RUN;

Příkazy uvnitř se dělí do tří skupin. První skupinu tvoří příkazy jako SET, INPUT, INFILE, MERGE, které se provádějí obvykle hned na začátku. Ve druhé skupině jsou sekvence příkazů manipulující s jednotlivými hodnotami dat, jako transformace, přiřazení, IF, atd. Třetí skupinou jsou příkazy, které se vždy provádějí úplně nakonec, pokud celá procedura proběhne bez chyb. Takové jsou příkazy DROP, KEEP, či RENAME. Rozdíl je v tom, že první a třetí skupina příkazů se provádí jen jednou, buď na začátku nebo na konci, ale druhá skupina příkazů se provádí opakovaně v jakémsi utajeném for-cyklu, který běží přes všechna pozorování. To znamená, že se vezme jedno pozorování ze vstupních dat, provedou se s ním patřičné operace, výsledek se zapíše do výstupního souboru jako jedno pozorování a celý proces se opakuje s dalšími pozorováními, dokud se všechna nevyčerpají.

Proberme si nyní jednoduchý příklad, který do jisté míry ozřejmí některé z principů, vysvětlovaných v předchozím odstavci:

DATA prvni;
  INPUT x ;
  DATALINES;
0.1
0.5
1.0
2.0
-0.5
;
DATA druhe;
    SET prvni;
    y = log(x);
    IF y <  0 THEN z = 'záporné';
    IF y >= 0 THEN u = sqrt(y);
    KEEP u x y z;
    RENAME  z = jezap;
run;

Podívejme se na poslední datovou proceduru. Příkaz SET je příkaz první skupiny: ten načte obsah datového souboru PRVNI. Poslední dva příkazy patří do třetí skupiny a provedou se až nakonec. Uprostřed jsou sevřeny tři příkazy druhé skupiny, které se provádějí v cyklu pro každé pozorování datového souboru PRVNI. Vytvářejí se jimi tři nové veličiny: numerické Y a U a znaková Z. Nově vytvořená veličina se vždy na počátku každého průběhu cyklu iniciuje chybějící hodnotou, kterou representuje tečka . u numerické veličiny a prázdný řetězec "" u znakové. Všimněte si, že veličinám Z a U se přiřazuje jiná hodnota jen někdy, v závislosti na hodnotě veličiny X, potažmo Y. Nedojde-li k přiřazení nebo není-li přiřazení korektní, v datech zůstává chybějící hodnota, jak se můžeme přesvědčit prohlédnutím dat DRUHE:

OBS       X        Y        JEZAP        U
 1      0.1    -2.30259    záporné     .
 2      0.5    -0.69315    záporné     .
 3      1.0     0.00000               0.00000
 4      2.0     0.69315               0.83255
 5     -0.5      .         záporné     .

Všimněte si pátého pozorování: logaritmus záporného čísla se spočítal jako chybějící hodnota, ale ta je vzápětí prohlášena za zápornou. To není od SASu příliš korektní chování! SAS totiž chybějící hodnoty při srovnávání považuje za minus nekonečna. Mohli bychom tento problém obejít, kdybychom napsali IF y<0 AND y<>. THEN z='záporné';

Z tohoto systému zpracování vyplývá řada komplikací a chytáků, které je třeba si uvědomovat. Například v principu záleží na pořadí jednotlivých příkazů uvnitř datové procedury. Proto je dobré dodržovat rozdělení příkazů do oněch tří skupin a nemíchat je mezi sebou.

Jiným důsledkem je, že jednomu pozorování vstupního souboru normálně odpovídá jedno pozorování výstupního souboru. To se ne vždy hodí a pokud to chceme ovlivnit, musíme sami zasáhnout. Zabránit tomu, aby se určité pozorování vypsalo do výstupního souboru, je jednoduché. Stačí napsat prázdnou podmínku jako IF vek>55, nebo explicitně IF vek<=55 THEN DELETE. Naopak, chceme-li na jedno vstupní pozorování generovat několik výstupních, musíme použít klíčové slovo OUTPUT, které vydá pokyn k výpisu jednoho pozorování v tom stavu, v jakém zrovna je.

Protože pozorování se zpracovávají sekvenčně jedno po druhém, vzniká problém, kdykoli potřebujeme mít přístup i k hodnotám jiných pozorování, než je právě to, které zrovna zpracováváme. Máme jenom dva nástroje jak si pomoci: příkaz RETAIN a funkci LAG. Oba jsou diskutovány níže.

Existuje možnost používat cykly různého druhu uvnitř datové procedury. Takový cyklus se normálně provádí vnořeně do onoho implicitního for-cyklu přes všechna pozorování. Ale pokud vytváříme soubor bez jakýchkoli vstupních dat, například simulačně, onen uschovaný implicitní for-cyklus se neprovádí, protože ani není zřejmé, kolik pozorování by měl vytvářet. V takovém případě musíme celý cyklus vytvořit sami uvnitř datové procedury.

Všechny tyto problémy jsou do jisté míry vysvětleny v následujících kapitolách.

3.2 Přenos hodnot veličiny na další pozorování

Při přípravě dat často potřebujeme počítat například kumulované součty určitých veličin a jiné rekurentní výpočty. Zatím vysvětlené metody to neumožňují, neboť v datové proceduře můžeme normálně pracovat jen s jedním pozorováním a hodnoty ostatních jsou pro nás nedostupné. Řešením tohoto problému je příkaz RETAIN, který umožňuje přenášení hodnot zvolené veličiny na další pozorování. Pracuje se s ním takto:

DATA druhe;
  SET prvni;
  RETAIN c 0;
  c=c+x;
RUN;

Příkaz RETAIN c 0 způsobí, že veličina C se inicialisuje při prvním pozorování hodnotou 0 (nikoli chybějící hodnotou jako obvykle) a nadále je u každého dalšího pozorování k disposici její hodnota spočtená při předchozím pozorování. Přičítáme-li k ní tedy hodnotu X, vytváříme kumulativní součty veličiny X. Hle:

OBS       X     C
 1      0.1    0.1
 2      0.5    0.6
 3      1.0    1.6
 4      2.0    3.6
 5     -0.5    3.1

Stejnou věc lze spočítat zkratkovým zápisem

DATA druhe;
  SET prvni;
  c+x;
RUN;

SAS to pochopí jako přiřazení veličině C, která se má inicialisovat nulou a přenášet.

Příkaz RETAIN v kombinaci s tříděním SORT je vhodný pro počítání tabulek četností. Vezměme si datový soubor

DATA kravy;
  INPUT dojivost $1-10 cislo;
  DATALINES;
mizerná      1
dobrá        2
vynikající   3
mizerná      4
vynikající   5
mizerná      6
dobrá        7
dobrá        8
vynikající   9
mizerná      10
žádná        11
vynikající   12
vynikající   13
RUN;

Rádi bychom znali četnost kvality dojnic a jaká různá hodnocení dojivosti jsou vůbec možná. Nejprve krávy setřídíme:

PROC SORT DATA=kravy; BY dojivost; RUN;

a teď je spočítáme s použitím přenášených veličin CETNOST a KOLIK a vnitřních veličin FIRST.DOJIVOST a LAST.DOJIVOST:

DATA dojtridy;
  SET kravy;
  BY dojivost;
  RETAIN cetnost 0 kolik 0;
  IF first.dojivost THEN cetnost=1; ELSE cetnost+1;
  IF last.dojivost THEN kolik+1;
  IF last.dojivost;
RUN;

CETNOST zaznamenává počet krav v dané skupině a KOLIK počítá počet skupin. Výstup pozorování se provádí jen, jde-li o poslední pozorování ve své skupině, takže výsledný soubor bude mít tolik pozorování, kolik je skupin. A takhle to vypadá:

OBS    DOJIVOST      CISLO    CETNOST    KOLIK
 1     dobrá            8        3         1
 2     mizerná         10        4         2
 3     vynikající      13        5         3
 4     žádná           11        1         4

Veličina CISLO zde obsahuje identifikaci poslední nalezené krávy v každé skupině dojivosti.

3.3 DO bloky a smyčky

DO blok je množina příkazů uzavřená mezi klíčovými slovy DO a END. Používá se dvěma způsoby: buď k vložení skupiny příkazů na místo, kde se očekává příkaz jediný, anebo k definování cyklů. První způsob použití nezaslouží víc než prostý příklad:

DATA druha; SET prvni;
  IF x < 0 THEN DO;
    y = .;
    z = sqrt(-x) + rannor(123);
    T = 'Kontrola';
  END;
RUN;

Cykly se uvnitř datových procedur SASu dají použít v několika variantách:

For cyklus:
DO i = 1 to 4; 
  <příkazy>
END;
For cyklus přes znakové řetězce:
DO month = 'FEB', 'MAR', 'APR';
  <příkazy>
END;
Do-While cyklus
DO WHILE i<n;
  <příkazy>
END;
For cyklus s obecným krokem:
DO i = 1 to 10 by 2; 
  <příkazy>
END;
For cyklus s podmínkou:
DO k =1 to 12 WHILE(month='APR'); 
  <příkazy>
END;
Do-Until Cyklus:
DO UNTIL i>=m; 
  <příkazy>
END;
For cyklus přes vyjmenované hodnoty:
DO x = 10, 20, 30, 50 to 100 by 5; 
  <příkazy>
END;
   

Fungování těchto konstrukcí je zcela zřejmé. Je třeba mít poze na paměti, že probíhají uvnitř každého pozorování zvlášť (vnořené v onom utajeném velkém for-cyklu). Pouze v případě, kdy nenačítáme žádná data, onen velký for-cyklus neprobíhá a my ho sami musíme vytvořit. Zde je příklad simulace: vytvoření tisíce realisací náhodné veličiny s rozdělením chí kvadrát o šesti stupních volnosti:

DATA simul;
  DO n = 1 TO 1000;
    chikv=0;
      DO i=1 TO 6;
        znorm=rannor(7331);
        chikv=chikv+znorm**2;
      END;
    OUTPUT;
  END;
  KEEP chikv;
RUN;

Vnější cyklus přes N vytváří tisíc pozorování. Veličina CHIKV se iniciuje jako 0 a pak se do ní ve vnitřním cyklu přes I postupně přičítají kvadráty šesti nasimulovaných normálních veličin. Argument funkce RANNOR je seed - počáteční hodnota pro generátor náhodných čísel. Vyhodnocuje se jenom jednou v průběhu celé datové procedury (jinak bychom vygenerovali tisíc totožných chí-kvadrát veličin). Příkaz OUTPUT se provádí na konci každého cyklu přes N a způsobí vytvoření nového pozorování výstupního datového souboru a naplnění všech hodnot jeho veličin. Úplně nakonec vydáváme příkaz uchovat pouze veličinu CHIKV (vytvořili jsme také veličinu ZNORM, ale ta nás vůbec nezajímá). Další použití příkazu OUTPUT je diskutováno v kapitole 3.6.

3.4 Konstrukce IF .. THEN .. ELSE

Podmíněné příkazy tohoto typu slouží k selekci pozorování nebo jejich podmíněnému zpracovávání. Úplná verse této konstrukce je

IF <podmínka> THEN <příkaz1>; ELSE <příkaz2>;

ačkoli, jak již víme, klausule ELSE je nepovinná a lze ji vynechat. SAS očekává právě jeden příkaz jak za THEN tak za ELSE. Chceme-li podmíněně provádět skupiny více příkazů, musíme je uzavřít mezi DO a END. Zde je příklad:

DATA druhe; SET prvni;
  y=1;
  IF x < 0 THEN DO
      y = .;
      z = sqrt(-x);
    END;
  ELSE z = sqrt(x);
RUN;

Konstrukci IF .. THEN .. ELSE je možné řetězit:

DATA druhe; SET prvni;
  IF skore<4 THEN znamka='neprospěl';
    ELSE IF skore<6 THEN znamka='dobře';
      ELSE IF skore<8 THEN znamka='velmi dobře';
        ELSE znamka='výborně';
RUN;

Šikovnější příkaz pro takové roztřídění je ovšem SELECT (viz níže).

3.5 Konstrukce SELECT

Konstrukce SELECT nahrazuje sekvenci zřetězených příkazů IF .. THEN .. ELSE prováděných za účelem klasifikace pozorování do skupin. V příkladu na konci předchozí kapitoly se mají pozorování oznámkovat čtyřmi stupni výborněneprospěl na základě hodnot veličiny SKORE. Namísto tam uvedého řešení můžeme s výhodou využít přehlednější konstrukci

DATA druhe; SET prvni;
  SELECT;
    WHEN (skore<4) znamka='neprospěl';
    WHEN (skore<6) znamka='dobře';
    WHEN (skore<8) znamka='velmi dobře';
    OTHERWISE znamka='výborně';
  END;
RUN;

SAS postupně vyhodnocuje podmínky (musí být vypsány v závorkách) jednotlivých příkazů WHEN a jakmile najde první splněnou podmínku, provede příslušný příkaz a konstrukci SELECT opustí. Klausule OTHERWISE je nepovinná. Existuje i druhý způsob použití konstrukce SELECT vhodný jen pro diskrétní veličiny:

DATA druhe; SET prvni;
  SELECT (skore);
    WHEN (1,2,3) znamka='neprospěl';
    WHEN (4,5)   znamka='dobře';
    WHEN (6,7)   znamka='velmi dobře';
    OTHERWISE znamka='výborně';
  END;
RUN;

Zde se hodnota veličiny uvedené v závorce za příkazem SELECT porovnává s hodnotami, jejichž seznam oddělený čárkami je v závorkách za jednotlivými WHEN klausulemi. Jakmile některá s hodnot souhlasí s hodnotou veličiny, provede se příslušný příkaz a provádění konstrukce SELECT je ukončeno.

3.6 Pole (array)

Pole v SASu umožňují spojit dohromady několik veličin, nazvat je jedním jménem a přistupovat k nim pomocí indexů. Používají se uvnitř datové procedury, chceme-li si zjednodušit zpracování dat pomocí vnořeného cyklu. Uvažujme třeba tři veličiny X, Y a Z, které mají chybějící hodnoty zakódovány jako 9999. Potřebujeme všechny chybějící hodnoty najít a překódovat na tečky. Můžeme to udělat takto:

DATA druhe; SET prvni;
  IF x=9999 THEN x=.;
  IF y=9999 THEN y=.;
  IF z=9999 THEN z=.;
RUN;

To je snadné, pokud máme takové veličiny tři, ale nešikovné, je-li jich pár tuctů.  Pak se vyplatí použít pole:

DATA druhe; SET prvni;
  ARRAY xyz{3} x y z;
  DO i=1 TO 3;
    IF xyz{i}=999 THEN xyz{i}=.;
  END;
RUN;

Příkaz ARRAY jmpole{n} vel1 vel2 ... veln; definuje pole nazvané JMPOLE, které má N složek, totiž hodnoty veličin VEL1, ..., VELN (v našem příkladě má pole XYZ tři složky X, Y a Z). Namísto skutečných jmen jednotlivých veličin VEL1, ..., VELN můžeme nadále používat jen jméno pole s příslušným indexem ve složené závorce, tj. JMPOLE{1}, ..., JMPOLE{N}. To nám umožní těchto N veličin zpracovávat v cyklu přes nějakou indexovací proměnnou, jak je vidět na našem příkladě. Poznamenejme ještě, že u veličin pojmenovaných např. X1, X2, ..., X8 můžeme jejich seznam zapsat zkratkou X1-X8,  což značně zjednodušuje psaní definice pole.

Kromě plné syntaxe příkazu ARRAY

ARRAY pole{6} vel1-vel6;

jsou platné také některé zkrácené zápisy. Například ve

ARRAY pole{*} vel1-vel6;

se počet složek pole automaticky určí podle počtu spojovaných veličin. Také můžeme napsat

ARRAY pole{4};

Tento zápis je ekvivalentní příkazu

ARRAY pole{4} pole1 pole2 pole3 pole4;

tj. vytvoří se automaticky 4 veličiny se jmény tvaru POLEn.

Zde je jiný příklad na použití polí při zpracování dat. Původní data representují longitudinální měření teploty (v časech 0, 15, 30 a 45 dní) pro 15 jedinců rozdělených do tří skupin podrobených různým ošetřením:

DATA teploty;
  input osetr subjekt tepl1 tepl2 tepl3 tepl4;
  DATALINES;
  1  1  -0.3  -0.2   1.2   3.1
  1  2  -0.5   2.2   3.3   3.7
  1  3  -1.1   2.4   2.2   2.7
  1  4   1.0   1.7   2.1   2.5
  1  5  -0.3   0.8   0.6   0.9
  2  1  -1.1  -2.2   0.2   0.3
  2  2  -1.4  -0.2  -0.5  -0.1
  2  3  -0.1  -0.1  -0.5  -0.3
  2  4  -0.2   0.1  -0.2   0.4
  2  5  -0.1  -0.2   0.7  -0.3
  3  1  -1.8   0.2   0.1   0.6
  3  2  -0.5   0.0   1.0   0.5
  3  3  -1.0  -0.3  -2.1   0.6
  3  4   0.4   0.4  -0.7  -0.3
  3  5  -0.5   0.9  -0.4  -0.3
;
RUN;

Tato data byla připravena pro mnohorozměrnou analýzu pomocí procedury PROC GLM. Lepší metody statistické analysy těchto dat (lineární smíšené modely) však implementuje procedura PROC MIXED, která vyžaduje aby každé pozorování obsahovalo právě jedno měření teploty (s indikací subjektu, kterého se týká a času, kdy bylo učiněno). Potřebujeme tedy datovou strukturu tohoto tvaru:

OBS    OSETR    SUBJEKT    CAS    TEPLOTA
  1      1         1         0      -0.3
  2      1         1        15      -0.2
  3      1         1        30       1.2
  4      1         1        45       3.1
  5      1         2         0      -0.5
  6      1         2        15       2.2
  7      1         2        30       3.3
  8      1         2        45       3.7
  9      1         3         0      -1.1
 10      1         3        15       2.4
 11      1         3        30       2.2
 12      1         3        45       2.7
 13      1         4         0       1.0
 14      1         4        15       1.7
 15      1         4        30       2.1
 16      1         4        45       2.5

a tak dále, dohromady 4*15=45 pozorování. Přetransformování dat provede následující datová procedura:

DATA teploty2; SET teploty;
  ARRAY ptepl{4} tepl1-tepl4;   /* vytváří se pole pro 4 měření teploty                    */
  DO i=1 TO 4;                  /* for-cyklus přes 4 měření                                */
    cas=15*(i-1);               /* výpočet okamžiku měření (0, 15, 30, 45)                 */
    teplota=ptepl{i};           /* zapsání teploty do veličiny TEPLOTA                     */
    OUTPUT;                     /* pokyn k zápisu dalšího pozorování do výstupního souboru */
  END;
  DROP tepl1-tepl4 i;           /* zrušení nepotřebných veličin                            */
RUN;

Soubor TEPLOTY2 opravdu má požadovanou strukturu. Všimněte si použití příkazu OUTPUT uvnitř for-cyklu, který způsobí vygenerování čtyř pozorování souboru TEPLOTY2 na každé pozorování souboru TEPLOTY.

3.7 Funkce LAG: přístup k předchozím hodnotám veličin

Funkce LAG má podobný význam jako příkaz RETAIN, totiž umožnit přístup k hodnotám předchozích pozorování. Její použití je prosté: LAG(X) vrací hodnotu veličiny X z předchozího pozorování, LAG2(X) vrací hodnotu X o dvě pozorování nazpět a tak dále, až LAG100(X) vrací hodnotu o 100 pozorování nazpět. Každý výskyt funkce LAGN (N zastupuje číslo mezi 1 a 100) uvnitř datové procedury vytváří speciální frontu délky N, kterou inicialisuje N chybějícími hodnotami a při každém volání přidá jednu hodnotu na konec fronty a vrátí jednu hodnotu z vršku fronty. Jestliže se funkce LAGN provádí podmíněně (jen pro některá pozorování), uschovává do fronty pouze hodnoty těch pozorování, u nichž byla podmínka splněna. Zde je příklad aplikace na datový soubor TEPLOTY2:

DATA lagtepl; SET teploty2;
  lagcas=lag(cas);
  lagtep=lag(teplota);
  lag2subj=lag2(subjekt);
  IF cas=0 THEN lagtc0=lag(teplota);
RUN;

Zde je výsledek (prvních 20 pozorování):

OBS    OSETR    SUBJEKT    CAS    TEPLOTA    LAGCAS    LAGTEP    LAG2SUBJ    LAGTC0
  1      1         1         0      -0.3        .         .          .          .
  2      1         1        15      -0.2        0       -0.3         .          .
  3      1         1        30       1.2       15       -0.2         1          .
  4      1         1        45       3.1       30        1.2         1          .
  5      1         2         0      -0.5       45        3.1         1        -0.3
  6      1         2        15       2.2        0       -0.5         1          .
  7      1         2        30       3.3       15        2.2         2          .
  8      1         2        45       3.7       30        3.3         2          .
  9      1         3         0      -1.1       45        3.7         2        -0.5
 10      1         3        15       2.4        0       -1.1         2          .
 11      1         3        30       2.2       15        2.4         3          .
 12      1         3        45       2.7       30        2.2         3          .
 13      1         4         0       1.0       45        2.7         3        -1.1
 14      1         4        15       1.7        0        1.0         3          .
 15      1         4        30       2.1       15        1.7         4          .
 16      1         4        45       2.5       30        2.1         4          .
 17      1         5         0      -0.3       45        2.5         4         1.0
 18      1         5        15       0.8        0       -0.3         4          .
 19      1         5        30       0.6       15        0.8         5          .
 20      1         5        45       0.9       30        0.6         5          .

Všimněte si, že LAGTC0 obsahuje hodnotu teploty změřenou na předchozím subjektu v čase 0.

3.8 Vytváření několika datových souborů v jednom DATA bloku

Zde je příklad, jak v jedné datové proceduře třídit pozorování do několika vytvářených datových souborů:

FILENAME vsechno 'c:\vyzkum\chrousti\data\ozer.asc';
DATA ozer1996 ozer1997 ozer1998 ozer1999;
  INFILE vsechno;
  INPUT rok chrousti okres misto ozer okus oliz;
  SELECT(rok);
    WHEN (1996) OUTPUT ozer1996;
    WHEN (1997) OUTPUT ozer1997;
    WHEN (1998) OUTPUT ozer1998;
    OTHERWISE OUTPUT ozer1999;
  END;
RUN;

3.9 Konverze znakových veličin na numerické

Hodnoty znakové veličiny předěláme na numerické tím, že je přiřadíme numerické veličině. Typ veličin je v SASu určen v okamžiku jejich prvního použití, tj. při prvním přiřazení anebo v příkazu INPUT. Řetězce se též automaticky konvertují na čísla, jsou-li použity v aritmetické operaci.

DATA test;
  INPUT s $ ;
  x = 0;
  x = s;
  DATALINES;
  1
  2
  3
  4
  5
;
RUN;

Zde byla veličina S deklarována v příkazu input jako znaková. Její hodnoty pak byly převedeny do numerické veličiny X (přiřazení X=0 definuje X jako numerickou veličinu). Jiná možnost by byla nahradit dvojici přiřazení x=0; x=s; příkazem x=s+0;.

Návrat na hlavní stránku