我輩はブロガーではない。ネタもまだない

SASとかDelphiあたりの人様の役に立たないネタを提供します

SAS xportファイルに仕様上の不備?

ちょっと前にSASxportファイルへのアクセスを試してみましたが、その際、おかしな挙動をしたのでまとめておきます。
(2020/11/20追記)



とりあえず以下のプログラムを実行してみます

options dlcreatedir;
libname temp 'c:\temp';

data test1 test2;
  array a{3} $2;
  do i=1 to 3;
    a{i}=' A';
  end;
  output test1 test2;
  output test1;
  do i=1 to 3;
    a{i}=' ';
  end;
  output test2;
  drop i;
run;


workライブラリに作成されるデータセットは以下の2obs、3変数のものです。

f:id:japelin:20201113132907p:plain
データセット:Test1
f:id:japelin:20201113132929p:plain
データセット:Test2

続いて、この2つのデータセットをtext.xptというxport形式のファイルに変換し、再度tempライブラリにsasデータセットとして再変換しています。

libname out xport 'c:\temp\test.xpt';
proc copy in=work out=out;
  select test:;
run;
proc copy in=out out=temp;
  select test:;
run;

この結果生成されるデータセットは以下の通りです。

f:id:japelin:20201113133138p:plain
データセット:Test1
f:id:japelin:20201113133213p:plain
データセット:Test2

test2の2obs目が失われています。


SASxportの仕様を調べたところ、バイナリファイルは1ブロック80バイトで構成されており、ヘッダー部分、データ部分それぞれにおいて、最後が80バイトに満たない場合は80バイトまで空白で埋める(padding)、という挙動をするようですが、文字列についてはそのままバイナリに保存されているため、空obs(欠損)と空白のpaddingが区別できていないのでは?と思います。

f:id:japelin:20201113140015p:plain
バイナリエディタで開いた様子
赤枠がヘッダー部分
青枠がデータ部分
グレーの網掛けが空白padding部分
オレンジの網掛けが空データの2obs目。
空obsと空白paddingの区別が付きません…

その結果、
・データセットに含まれる変数がすべて文字変数
かつ
・最後のobsがすべて欠損
かつ
・行のバッファ(すべての変数長の合計)が 80 40以下(その後の検証で41以上なら削除されないことが分かりましたので訂正しました)
の場合に最後の欠損obsが復元できなくなる、という結果になります。
(数値変数の場合、8バイトにフラグ1バイトと数値領域7バイトが確保され、obsのデータという識別ができるため、数値変数が1つでも存在すれば問題ありません)

どうにかならんもんですかねぇ。
せめてobs数を保持していれば、と思うのですが。

(2020/11/20追記)
どうも米国本社では不具合として認識しているようで、将来的なバージョンでの対応を予定しているとのこと。
早く不具合諸々修正したSAS 10(SAS Xとか)でも出てほしいのですが、Viyaがリリースされてしまっているので、PC版SASの更新は当面なさそう。
単純にヘッダーにobs数を埋め込むだけでいいと思うんですけど、旧バージョンのSASや3rdパーティー関係で影響がありそうなのでなんとも。

まぁ、SASxportを使用するCDISCで言えば、全てが欠損のobsなんて発生し得ないわけで、実際には影響は極々軽微と思われます。
私のような仕様バkに突っ込まれる程度で。