Удаление строк дубликатов в SAS

Тема довольно простая и задача, я думаю, распространенная, но поскольку мне в моей работе с ней пришлось столкнуться совсем недавно, то не обошлось без кривого кода и дальнейшего радостного нахождения необходимой функции. Поэтому для наглядности расскажу все по порядку.
Вначале мной был опробован метод основанных на тех знаниях которые у меня были, а именно использовались магические First.переменная и Last.переменная . Что это?
Если вы отсортируете вашу базу по какой-либо переменной , например, Name, то получите, скажем, такой  результат:
Name
1
Андрей  
2
Андрей  
3
Вася   
4
Коля   
5
Яна    
6
Яна    
7
Яна    
8
Яна    
Так вот, поскольку SAS обрабатывает данные построчно, то находясь на первой строке он будет знать что Андрей под номером 1 это начало группы Андреев и для первого Андрея будет выполнятся условие  Fist.Name=1, для последнего Андрея (2 строка), замыкающего группу будет верно Last.Name=1.
Name
Для проверки переменной Name
1
Андрей  
Fist=1
2
Андрей  
Last=1
3
Вася   
Fist=1    Last=1
4
Коля   
Fist=1    Last=1
5
Яна    
Fist=1
6
Яна    
7
Яна    
8
Яна    
Last=1
Т.к. Вася у нас в списке один то он является как началом, так и концом группы т.е. обрабатывая строчку с Васей  SAS будет считать что для него верны оба выражения Fist.Name=1 и Last.Name=1.
Ян у нас много, для Ян в 6 и 7 строке оба условия
if  Fist.Name=1 и 
if  Last.Name=1 
ложные т.к. они не начинают и не замыкают отсортированные группы. 
Если попытаться подытожить, то после сортировки вы с помощью условий Fist.переменная=1 и Last. переменная =1 можете понять — где начинается и где кончается отсортированная группа. К слову если вы будете сортировать по нескольким переменным картина будет примерна такая:
Name
Age
Для проверки переменной Name
Для проверки переменной Age
1
Андрей  
12
Fist=1
Fist=1    Last=1
2
Андрей  
13
Last=1
Fist=1    Last=1
3
Вася   
11
Fist=1    Last=1
Fist=1    Last=1
4
Коля   
15
Fist=1    Last=1
Fist=1    Last=1
5
Яна    
14
Fist=1
Fist=1
6
Яна    
14
7
Яна    
14
Last=1
8
Яна    
67
Last=1
Fist=1    Last=1
Ну вот на идеи заключающейся в том, что нам надо оставить только те записи, которые являются началом очередной группы ( при сортировке по двум переменным началом группы по второй переменной) и был основан «гениальный» метод  удаления дубликатов. Этот метод еще допустим, если надо решить проблему дубликатов по одной или двум переменным, но как только встает вопрос о всех переменных, тут уж простите «хана», надо сперва отсортировать по всем переменным а потом прописать кучу условий и становится понятно что кто-то чего то не знает. Т.к. не могли создатели языка не подумать о столь простой и нужной вещи. Она и нашлась спустя пары минут поиска:
PROC SORT  in= ФАЙЛ out=ФАЙЛ NODUNKEY;
BY _ALL_; *в этом случае дубликаты ищутся по всем переменным, можно прописать по каким именно вам надо;
Run;
Отрабатывае этот код, естественно, в разы быстрее чем все придуманные мной до этого извращения.
Заметка будет полезна скорее начинающим чем людям долго работающим с SAS

Удаление строк дубликатов в SAS: 9 комментариев

  1. К сожалению, проблема в обоих способах заключается в том, что требуется использовать сортировку. Обычно это означает нагрузку на БД, которая не желательна.

    Я бы порекомендовал использовать PROC SQL в этих целях.

    Допустим у нас есть табличка TABLE (ID CHAR) на стороне БД с которой нам предстоит работать.

    Тогда код бы примерно выглядел так:

    libname t1 ;
    libname t2 ;

    proc sql;
    create table t2.TABLE2 as t1.TABLE;
    insert into t2.TABLE2
    select * from t1.table
    group by ID
    having count(ID) > 0;
    quit;

  2. Стоит сравнить методы, у меня был довольно большой массив больше 50 мл записей и отрабатывал он за секунды, тогда завтра поэкспериментирую и сравним результаты, это будет интересно)

  3. Не совсем верно описана работа proc sort.
    Опция NODUPLICATES позволяет выкинуть все дублирующиеся строчки. А команда BY _ALL_; говори лишь о том, что нужно произвести сортировку по всем переменным и никак не влияет на удаление дублей.

  4. На мой взгляд этот код просто создаст в таблице t2 копию t1. Можно написать having count(ID) = 0; но тогда будут выброшены вообще все строчки у которых есть дубли, а в задаче требуется один экземпляр оставить.
    Проще всего сделать так:
    proc sql;
    create table t2 as select distinct * from t1;
    quit;

  5. имелось в виду, конечно having count(ID) = 1;
    Еще стоит обратить внимание, что count(ID) будет считать только непустые ID. В общем случае, когда нужно просто подсчитывать количесво строчек в группах, лучше писать count(*) .

  6. Это не совсем верно, нашла заметку:
    http://www.datasavantconsulting.com/roland/nodup.html
    Потестировала NODUPLICATES действительно результат несколько не устойчивый, зато nodupkey выполняет свою функцию вполне стабильно. Думаю в мой заметки стоит заменить одну функцию на другую и будет корректнее)

Добавить комментарий

Войти с помощью: 

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.