3

SPSS コマンド (MERGE FILES など) を使用して、2 つの SPSS データセット間で左外部結合を実行できますか? 結合フィールドはどちらのデータセットでも一意ではないと仮定します。

例: 左の Dataset1 に ClassNbr と Fact1 の 2 つのフィールドと、これらの 4 つのレコードが含まれているとします。. .

1 A
1 D
2 A
3 B

Dataset2 に ClassNbr と Fact2 の 2 つのフィールドと、これらの 3 つのレコードが含まれているとします。. .

1 XX
1 XY
3 ZZ

ClassNbr で Dataset1 と Dataset2 を結合したいと考えています。望ましい結果は、次のような 6 レコードのデータセットです。

1 A XX
1 A XY
1 D XX
1 D XY
2 A (NULL)
3 B ZZ

(SQL/Python などではなく) SPSS コマンドを使用するソリューションをお勧めします。

4

2 に答える 2

2

「STATS CARTPROD」拡張バンドルをインストールすると、これを行うことができます。この拡張機能を使用すると、外部結合を作成するための中間ステップとしてデカルト積を作成できます。

SPSS 22 以降、プログラム メニュー Extra->Extension Bundles->Install and Download extension bundles から直接ダウンロードできます。ここから手動でダウンロードしてインストールすることもできます 。動作させるために「Python Essentials for SPSS」をインストールしました。

*** create the example data.

DATA LIST FREE / classnbr1 (F1) fact1 (A1).
BEGIN DATA
1 A
1 D
2 A
3 B
END DATA.
DATASET NAME data1.

DATA LIST FREE / classnbr2 (F1) fact2 (A2).
BEGIN DATA
1 XX
1 XY
3 ZZ
END DATA.
DATASET NAME data2.

「STATS CARTPROD」拡張機能を使用しているときに、変数名に大文字を使用すると問題が発生しました。「classnbr」が両方のデータセットで異なる変数名を持つことも重要です。

*** create cartesian product using the STATS CARTPROD extension.

DATASET ACTIVATE data1.

STATS CARTPROD INPUT2=data2
   VAR1=classnbr1 fact1 VAR2=classnbr2 fact2
/SAVE OUTFILE="C:\MY FOLDER\cardprod.sav" DSNAME = cart.
EXECUTE.

*** create an equi join.

SELECT IF classnbr1 = classnbr2.
EXECUTE.

DELETE VARIABLES classnbr2.

ここで、data2 に一致しないケースを含めます。

*** create left outer join
* assuming both data sets are ordered by classnbr1 and fact1

ADD FILES 
   /FILE = cart
   /FILE = data1
   /BY classnbr1 fact1.
EXECUTE.
DATASET NAME outer_join.
DATASET ACTIVATE outer_join.

COMPUTE select=1.
IF (length(fact2)=0 AND classnbr1=LAG(classnbr1) AND fact1=LAG(fact1)) select=0.
EXECUTE.

SELECT IF select = 1.
EXECUTE.
DELETE VARIABLES select.

ただし、非常に大きなデータ セットを使用すると、問題が発生する可能性があります。その場合、デカルト積は巨大になります。

この影響を少し軽減するために、デカルト積を生成するに、対応する他のデータ セットに一致しないデータ セットからすべてのケースを削除できます。

これは、それを行う方法です:

*** create the example data.
*** (I added an additional case to the second data set, which will be deleted 
in the result, since it has no match in the first data set)

DATA LIST FREE / classnbr1 (F1) fact1 (A1).
BEGIN DATA
1 A
1 D
2 A
3 B
END DATA.
DATASET NAME data1.

DATA LIST FREE / classnbr2 (F1) fact2 (A2).
BEGIN DATA
1 XX
1 XY
3 ZZ
4 XY
END DATA.
DATASET NAME data2.


