データの入出力#
データを分析するためには、SASが理解できるデータセットとしてデータを読み込む必要があります。ここでは様々な状況で機能するデータの読み込み方法を学びます。ただし、SASデータセットにデータを読み込む際は、常に次の3つのことをSASに伝える必要があります。
データの場所 - プログラム内に埋め込まれた入力ストリームデータなのか、プログラム外部にある生データなのか、または別のSASデータセットに含まれているのか?
データの形式 - データ値が整然と定義された列に並んでいてカラム入力が使えるか、データ値が少なくとも1つの空白で区切られていてリスト入力が使えるか、データ値に特殊文字が含まれていてフォーマット入力を使わなければならないか?
作成するSASデータセットの種類 - 永久SASデータセットを作成するのか、一時SASデータセットを作成するのか?
ここでは、これらすべてのケースについて学びます。入力ストリームデータ、外部の生データ(csvファイルなど)、別のSASデータセットからのデータの読み込み方法を学びます。カラム入力、リスト入力、フォーマット入力の使い方も学びます。そして、一時データセットと永久データセットの作成方法も学びます。
入力ストリームデータの読み込み#
セクションのタイトルは「入力ストリームデータの読み込み」ですが、データをSASデータセットに読み込む方法のひとつだけに焦点をあてることは難しいです。前で説明したように、SASデータセットにデータを読み込む際は、常に3つのことをSASに伝える必要があります。データの場所、データの形式、作成するSASデータセットの種類です。さっそく例を見ていきましょう。
例#
次のプログラムでは、カラム入力を使って入力ストリームデータを読み込み、一時データセットtemp1を作成して、結果のデータセットにタイトルを付けて出力しています。
data temp1;
input subj 1-4 gender 6 height 8-9 weight 11-13;
datalines;
1024 1 65 125
1167 1 68 140
1168 2 68 190
1201 2 72 190
1302 1 63 115
;
run;
title 'Output dataset: TEMP1';
proc print data=temp1;
run;
OBS | subj | gender | height | weight |
---|---|---|---|---|
1 | 1024 | 1 | 65 | 125 |
2 | 1167 | 1 | 68 | 140 |
3 | 1168 | 2 | 68 | 190 |
4 | 1201 | 2 | 72 | 190 |
5 | 1302 | 1 | 63 | 115 |
DATALINESステートメントは、その後に続く行がデータであることをSASに示します。DATALINESに続くすべての行はデータとして扱われ、セミコロン(;)が現れるまで続きます。このセミコロンはデータセットの終わりを示します。DATALINESはデータステップの最後に記述する必要があることに注意してください。セミコロン終了後のものはSASによって実行されません。
INPUTステートメントは、入力データからどの列を読み込むか、そしてSAS変数名を指定します。
RUNステートメントは、データステップをSASに実行させます。PROC PRINTステートメントは、一時的データセットtemp1を出力するようSASに指示します。
このプログラムで重要なことは次の通りです。
DATALINES
ステートメントは、SASに入力ストリームデータが続くことを伝えるステートメントです。DATALINESステートメントは次のようになります:データステップの最後に現れる(RUNステートメント以外)
データ行の直前に記述する
ステートメントは不要でセミコロン1つで終了する。データステップには1つのDATALINESステートメントしか書けません
INPUTステートメントは、SASにデータの形式を伝えるステートメントです。ここでは、データ値が特定の列にあるので、カラム入力を使用しています。標準的な数値データには、数字、小数点、指数表記(3.1E5など)、プラス記号かマイナス記号のみが含まれます。
一般に、生データの各フィールドをSASデータセットに読み込みたい場合、INPUTステートメントで次の情報を指定する必要があります。
変数が文字変数である場合は、変数名の直後にスペース1つと$記号を付けます。このデータセットには文字変数はありません。「subj」が列1から4まで、「gender」が列6、「height」が列8から9まで、「weight」が列11から13までを表しています。列番号は左端の列を1として右に数えていきます。正しく定義されていることを確認するために、左から右へ列を数え以下を確認してみるのもよいでしょう。
データ値の型(文字または数値)
定義された列に従って配置されている
有効なSAS変数名
指定するデータ型(文字または数値)
フィールドの開始と終了の列番号をハイフン(-)で区切ったもの
DATAステートメントは、作成するSASデータセットが一時的か永続的かをSASに伝えるステートメントです。ここでは、一時データセットtemp1 を作成するよう指示しています。一時データセットはtemp1のように1レベルの名前で指定します。stat480.temp1のように2レベルだと永久データセットになります。一時データセットは現在のSASセッションの終了時に削除されることに注意してください。
プログラムを開いて実行し、まずログウィンドウでエラーがないかを確認してください。次にアウトプットウィンドウを見て、PRINTプロシージャの出力を確認してください。
DATALINESステートメントの代わりにCARDSステートメントを使っても同じ結果になります。プログラムエディタでDATALINESをCARDSに置き換えて、プログラムを再実行すれば確認できます。
さらに追記しておきますが、データ値にセミコロンが含まれる場合はDATALINESステートメントは使えません。その場合はDATALINES4ステートメントに置き換え、セミコロン1つを4つのセミコロン(;;;;)で置き換える必要があります。
SASデータライブラリ#
一時データセットと永久データセットの違いを理解する前に、SASのデータライブラリについての理解が必要です。SASライブラリとは、同じフォルダまたはディレクトリ内に格納されたSASファイルの集合のことです。SAS形式の拡張子以外のファイルが同じフォルダに入っていてもかまいません。
ファイル作成時に指定するライブラリ名によって、SASファイルが一時的または永続的に保存されます。
Work またはライブラリ名を指定しない場合、作成したファイルは一時的なWorkライブラリに保存されます。SASセッションを終了すると、一時ライブラリとその中のファイルはコンピューターのメモリから削除されます。
Workではないライブラリ名を指定した場合、ファイルは永続的に保存されます。後のSASセッションでそのライブラリとその内容を利用できます。
永久SASファイルの参照方法#
一時的か永続的かに関わらず、SASはデータセットを2レベル名で参照します。
libref.ファイル名
2レベル名の libref はSASデータライブラリの(ニックネーム)名で、ファイル名はその中のファイル名です。例えば、ライブラリPHC6089にデータセットYTSがある場合、以下のようになります。
WindowsまたはUFアプリを使っている場合:
SAS University EditionまたはOnDemand Academicsを使っている場合:
ライブラリPHC6089のデータセットYTSを出力するには、以下のコードのPHC6089.YTSのように参照します。
proc print data = PHC6089.YTS;
run;
この例では、YTSがPHC6089ライブラリの永久データセットであることが分かります。
一時SASファイルの参照方法#
前にも記載していますが、一時的か永続的かに関わらず、SASはデータセットを2レベル名で参照します。
libref.ファイル名
一時的データセットの libref は常に Work です。そのため、Work内の任意のデータセットを以下のように参照できます。
Work.ファイル名
ここでファイル名はそのファイル名です。例えば、一時データセットtemp1がある場合は次のようになります。
WindowsSASまたはUFアプリを使っている場合:
SAS University EditionまたはOnDemand Academicsを使っている場合:
デフォルトの一時ライブラリ Work の一時データセット Temp1 を出力するには、次のようにします。
proc print data = work.temp1;
run;
SAS内部では常に2レベル名を使いますが、あなたも同様にする必要はなく次のうような1レベル名を使うこともできます。 filename
1レベル名を使うと、デフォルトでWorkが前につくと見なされます。そのため、前のコードは次のように書くことができます。
proc print data = temp1;
run;
ライブラリの定義#
最後に、ライブラリの定義方法を見ていきましょう。LIBNAMEステートメントを使い、libref(ライブラリ参照名)をコンピューター上の特定のフォルダまたはディレクトリ(SASファイルが含まれる)に関連付けます。 例えば私のコンピューターには以下のサブディレクトリがあります。
folders/myfolders/SAS_Notes/data
このディレクトリには yts.sas7bdatというSASデータセットが入っています。
このサブディレクトリに PHC6089 というライブラリ参照名をつけるには、以下のLIBNAME
ステートメントを使います。
libname PHC6089 "/folders/myfolders/SAS_Notes/data";
一般的に、ライブラリ参照名は1~8文字の文字または数字とアンダースコアからなり、先頭は文字またはアンダースコアでなければなりません。ライブラリの物理的な名前(ここでは”/folders/myfolders/ SAS_Notes/data”)はWindowsの規則に従います。LIBNAMEステートメントは必要であればプログラム中でいくつでも使用することができます。
LIBNAMEステートメントを実行した後、ログウィンドウを確認して、ライブラリ参照名が正しく割り当てられたというメッセージが出ていることを確認することができます。
すべてうまくいっていれば、以下のようなメッセージがログウィンドウに表示されています。
1 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
68
69 libname PHC6089 "/folders/myfolders/SAS_Notes/data";
NOTE: ライブラリ参照名PHC6089を次のように割り当てました。
エンジン: V9
物理名: /folders/myfolders/SAS_Notes/data
70
71 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
81
注意点として、LIBNAMEステートメントはグローバルステートメントです。つまり、ライブラリ参照名は変更、取り消し、またはSASセッションの終了までその効力が続きます。新しいSASセッションを開始するたびに、アクセスしたい永久SASデータライブラリにライブラリ参照名を割り当てる必要があります。
永久SASデータセットへのデータ読み込み#
前の例で扱ったセッション終了時に削除される一時データセットではなく、指定したディレクトリに保存された永久データセットも簡単に作成することができます。それでは試してみましょう!
例#
次のプログラムはカラム入力による最もシンプルな読み込みの例で、入力ストリームデータから永久SASデータセットPHC6089.temp2を作成しています。
libname PHC6089 "/folders/myfolders/SAS_Notes/data/";
*Specifies the SAS data library (directory);
data phc6089.temp2;
input subj 1-4 gender 6 height 8-9 weight 11-13;
datalines;
1024 1 65 125
1167 1 68 140
1168 2 68 190
1201 2 72 190
1302 1 63 115
;
run;
title 'Output dataset: PHC6089.TEMP2';
proc print data=PHC6089.temp2;
run;
OBS | subj | gender | height | weight |
---|---|---|---|---|
1 | 1024 | 1 | 65 | 125 |
2 | 1167 | 1 | 68 | 140 |
3 | 1168 | 2 | 68 | 190 |
4 | 1201 | 2 | 72 | 190 |
5 | 1302 | 1 | 63 | 115 |
前の例との違いは以下の通りです。
LIBNAMEステートメントがあり、データセットをPHC6089の/folders/myfolders/SAS_Notes/dataディレクトリに永続的に書き込むようSASに指示しています。
DATAステートメントのデータセット名が2レベル名になっています。これでSASに永続的データセットtemp2をPHC6089のディレクトリに作るよう指示しています。
後続のプロシージャ(ここではPRINT)で、永続的データセットを2レベル名で参照しています。
プログラムを開いて実行する前に、/folders/myfolders/SAS_Notes/dataが実際に存在することを確認してください。存在しない場合は適切なディレクトリを作成するか、LIBNAMEステートメントを編集する必要があります。
プログラムを実行すると、次のことが分かります。
phc6089.temp2の内容と構造はwork.temp1と同じです。一時的か永続的かの違いしかありません。
Explorerウィンドウで、temp2がphc6089ライブラリの下に表示されており、永久データセットであることが分かります。
Windowsエクスプローラーで、SASデータセットが実際に/folders/myfolders/SAS_Notes/dataディレクトリに永続的に保存されていることが確認できます。
生データ(テキストデータ)のファイルからデータを読み込む#
これまで入力ストリームデータの例だけでしたが、ここからは生データをSASデータセットに読み込む方法を扱います。
ここでの生データのファイルとは、データ値がフィールドに並んだレコードを含むテキストファイルのことです。一般的なファイルの拡張子は.datや.txtです。生データのファイルはASCII、shift-jisやutf-8などの特定の文字コードで構成され、メモ帳やワードパッドで表示できるファイルです。スプレッドシートのようなExcelに保存されたデータセットはバイナリ形式であり、生のテキストデータファイルではありません。
例#
以下のプログラムはカラム入力による最もシンプルな読み込みの例で、生データtemp3.datを読み込み、一時データセットtemp3を作成しています。
data temp3;
infile '/folders/myfolders/SAS_Notes/data/temp3.dat';
input subj 1-4 gender 6 height 8-9 weight 11-13;
run;
title 'Output dataset: TEMP3';
proc print data=temp3;
run;
OBS | subj | gender | height | weight |
---|---|---|---|---|
1 | 1024 | 1 | 65 | 125 |
2 | 1167 | 1 | 68 | 140 |
3 | 1168 | 2 | 68 | 190 |
4 | 1201 | 2 | 72 | 190 |
5 | 1302 | 1 | 63 | 115 |
INPUTステートメントの前で使うINFILEステートメントがDATALINESステートメントの代わりにとなっています。INFILEステートメントは、生のデータファイルがコンピューター上のどこに保存されているかをSASに伝えます。ファイル名と場所は引用符で囲む必要があります。この例では、生のデータファイルtemp3.datが”/folders/myfolders/SAS_Notes/data”ディレクトリに保存されています。データのみがファイルには格納されています。
このプログラムを実行するには、最初にtemp3.datファイル(READMEに記載のリンクから入手可能)をコンピューターの適切な場所に保存する必要があります。次に、INFILEステートメントを編集して、ファイルの正しい場所を反映させます。最後に、SASプログラムを開いて実行し、ログと出力ウィンドウを確認して、データが一時データセットtemp3に適切に読み込まれたことを確認します。
INFILEステートメントでファイル名と場所を指定する代わりに、fileref(ファイル参照名)を使うこともできます。librefと同様に、FILENAMEステートメントでfilerefをデータファイルの保存場所に関連付けます。すなわちlibrefはSASデータライブラリを参照しますが、filerefは外部データファイルの保存場所を一時的に参照します。
例#
以下のプログラムはINFILEステートメントでFILENAMEステートメントによりfilerefを使用する例で、生データファイルtemp3.datを読み込み一時データセットtemp4を作成します。
filename patients '/folders/myfolders/SAS_Notes/data/temp3.dat';
data temp4;
infile patients;
input subj 1-4 gender 6 height 8-9 weight 11-13;
run;
title 'Output dataset: TEMP4';
proc print data = temp4;
run;
OBS | subj | gender | height | weight |
---|---|---|---|---|
1 | 1024 | 1 | 65 | 125 |
2 | 1167 | 1 | 68 | 140 |
3 | 1168 | 2 | 68 | 190 |
4 | 1201 | 2 | 72 | 190 |
5 | 1302 | 1 | 63 | 115 |
FILENAMEステートメントでpatientsというfilerefをtemp3.datファイルの保存場所に関連付けています。一般的に、filerefは1〜8文字の文字または数字で、先頭は文字かアンダースコアでなければなりません。ファイルの物理的な名前の指定はWindowsの規則に従います。
まだtemp3.datファイルを保存していない場合は、適切な場所に保存してください。次に、FILENAMEステートメントを編集して、ファイルの正しい場所を反映させます。最後に、プログラムを開いて実行し、ログと出力ウィンドウを確認して、データが一時的データセットtemp4に適切に読み込まれたことを確認します。
カラム入力による読み込み#
前で説明しているように、SASには3つの入力スタイルがあります。
カラム入力は、データ値が固定の列に入力されている場合に使用します。
リスト入力は、データ値が少なくとも1つのスペース(または文字)で区切られている場合に使用します。
フォーマット入力は、日付や通貨額など、特殊文字を含む数値データを読み込む場合に使用します。
このセクションでは、カラム入力の2つの簡単な例を見ていきます。後のセクションではリスト入力とフォーマット入力についても扱います。
コメント この後の例では、DATALINES ステートメントを使ってデータを読み込みますが、INFILE文を使用することもできます。また永久データセットを作成することもできますが、一時データセットを作成します。最後に、各データステップの後、PRINTプロシージャ(PROC PRINT)を使用して、結果のSASデータセットを出力し確認できるようにします。
カラム入力では、各レコード内の同じ列にあるデータ値を読み込めます。カラム入力を使うには、INPUTステートメントで変数名を並べ、続けてその変数のデータが収まっている列の範囲を指定します(文字変数の場合は$記号を先に付ける)。カラム入力は、データが固定の列にあり、標準的な文字または数値フォーマットの場合に使えます。カラム入力では、指定した最後の列までデータ値を読み込みます。
カラム入力の重要なポイントは次の通りです。
欠損値を示すプレースホルダ(ピリオドなど)は不要です。欠損値は空白のままでかまいません。
文字変数の長さが指定した列の範囲で決まり、デフォルトの8文字を超えることが可能で、スペースも埋め込めます。
フィールドを完全に飛ばしたり、順序を変えて読み込むことができます。
値の一部だけを読み込んだり、値を再度読み込むこともできます。
データ値の間にスペースを入れる必要はありません。
例#
以下のプログラムはシンプルなカラム入力の例です。
data temp;
input subj 1-4 name $ 6-23 gender 25 height 27-28 weight 30-32;
cards;
1024 Alice Smith 1 65 125
1167 Maryann White 1 68 140
1168 Thomas Jones 2 68 190
1201 Benedictine Arnold 2 68 190
1302 Felicia Ho 1 63 115
;
run;
title 'Output dataset: TEMP';
proc print data=temp;
run;
OBS | subj | name | gender | height | weight |
---|---|---|---|---|---|
1 | 1024 | Alice Smith | 1 | 65 | 125 |
2 | 1167 | Maryann White | 1 | 68 | 140 |
3 | 1168 | Thomas Jones | 2 | 68 | 190 |
4 | 1201 | Benedictine Arnold | 2 | 68 | 190 |
5 | 1302 | Felicia Ho | 1 | 63 | 115 |
まずSASコードを確認して、カラム入力のINPUTステートメントの設定方法を理解しましょう。
データポイントは列に並んでいます。読みやすいようにデータ値は空白で区切られていますが、カラム入力の場合は必須ではありません。列番号1は左端の列です。
INPUTステートメントは、subject番号がcolumn 1-4、名前が文字変数で列6-23、 性別が文字変数の列25、身長が列27-28、体重が列30-32にあると指定しています。カラム入力では、文字変数に埋め込まれたスペースを許可するため、名前は最大18文字の長さになります。
SASプログラムを開いて実行します。
最後に、PRINTプロシージャの出力を確認して、データが適切に読み込まれたことを確かめます。
例#
以下のプログラムはカラム入力のいくつかの機能の例です。
data temp;
input init $ 6 f_name $ 6-16 l_name $ 18-23
weight 30-32 height 27-28;
cards;
1024 Alice Smith 1 65 125
1167 Maryann White 1 68 140
1168 Thomas Jones 2 190
1201 Benedictine Arnold 2 68 190
1302 Felicia Ho 1 63 115
;
run;
title 'Output dataset: TEMP';
proc print data=temp;
run;
OBS | init | f_name | l_name | weight | height |
---|---|---|---|---|---|
1 | A | Alice | Smith | 125 | 65 |
2 | M | Maryann | White | 140 | 68 |
3 | T | Thomas | Jones | 190 | . |
4 | B | Benedictine | Arnold | 190 | 68 |
5 | F | Felicia | Ho | 115 | 63 |
まずコードを確認して、カラム入力の機能に慣れましょう。次にプログラムを開いて実行します。
PRINTプロシージャの出力から、データセットtempの変数の並び順がデータに含まれる順序ではなく、INPUTステートメントの順序に従っていることを確認します。またデータセットの最初の列はスキップされていることに注目してください。
リスト入力による読み込み#
前のセクションでは、下のようなデータをカラム入力で読み込む方法を確認しました。
DATALINES;
Smith 8145551354 3.89
Washington 8145569847 2.73
Wing 8145359376 3.56
Jackson 8145557437 3.12
;
ここでは、次のようなフリーフォーマットのデータをリスト入力で読み込む方法を確認します。
Smith 8145551354 3.89
Washington 8145569847 2.73
Wing 8145359376 3.56
Jackson 8145557437 3.12
リスト入力は最も簡単な入力方法かもしれません。下の例のように変数名をINPUTステートメントで並べて、対応するデータフィールドの順序と一致させるだけです。その利便性には次のような制約があります。
フィールドは少なくとも1つのブランク(またはその他の区切り記号)で区切る必要があります。
フィールドは左から右の順番で読み込まれる必要があります。
フィールドをスキップしたり、再読み込みすることはできません。
欠損値は、ピリオド(.)などのプレースホルダで表す必要があります。(ブランクのフィールドがあると、変数名とデータ値のマッチングがずれてしまいます)
文字値にはスペースを含めることができません。
文字値のデフォルトの長さは8バイトです。それを超える値は切り捨てられます。 注 1バイト=1文字
データは標準の文字または数値形式でなければなりません。
例#
リスト入力の基本的な使い方を最もシンプルな例で見ていきましょう。データ値は1つのスペースで区切られていることに注目してください。また値を列で揃えることは必須ではありませんが、見やすくするため揃えることを推奨します。
data temp;
input subj name $ gender height weight;
* 変数名のあとの$は、文字変数であることを示す;
* The $ that follows name tells SAS that it is a character variable;
* デフォルトでは、nameは最大8文字までしか読み込むことができない;
* By default, name only allows up to 8 characters to be read in;
cards;
1024 Alice 1 65 125
1167 Maryann 1 68 140
1168 Thomas 2 68 190
1201 Benedictine 2 72 190
1302 Felicia 1 63 115
;
run;
title 'Output dataset: TEMP';
proc print data=temp;
run;
OBS | subj | name | gender | height | weight |
---|---|---|---|---|---|
1 | 1024 | Alice | 1 | 65 | 125 |
2 | 1167 | Maryann | 1 | 68 | 140 |
3 | 1168 | Thomas | 2 | 68 | 190 |
4 | 1201 | Benedict | 2 | 72 | 190 |
5 | 1302 | Felicia | 1 | 63 | 115 |
INPUTステートメントは、リスト入力を使ってデータを読み込むように指示します。リスト入力の場合は、変数名をスペースで区切って並べるだけです。変数の順序は、データファイル内の対応するフィールドの順序と一致させる必要があります。文字変数の場合は$記号を付けます。
プログラムを開いて実行し、PRINTプロシージャの出力を確認して、データが適切に読み込まれたことを確認します。ただし、4行目のBenedictineの名前がBenedictに切り捨てられていることに注目してください。これは、デフォルトの文字長が8文字に制限されているためです。後でインフォーマットを使ってこの問題を解決する方法を扱います。
この例では、欠損しているBennyの身長を示すために、ピリオド(.)のプレースホルダを使う必要があります。
data temp;
input subj name $ gender height weight;
cards;
1024 Alice 1 65 125
1167 Maryann 1 68 140
1168 Thomas 2 68 190
1201 Benny 2 . 190
1302 Felicia 1 63 115
;
run;
title 'Output dataset: TEMP';
proc print data=temp;
run;
OBS | subj | name | gender | height | weight |
---|---|---|---|---|---|
1 | 1024 | Alice | 1 | 65 | 125 |
2 | 1167 | Maryann | 1 | 68 | 140 |
3 | 1168 | Thomas | 2 | 68 | 190 |
4 | 1201 | Benny | 2 | . | 190 |
5 | 1302 | Felicia | 1 | 63 | 115 |
前でも記載しているように、Bennyの身長が欠損しているため、リスト入力ではピリオド(.)のプレースホルダを使う必要があることに注意してください。
プログラムを開いて実行し、PRINTプロシージャの出力を確認して、データが適切に読み込まれたことを確認します。次に、プログラムを編集して欠損値のピリオド(.)を削除してください。プログラムを再実行すると、ログファイルに次のような注意が表示されるはずです。
NOTE: SAS went to a new line when INPUT statement reached past the end of a line
data temp;
input subj name $ gender height weight;
cards;
1024 Alice 1 65 125
1167 Maryann 1 68 140
1168 Thomas 2 68 190
1201 Benny 2 190
1302 Felicia 1 63 115
;
run;
title 'Output dataset: TEMP';
proc print data=temp;
run;
OBS | subj | name | gender | height | weight |
---|---|---|---|---|---|
1 | 1024 | Alice | 1 | 65 | 125 |
2 | 1167 | Maryann | 1 | 68 | 140 |
3 | 1168 | Thomas | 2 | 68 | 190 |
4 | 1201 | Benny | 2 | 190 | 1302 |
そして、出力結果は明らかに誤っています。 デフォルトでは、SASはINPUTステートメントの変数名よりもデータ行にデータ値が少ない場合、次の行からデータを探します。この例では、Bennyの身長が190(次の行の最初の数値)、体重が1302(その次の行の最初の数値)と誤って読み込まれてしまいました。
例#
以下のプログラムでは、スペースでない区切り文字を使用するINFILEステートメントのDELIMITERオプションの例です。この例では一般的な区切り文字のカンマ(,)を指定しています。
data temp;
infile cards delimiter=',';
input subj name $ gender height weight;
cards;
1024,Alice,1,65,125
1167,Maryann,1,68,140
1168,Thomas,2,68,190
1201,Benny,2,.,190
1302,Felicia,1,63,115
;
run;
title 'Output dataset: TEMP';
proc print data=temp;
run;
OBS | subj | name | gender | height | weight |
---|---|---|---|---|---|
1 | 1024 | Alice | 1 | 65 | 125 |
2 | 1167 | Maryann | 1 | 68 | 140 |
3 | 1168 | Thomas | 2 | 68 | 190 |
4 | 1201 | Benny | 2 | . | 190 |
5 | 1302 | Felicia | 1 | 63 | 115 |
デフォルトではデータがスペース区切りと見なされますが、INFILEステートメントのDELIMITERオプションを使えば、他の区切り文字(この例ではコンマ)を指定できます。DELIMITERオプションは、データがカンマ区切りであることをSASに伝えます。INFILEステートメントは外部ファイルの読み込みで使用しますが、CARDS(またはDATALINES)オプションを含めると、データがコード内に含まれていることを示します。プログラムを開いて実行し、PRINTプロシージャの出力を確認して、データが適切に読み込まれたことを確認してください。
フォーマット入力の読み込み#
前のセクションでカラム入力について学びました。カラム入力は標準の数値データのみを読み込めます。一方、フォーマット入力では標準の数値データと非標準の数値データの両方を読み込めます。つまり、フォーマット入力はカラム入力の機能に加えて、非標準のデータ値を読み込む機能が追加されています。
標準の数値データ値とは以下のものです。
数字
小数点
指数表記の数値(3.1E5など)
マイナス記号(-)、プラス記号(+)
標準の数値データ値の例: 26、3.9、-13、+3.14、314E-2、2.193E3(Eは指数表記)
非標準の数値データ値とは以下のものです。
ドル記号($)、パーセント記号(%)、コンマ(,)などの特殊文字を含む値
日付と時刻の値
分数形式、バイナリ形式整数、バイナリ形式実数、16進形式のデータ
非標準の数値データ値の例: 23.3%、$1.26、03/07/47
INPUTステートメント#
フォーマット入力を使うINPUTステートメントの一般的な形式は次のとおりです。
INPUT 変数 インフォーマット;
この中で、
ポインタコントロール は、SASにデータ値の読み込み開始列番号を指示します(省略可能)
変数は作成する変数の名前です
インフォーマットは、生のデータ値を読み込むための特別な指定です
注意点として、上記のINPUTステートメントは標準的なSASヘルプの表記を使用しています。例えば、ポインタコントロールは山括弧<>で囲まれていますが、これは省略可能であることを示しており、例えば1列目から始まる値を読み込む場合は不要です。実際のプログラムに<>を記載すると、SASはエラーを出します。
ポインタコントロールには2つの種類があります。
@n は、入力ポインタを特定の列番号nに移動させます
+n は、入力ポインタを現在の位置から相対的にn列分進めます
さらに、インフォーマットは生のデータ値を読み込むための特別な指示を伝えるために使用します。SASには多くの(多すぎる?)インフォーマットがあります。例えば、数値インフォーマット”mmddyy8.”は、最大8文字の日付(10/27/05のようなもの)を読み込むようSASに指示します。数値インフォーマット”comma6.”は、コンマを含む最大6文字の数値(11,387など)を読み込むようSASに指示します。
例を見ていきましょう。
この例では、@n列ポインタコントロールと標準の数値インフォーマットを使って、「subj」、「height」、「weight」の3つの数値変数を一時的なSASデータセットtempに読み込んでいます。
data temp;
input @1 subj 4.
@27 height 2.
@30 weight 3.;
datalines;
1024 Alice Smith 1 65 125 12/1/95 2,036
1167 Maryann White 1 68 140 12/01/95 1,800
1168 Thomas Jones 2 190 12/2/95 2,302
1201 Benedictine Arnold 2 68 190 11/30/95 2,432
1302 Felicia Ho 1 63 115 1/1/96 1,972
;
run;
title 'Output dataset: TEMP';
proc print data = temp;
run;
OBS | subj | height | weight |
---|---|---|---|
1 | 1024 | 65 | 125 |
2 | 1167 | 68 | 140 |
3 | 1168 | . | 190 |
4 | 1201 | 68 | 190 |
5 | 1302 | 63 | 115 |
INPUTステートメントを見ると、まず@1でポインターを列1に移動させ、「subj」を4列分の幅で読み込んでいます。次に@27でポインターを列27に移動させ、「height」を2列分の幅で読み込み、最後に@30でポインターを列30に移動させ、「weight」を3列分の幅で読み込んでいます。
subj、height、weightの後に付いている4.、2.、3.はインフォーマットで、標準の数値データをどのように読み込むかをSASに指示しています。ここでは標準の数値データを読み込むので、w.dインフォーマットを使用しています。wはデータ値の幅(列数)を表し、dは小数点以下の桁数を表します。ピリオド(.)で区切られている必要があります。dを省略した場合でも、ピリオドは必須です。
より具体的に説明すると、「subj」の値は4列幅で小数点以下はないので、4.インフォーマットを使用しています。代わりに4.0と指定してもかまいません。「height」は2列幅で小数点以下はないので、2.インフォーマットを使います。「weight」は3列幅で小数点以下はないので、3.インフォーマットを使います。
w.dインフォーマットは、データ値に既に小数点が含まれている場合、指定したdは無視されることに注意してください。例えば、23.001という6列幅の値に対して6.インフォーマットを指定した場合、SASは23.001として値を保存します。小数点以下の桁数は指定どおりにはならないのです。
プログラムを実行し、PRINTプロシージャの出力を確認して、3つの変数が正しく読み込まれていることを確認してください。前で触れた最初の列を読み込むならポインタの移動は不要なことは覚えていますか?@1を削除してみて、SASがデフォルトで先頭列から読み込みを開始することを確かめてもいいでしょう。
例#
この例では、@nポインタコントロールと、標準の文字・数値インフォーマットを使って、文字変数「l_name」と「f_name」、数値変数「weight」と「height」を一時SASデータセットtempに読み込んでいます。
data temp;
input @18 l_name $6.
@6 f_name $11.
@30 weight 3.
@27 height 2.;
datalines;
1024 Alice Smith 1 65 125 12/1/95 2,036
1167 Maryann White 1 68 140 12/01/95 1,800
1168 Thomas Jones 2 190 12/2/95 2,302
1201 Benedictine Arnold 2 68 190 11/30/95 2,432
1302 Felicia Ho 1 63 115 1/1/96 1,972
;
run;
title 'Output dataset: TEMP';
proc print data = temp;
run;
OBS | l_name | f_name | weight | height |
---|---|---|---|---|
1 | Smith | Alice | 125 | 65 |
2 | White | Maryann | 140 | 68 |
3 | Jones | Thomas | 190 | . |
4 | Arnold | Benedictine | 190 | 68 |
5 | Ho | Felicia | 115 | 63 |
INPUTステートメントでは、まず@18でポインターを列18に移動させて「l_name」を\(6.インフォーマットで読み込み、次に@6でポインターを列6に移動させて「f_name」を\)11.インフォーマットで読み込んでいます。さらに@30でポインターを列30に進めて「weight」を3.インフォーマットで読み込み、最後に@27でポインターを列27に戻して「height」を2.インフォーマットで読み込んでいます。このように、@nポインター制御を使えば、データフィールドをどの順番で読み込んでも構いません。
「weight」の後の3. と「height」の後に現れる2. は見覚えがあるでしょう。これらは各数値変数をどのように読むかを指示するインフォーマットです。2つの文字変数、「l_name」と「f_name」の情報を見ると、それぞれがドル記号($)で始まることを確認できます。なぜなら、文字データ値を読み込もうとしているからです。したがって、$w. informatを使用します。wは入力データ値の幅つまり、それが占める列の数をSASに伝えます。ドル記号($)とピリオド(.)は必須の区切り文字です。例えば、私たちの例では、苗字(l_name)は最大6列を占めるため、$6. informatを使用し、名前(f_name)は最大11列を占めるため、$11. informatを使用します。
プログラムを開いて実行し、PRINTプロシージャの出力を確認して、4つの変数が正しく読み込まれていることを確認してください。
例#
この例では、@nの絶対カラムポインタコントロールに加えて、+nの相対カラムポインタコントロールと、非標準のインフォーマットも使用して、一時データセットtempに6つの変数を読み込んでいます。
data temp;
input @1 subj 4.
@6 f_name $11.
@18 l_name $6.
+3 height 2.
+5 wt_date mmddyy8.
+1 calorie comma5.;
datalines;
1024 Alice Smith 1 65 125 12/1/95 2,036
1167 Maryann White 1 68 140 12/01/95 1,800
1168 Thomas Jones 2 190 12/2/95 2,302
1201 Benedictine Arnold 2 68 190 11/30/95 2,432
1302 Felicia Ho 1 63 115 1/1/96 1,972
;
run;
title 'Output dataset: TEMP';
proc print data = temp;
run;
OBS | subj | f_name | l_name | height | wt_date | calorie |
---|---|---|---|---|---|---|
1 | 1024 | Alice | Smith | 65 | 13118 | 2036 |
2 | 1167 | Maryann | White | 68 | 13118 | 1800 |
3 | 1168 | Thomas | Jones | . | 13119 | 2302 |
4 | 1201 | Benedictine | Arnold | 68 | 13117 | 2432 |
5 | 1302 | Felicia | Ho | 63 | 13149 | 1972 |
「subj」、「f_name」、「l_name」の読み込み方は前の例と同じです。「height」の読み込みは+3を使って、「l_name」の最後の列から3列分進んだ位置から開始しています。「wt_date」の読み込みは+5を使って、「height」の最後の列から5列分進んだ位置から開始しています。「calorie」の読み込みは+1を使って、「wt_date」の最後の列から1列分進んだ位置から開始しています。
「height」、「 wt_date」、「calorie」の読み込みでは相対列ポインターを使用しています。+nの相対列ポインター制御は、現在のポインター位置から相対的にn列分進めることを示します。ポインターがどこに移動するかを正確に把握するには、フィールドの読み込み後にポインターがどこに移動するかを理解する必要があります。一般に、フォーマット入力の場合、ポインターは読み込んだフィールドの直後の最初の列に移動します。
「wt_date」と「calorie」フィールドには非標準の数値データが含まれています。「wt_date」にはスラッシュ(/)が使われた日付があるため、mmddyy8.のインフォーマットを使って月/日/年の形式の最大8文字の日付を読み込むよう指示しています。「calorie」フィールドにはコンマ(,)が含まれているため、comma6.のインフォーマットを使って、コンマを含む最大6文字の数値を読み込むよう指示しています。
具体的にしましょう。「l_name」フィールドを読み終わったとき、列ポインタはそのフィールドの次の列に移動します。つまり、Arnoldのdの直後に続く最初の列(列24)に移動します。その後、heightフィールドは右に3列離れて始まるため、+3を移動させるように指示します。「height」フィールドを読み終わったとき、列ポインタはそのフィールドの次の最初の列に移動します。つまり、「height」の後の空白の列(列29)に移動します。その後、wt_dateフィールドは右に5列離れて始まるため、+5を移動させるように指示します。wt_dateフィールドを読み終わったとき、列ポインタはそのフィールドの次の最初の列に移動します。つまり、カロリーデータの前に空白の列(列42)に移動します。その後、「calorie」フィールドは右に1列離れて始まるため、SASに+1を移動させるように指示します。
非標準的な数値データを含む「wt_date」と「calorie」フィールドについて説明すれば、INPUTステートメントの説明は完了です。wt_dateフィールドでは、スラッシュ(/)を使用して日付を指定しており、カロリーデータにはカンマ(,)が含まれています。「wt_date」フィールドを読み込むために、mmddyy8. informatを使用してSASにmm/dd/yy形式で書かれた日付を想定するように指示します。8は、日付が最大8列を占めることをSASに伝えます。「calorie」フィールドを読み込むために、comma6. インフォーマットを使用してSASにカンマを含む数値データを読み込み、最大6列を占めることを指示します。
一般に、COMMAw.dインフォーマットは数値を読み込み、埋め込まれた空白、コンマ、ハイフン、ドル記号、パーセント記号、右カッコ、左カッコ(マイナス記号に変換される)を削除します。w.はフィールドの幅(特殊文字を含む)を示し、dは小数点以下の桁数を示します(省略可能)。
プログラムを実行し、PRINTプロシージャの出力を確認してください。フォーマット入力では出力フォーマットは指定されていないことに注意してください。例えば、日付12/01/95は13118という数値で出力されています。これはSASが日付を1960年1月1日からの経過日数として保存しているためです。1960年1月1日以前の日付は負の値になります。また、「calorie」の値はコンマなしで出力されていることにも注目してください。出力フォーマットを指定するには、FORMATステートメントを使う必要があります。 following code to see formatted output:
data temp;
input @1 subj 4.
@6 f_name $11.
@18 l_name $6.
+3 height 2.
+5 wt_date mmddyy8.
+1 calorie comma5.;
format wt_date mmddyy8. calorie comma5.;
datalines;
1024 Alice Smith 1 65 125 12/1/95 2,036
1167 Maryann White 1 68 140 12/01/95 1,800
1168 Thomas Jones 2 190 12/2/95 2,302
1201 Benedictine Arnold 2 68 190 11/30/95 2,432
1302 Felicia Ho 1 63 115 1/1/96 1,972
;
run;
title 'Output dataset: TEMP';
proc print data = temp;
run;
OBS | subj | f_name | l_name | height | wt_date | calorie |
---|---|---|---|---|---|---|
1 | 1024 | Alice | Smith | 65 | 12/01/95 | 2,036 |
2 | 1167 | Maryann | White | 68 | 12/01/95 | 1,800 |
3 | 1168 | Thomas | Jones | . | 12/02/95 | 2,302 |
4 | 1201 | Benedictine | Arnold | 68 | 11/30/95 | 2,432 |
5 | 1302 | Felicia | Ho | 63 | 01/01/96 | 1,972 |
他のSASデータセットからデータを読み込む#
入力データがどこにあるかをSASに伝えるという点から、これまでにインストリームデータおよび外部の生データファイルに含まれるデータをSASデータセットに読み込む方法について扱いました。次は、あるSASデータセットに既に含まれているデータを別のSASデータセットに読み込む方法について扱います。
例#
以下のプログラムでは永久データセットPHC6089.temp2と同じ一時データセットwork.tempを作成します。 :
libname PHC6089 '/folders/myfolders/SAS_Notes/data/';
data temp;
set PHC6089.temp2;
run;
title 'Output dataset: TEMP';
proc print data=temp;
run;
OBS | subj | gender | height | weight |
---|---|---|---|---|
1 | 1024 | 1 | 65 | 125 |
2 | 1167 | 1 | 68 | 140 |
3 | 1168 | 2 | 68 | 190 |
4 | 1201 | 2 | 72 | 190 |
5 | 1302 | 1 | 63 | 115 |
このコードでは
1レベルの名前が使用されているため、DATAステートメントはSASにtempという一時データセットを作成するように指示します。
SETステートメントは、既存の永久SASデータセットstat480.temp2のデータを、DATAステートメントに現れる一時的なtempデータセットに割り当てるようにSASに指示します。既存のデータセットの変数には既に名前が付けられているので、INPUTステートメントは必要ありません。つまり、SETステートメントは読み込むデータがすでにSASデータセットの構造になっていることを示し、データセットの名前を与えるだけです。
このプログラムを実行する前に、このセクションの前の例で永久SASデータセットPHC6089.temp2を作成しなければならないことに注意してください。SASプログラムを開き、PHC6089.temp2が/folders/myfolders/SAS_Notes/data/というディレクトリに格納されていない場合は、LIBNAMEステートメントを編集して、PHC6089.temp2がコンピュータに格納されている場所を反映させる必要があります。必要な変更を行ったらSASプログラムを実行し、出力を確認してください。新しい一時データセットtempの構造と内容は、永久SASデータセットPHC6089.temp2と同じであることに注目してください。
PROC IMPORTを使用した読み込み#
CSVやExcel形式など、区切られているファイルではPROC IMPORTを使用して読み込むことができます。 これはR言語の関数read_csv
と read_excel
と似ています。
例#
以下のプログラムはCSVファイルYouth_Tobacco_Survey_YTS_Data.csvを読み込み、一時データセットwork.ytsを作成します。
filename yts_data
"/folders/myfolders/SAS_Notes/data/Youth_Tobacco_Survey_YTS_Data.csv";
proc import datafile = yts_data out = yts dbms = csv replace;
getnames = yes;
guessingrows = max;
run;
35 SAS システム 2024年 6月 6日 木曜日 06時34分00秒
379 ods listing close;ods html5 (id=saspy_internal) file=_tomods1 options(bitmap_mode='inline') device=svg style=HTMLBlue;
379 ! ods graphics on / outputfmt=png;
380
381 filename yts_data
382 "/home/user-name/SAS_Notes/data/Youth_Tobacco_Survey_YTS_Data.csv";
383
384 proc import datafile = yts_data out = yts dbms = CSV replace;
385 getnames = yes;
386 guessingrows = max;
387 run;
NOTE: Unable to open parameter catalog: SASUSER.PARMS.PARMS.SLIST in update mode. Temporary parameter values will be saved to
WORK.PARMS.PARMS.SLIST.
388 /**********************************************************************
389 * PRODUCT: SAS
390 * VERSION: 9.4
391 * CREATOR: External File Interface
392 * DATE: 06JUN24
393 * DESC: Generated SAS Datastep Code
394 * TEMPLATE SOURCE: (None Specified.)
395 ***********************************************************************/
396 data WORK.YTS ;
397 %let _EFIERR_ = 0; /* set the ERROR detection macro variable */
398 infile YTS_DATA delimiter = ',' MISSOVER DSD firstobs=2 ;
399 informat YEAR best32. ;
400 informat LocationAbbr $2. ;
401 informat LocationDesc $24. ;
402 informat TopicType $25. ;
403 informat TopicDesc $29. ;
404 informat MeasureDesc $57. ;
405 informat DataSource $4. ;
406 informat Response $8. ;
407 informat Data_Value_Unit $1. ;
408 informat Data_Value_Type $10. ;
409 informat Data_Value best32. ;
410 informat Data_Value_Footnote_Symbol $1. ;
411 informat Data_Value_Footnote $71. ;
412 informat Data_Value_Std_Err best32. ;
413 informat Low_Confidence_Limit best32. ;
414 informat High_Confidence_Limit best32. ;
415 informat Sample_Size best32. ;
416 informat Gender $7. ;
417 informat Race $9. ;
418 informat Age $8. ;
419 informat Education $13. ;
420 informat GeoLocation $43. ;
421 informat TopicTypeId $3. ;
422 informat TopicId $6. ;
423 informat MeasureId $6. ;
424 informat StratificationID1 $4. ;
425 informat StratificationID2 $4. ;
426 informat StratificationID3 $4. ;
427 informat StratificationID4 $4. ;
428 informat SubMeasureID $5. ;
429 informat DisplayOrder best32. ;
430 format YEAR best12. ;
431 format LocationAbbr $2. ;
432 format LocationDesc $24. ;
433 format TopicType $25. ;
434 format TopicDesc $29. ;
435 format MeasureDesc $57. ;
436 format DataSource $4. ;
437 format Response $8. ;
438 format Data_Value_Unit $1. ;
439 format Data_Value_Type $10. ;
440 format Data_Value best12. ;
441 format Data_Value_Footnote_Symbol $1. ;
442 format Data_Value_Footnote $71. ;
443 format Data_Value_Std_Err best12. ;
444 format Low_Confidence_Limit best12. ;
445 format High_Confidence_Limit best12. ;
446 format Sample_Size best12. ;
447 format Gender $7. ;
448 format Race $9. ;
449 format Age $8. ;
450 format Education $13. ;
451 format GeoLocation $43. ;
452 format TopicTypeId $3. ;
453 format TopicId $6. ;
454 format MeasureId $6. ;
455 format StratificationID1 $4. ;
456 format StratificationID2 $4. ;
457 format StratificationID3 $4. ;
458 format StratificationID4 $4. ;
459 format SubMeasureID $5. ;
460 format DisplayOrder best12. ;
461 input
462 YEAR
463 LocationAbbr $
464 LocationDesc $
465 TopicType $
466 TopicDesc $
467 MeasureDesc $
468 DataSource $
469 Response $
470 Data_Value_Unit $
471 Data_Value_Type $
472 Data_Value
473 Data_Value_Footnote_Symbol $
474 Data_Value_Footnote $
475 Data_Value_Std_Err
476 Low_Confidence_Limit
477 High_Confidence_Limit
478 Sample_Size
479 Gender $
480 Race $
481 Age $
482 Education $
483 GeoLocation $
484 TopicTypeId $
485 TopicId $
486 MeasureId $
487 StratificationID1 $
488 StratificationID2 $
489 StratificationID3 $
490 StratificationID4 $
491 SubMeasureID $
492 DisplayOrder
493 ;
494 if _ERROR_ then call symputx('_EFIERR_',1); /* set ERROR detection macro variable */
495 run;
9794 rows created in WORK.YTS from YTS_DATA.
496
497
498 ods html5 (id=saspy_internal) close;ods listing;
499
36 SAS システム 2024年 6月 6日 木曜日 06時34分00秒
500
PROC IMPORT を実行すると、SAS はデータセットを読み込むための DATA ステップコード(ログファイル出力に表示)を生成することに留意してください。
PROC IMPORT の主なオプションの一部:
datafille: 読み込もうとしているコンピュータ上のデータセットファイルへのパス。
out: 作成する出力 SAS データセットの名前。前の例では一時データセットytsをWorkライブラリに作成しています。
DBMS: 読み込むファイルの種類 CSVやexcel(XLS or XLSX).
replace: 同じ名前のSASデータセットが既に存在する場合、このオプションを使用して上書きします。
getnames: 最初の行が列名の場合はYES. それ以外はNO。
guessingrows: このオプションは、SASがデータセット内の変数のデータ型と書式を把握するためにスキャンするデータセットの行数を指定します。データセット全体をスキャンするには正確な行数またはMAXを指定します。
演習#
PROC IMPORT を使用して、Youth_Tobacco_Survey_YTS_Data.csv を読み込み、それに youth という名前をつけてください。
READMEに記載のリンクからMonumentsデータセット、Monuments.xlsxをダウンロードします。PROC IMPORTを使ってデータセットを読み込み、monという名前で出力してください。
DATALINESを使って以下の列フォーマットデータを読み込み、PROC PRINTを使って結果を出力するデータステップを書いてください。このデータセットには、フランスのIlle-et-Vilaineにおける食道癌の情報が含まれています。変数は以下のとおりです。
年齢層
アルコール消費量
タバコ消費量
症例数
コントロール数
データを読み込むためにデータステップを書いて結果を表示させてください。注意: 最初の行は列を数えるためのものです。各数値に5をかけたものが列番号になります。
----1----2----3----4----5----6----7----8
75+ 0-39g/day 0-9g/day 1 18
75+ 0-39g/day 10-19 2 6
75+ 0-39g/day 30+ 1 3
75+ 40-79 0-9g/day 2 5
75+ 40-79 10-19 1 3
75+ 40-79 20-29 0 3
75+ 40-79 30+ 1 1
75+ 80-119 0-9g/day 1 1
75+ 80-119 10-19 1 1
75+ 120+ 0-9g/day 2 2
75+ 120+ 10-19 1 1