Как выполнить левое внешнее объединение с помощью команд SPSS? - PullRequest
3 голосов
/ 04 октября 2011

Можно ли использовать команды SPSS (например, MERGE FILES) для выполнения левого внешнего соединения между двумя наборами данных SPSS?Предположим, что поле соединения не уникально ни в одном наборе данных.

Пример. Пусть левый набор данных 1 содержит 2 поля - ClassNbr и Fact1 - и эти 4 записи.,.

1 A
1 D
2 A
3 B

Пусть Dataset2 содержит 2 поля - ClassNbr и Fact2 - и эти 3 записи.,.

1 XX
1 XY
3 ZZ

Я хочу присоединиться к Dataset1 и Dataset2 на ClassNbr.Желаемым результатом является набор из 6 записей следующим образом:

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

Я бы предпочел решение, использующее команды SPSS (в отличие от SQL / Python / и т. Д.).

Ответы [ 2 ]

2 голосов
/ 23 июля 2014

Это можно сделать, если установить пакет расширения «STATS CARTPROD».С помощью этого расширения вы можете создать декартово произведение как промежуточный шаг для создания внешнего соединения.

Начиная с SPSS 22, вы можете загрузить его прямо из меню программы Extra-> Extension Bundles-> Install and Download bundles extension.Вы также можете скачать и установить его вручную здесь: https://www.ibm.com/developerworks/community/files/app?lang=en#/file/d0afcd4e-6d5d-4779-84ef-2b68bc81b861 Обратите внимание, что для его работы необходимо установить "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.

Теперь включите случаи, которые не совпадают в данных 2.

*** 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.
2 голосов
/ 04 октября 2011

Насколько я знаю, вы не можете сделать это напрямую. Один из возможных способов сделать это - «преобразовать» данные из длинного формата в широкоформатный (с использованием 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). Но, надеюсь, это поможет вам начать.

...