*** select cases who (don't) have a matching correspondent in the other dataset

** Create a list of unique key values of data set data2 
** (In this Example the key Value is classnbr2).

DATASET ACTIVATE data2.
DATASET COPY data2_keylist.
DATASET ACTIVATE data2_keylist.

* Assuming the data set is already sorted by the key value.
* Mark the first occurance of every key kalue in the data set.
COMPUTE list = 1.
IF classnbr2 = LAG(classnbr2) list = 0.
SELECT IF list=1.
EXECUTE.

* Delete all variables except the (now unique) key value

MATCH FILES
   /FILE *
   /KEEP classnbr2.
EXECUTE.

** Match the list of data2 key values to data1 in order to mark
** which cases of data1 have at least one correspondent case in data 2.
DATASET ACTIVATE data1.
MATCH FILES
   /FILE *
   /TABLE data2_keylist
      /RENAME classnbr2=classnbr1
      /IN data2
   /BY classnbr1.
EXECUTE.

** Remove cases from data1 who don't have a correspondent in data2
** and store them in another dataset, because we need to add them later.
DATASET COPY date1_nomatch.
SELECT IF data2=1.
EXECUTE.

DATASET ACTIVATE date1_nomatch.
SELECT IF data2=0.
EXECUTE.

** Now doing the same for the other data set.

** Create a list of unique key values of data set data1 
** (In this Example the key Value is classnbr1).

DATASET ACTIVATE data1.
DATASET COPY data1_keylist.
DATASET ACTIVATE data1_keylist.

* Assuming the data set is already sorted by the key value.
* Mark the first occurance of every key kalue in the data set.
COMPUTE list = 1.
IF classnbr1 = LAG(classnbr1) list = 0.
SELECT IF list=1.
EXECUTE.

* Delete all variables except the (now unique) key value

MATCH FILES
   /FILE *
   /KEEP classnbr1.
EXECUTE.

** Match the list of data2 key values to data1 in order to mark
** which cases of data1 have at least one correspondent case in data 2.
DATASET ACTIVATE data2.
MATCH FILES
   /FILE *
   /TABLE data1_keylist
      /RENAME classnbr1=classnbr2
      /IN data1
   /BY classnbr2.
EXECUTE.


** Remove cases from data1 who don't have a correspondent in data2.
SELECT IF data1=1.
EXECUTE.

*** create a cartesian product of the two reduced datasets.
DATASET ACTIVATE data1.

STATS CARTPROD INPUT2=data2
   VAR1=classnbr1 fact1 VAR2=classnbr2 fact2
/SAVE OUTFILE="C:\MY FOLDER\cardprod.sav" DSNAME = outer_join.
EXECUTE.

*** create an equi join.
SELECT IF classnbr1 = classnbr2.
EXECUTE.

DELETE VARIABLES classnbr2.


*** create left outer join by adding the cases from date1_nomatch.
DATASET ACTIVATE outer_join.
ADD FILES 
   /FILE = *
   /FILE = date1_nomatch
   /BY classnbr1 fact1
   /DROP data2.
EXECUTE.

* Some cleaning up.
DATASET CLOSE data1_keylist.
DATASET CLOSE date1_nomatch.
DATASET CLOSE data2_keylist.
于 2014-07-23T18:12:57.513 に答える
2

私の知る限り、これを直接行うことはできません。回避策として考えられる方法の 1 つは、データをロング フォーマットからワイド フォーマットに「再形成」し ( を使用casestovars)、マージを実行してから、ロング フォーマットに再形成することです ( を使用varstocases)。以下は使用例です (コードについて説明が必要な場合は、お問い合わせください)。

data list free / ClassNbr (F1) Fact1 (A1).
begin data
1 A
1 D
2 A
3 B
end data.
dataset name data1.

casestovars 
/id = ClassNbr.

data list free / ClassNbr (F1) Fact2 (A2).
begin data
1 XX
1 XY
3 ZZ
end data.
dataset name data2.

casestovars 
/id = ClassNbr.

match files file = 'data1'
/file = 'data2'
/by ClassNbr.
execute.

varstocases
/make Fact1 FROM Fact1.1 to Fact1.2
/null = KEEP.
varstocases
/make Fact2 FROM Fact2.1 to Fact2.2
/null = KEEP.

これにより、望ましくないケースがいくつか作成されます。ここでは、これらのケースを特定して削除するための一連のコマンドを定義しました (これは、より効率的に改善できると確信しています)。

*now cleaning up the extra records.
compute flag = 0.
if ClassNbr = lag(ClassNbr) and Fact1 = lag(Fact1) and Fact2 = lag(Fact2) flag = 1.
select if flag = 0.
execute.
if Fact1 = " " and Fact2 = " " flag = 1.
select if flag = 0.
execute.
if ClassNbr = lag(ClassNbr) and Fact1 = lag(Fact1) and Fact2 = " " flag = 1.
select if flag = 0.
execute.
if ClassNbr = lag(ClassNbr) and Fact2 = lag(Fact2) and Fact1 = " " flag = 1.
select if flag = 0.
execute.

これをより堅牢にすることができると確信しています(おそらくいくつかのカスタムPython関数を作成します)。しかし、うまくいけば、これはあなたが始めるのに役立ちます.

于 2011-10-04T14:28:41.883 に答える