Рассмотрим структуру таблицы, в которой есть k
ключевые переменные и n
переменные данных.
Ключевые переменные определяют группу BY
и из всех строк в группе вы хотите выбрать наименьшее строки, чьи значения пропущенных данных полностью покрывают другие строки с такими же, но меньшими значениями пропущенных данных.
Рассмотрим одну строку с 5 переменными данных смешанного типа, абстрактно названную для этого анализа:
C1, C2, N3, C4, C5
C
для символа, N
для номера c.
Примечание. На все переменные данных нельзя ссылаться через один шаг DATA array
из-за различных типов.
Перемещение:
- Построить битовую маску, соответствующую не пропущенным значениям. В него будут включены
m
битов. - Идентификация субмасок
- Те битовые маски, чье покрытие хуже битовой маски
- Там будет
2
m
-1
подмаски
Рассмотрим пример строки:
Примеры значений данных имеют маску с m=3
Есть 2
3
-1 = 7
субмаски
1 1 0 0 *
1 * 0 0 1
1 * 0 0 *
* 1 0 0 1
* 1 0 0 *
* * 0 0 1
* * 0 0 *
Для любой другой строки в группе с такими же значениями (или нулями) соответствующая маска будет являться подмаской строки выборки и, таким образом, будет «неполноценной» по покрытию и, следовательно, может быть отброшена .
А sh, с ключом, который является всеми переменными данных, может использоваться для отслеживания основных строк с некоторой маской и вычисленных подмасок. Если последующая строка имеет подмаску, соответствующую главной маске предыдущей строки, предыдущая строка помечается как подчиненная и, следовательно, может быть отфильтрована из выбора.
A l oop за 2 n значения от 0
до 2
n
-1
- это простой способ перебора всех масок-кандидатов. BAND
Операции с основной маской будут вычислять подмаску из кандидата.
Пример кода
data have;input
ID FIRST:$ LAST:$ YEAR CITY:$ COUNTRY:$; datalines;
1 John SMITH 1985 NewYork USA
1 John . 1985 . USA
1 John . 1985 . UK
1 . SMITH . Miami USA
1 John SMITH 1985 NewYork USA
1 Mark SMITH 1990 London UK
1 Mark SMITH 1990 London UK
1 Mark SMITH 1990 London UK
1 Mark SMITH 1990 London UK
1 . SMITH 1990 London UK
1 Mark . 1990 London UK
1 Mark SMITH . London UK
1 Mark SMITH 1990 . UK
1 Mark SMITH 1990 London .
1 Mark SMITH . London UK
1 Mark . . London UK
;
data have;
set have have(in=_2);
if _2 then id=2;
run;
%macro loadkeysFor(var);
%local i j n itop bits;
%let n = %sysfunc(countw(&var));
%let itop = %eval(&n-1);
%do i = 0 %to &itop;
%local var&i;
%let var&i = %scan(&var,&i+1); %* data variable names;
%end;
%do i = 0 %to &itop;
_&i = &&var&i; %* generate code to save data values;
%end;
%do i = 0 %to &itop;
_bit&i = not missing(_&i); %* generate code to compute bits of mask;
%end;
%* mask indicates the non-missing permutations of 1 bits in mask submasks will be ;
_mask = input(cats(of _bit&itop-_bit0), binary&n..);
/* put (_&itop-_0) (=);*/
/* put (_bit&itop-_bit0) (1.) +1 _mask binary&n..;*/
if h.find() = 0 then continue;
%* continue will skip this row because when 'found' the data values of the row are either
%* - identical to a prior row, or
%* - inferior to a prior row
%*;
_submask = _mask;
_seq = index; %* non-missing seq is the mark of a principal row;
h.add(); %* new principal row. save it, and replace all keys of corresponding key values as inferior;
array _mark(0:%eval(2**&n)) _temporary_;
call missing (of _mark(*));
_seq = .; %* seq is the mark of an inferior submask;
do _maskbits_ = 0 to %eval(2**&n-1);
_submask = band (_mask, _maskbits_); %* good ole BAND - binary and, compute the submask;
if _submask = _mask then continue; %* skip principal row;
if missing(_mark(_submask)) then do; %* reduce extra work, each submask done only once;
_mark(_submask) = 1;
%* generate code to assign data values (from saved values) according to submask;
%* set host variables according to submask;
%do i = 0 %to &itop;
if band(_submask,blshift(1,&i)) then &&var&i = _&i; else call missing(&&var&i);
%end;
rc = h.replace(); %* add/replace hash entry of inferior sub-mask;
end;
end;
format _submask _mask binary&n.. _seq _n_ 4.;
%mend;
options mprint;
data want;
if 0 then set have;
if _n_ = 1 then do;
declare hash h (ordered:'a');
h.defineKey ('first', 'last', 'year', 'city', 'country');
h.defineData('first', 'last', 'year', 'city', 'country', '_seq'); * , 'row', '_submask', '_mask';
h.defineDone();
declare hiter hi('h');
declare hash select();
select.defineKey('_seq');
select.defineDone();
end;
h.clear();
do index = 1 by 1 until (last.id);
set have;
by id;
row = index;
%loadkeysFor(first last year city country)
end;
put index=;
indexTop = index;
%* retrieve maximally covering principal rows of group;
select.clear();
do _n_ = 1 by 1 while (hi.next() = 0);
if _seq then OUTPUT;
end;
keep id first last year city country;
run;