2017-02-07 15 views
0

Я пытаюсь найти быстрый способ заменить отсутствующие значения средним значением двух ближайших не пропущенных значений. Пример:SAS: замена отсутствующего значения средним числом ближайших соседей

Id Amount 
1 10 
2 . 
3 20 
4 30 
5 . 
6 . 
7 40 

Желаемая выход

Id Amount 
1 10 
2 **15** 
3 20 
4 30 
5 **35** 
6 **35** 
7 40 

Любые предложения? Я попытался использовать функцию сохранения, но я могу только выяснить, как сохранить последнее не пропущенное значение.

+1

Как вы определяющую ближайший? Для записи 5, почему это не 20/30 за 25? Ваши правила нуждаются в разъяснении. Посмотрите параметр PROC STANDARDIZE и MISSING для вариантов замены отсутствующих значений.Если ваш случай по-настоящему похож на ваш образец, выбор может быть линейной регрессией с отсутствующими значениями вмененных значений. – Reeza

+0

Хорошая точка. Для уточнения, насколько «близко» я хотел предыдущее не пропущенное значение и следующее не пропущенное значение – User1414

ответ

0

Это работает:

data have; 
    input id amount; 
cards; 
1 10 
2 . 
3 20 
4 30 
5 . 
6 . 
7 40 
; 
run; 

proc sort data=have out=reversed; 
    by descending id; 
run; 

data retain_non_missing; 
    set reversed; 
    retain next_non_missing; 
    if amount ne . then next_non_missing = amount; 
run; 

proc sort data=retain_non_missing out=ordered; 
    by id; 
run; 

data final; 
    set ordered; 
    retain last_non_missing; 
    if amount ne . then last_non_missing = amount; 
    if amount = . then amount = (last_non_missing + next_non_missing)/2; 
run; 

, но, как всегда, будет нуждаться в дополнительной проверки ошибок и т.д. для использования в производстве.

Основная идея состоит в сортировке данных в обратном порядке, что позволяет использовать RETAIN для переноса значения next_non_missing в резервную копию набора данных. Когда сортировка вернется в правильный порядок, у вас будет достаточно информации для интерполяции отсутствующих значений.

Возможно, существует PROC, чтобы сделать это более контролируемым образом (я ничего не знаю о PROC STANDARDIZE, упомянутом в комментарии Reeza), но это работает как решение для обработки данных.

+0

Ницца, это работает. Единственное, что я замечаю, это то, что если первое или последнее наблюдение отсутствует, то код не будет заполнять их (b/c нет последнего отсутствующего или следующего без пропусков). Но это незначительный момент, и можно вручную заполнить их. – User1414

+0

Отлично, пожалуйста, отметьте это как правильный ответ, если вы довольны этим. Вы правы в отношении недостающих первых/последних значений, поэтому я подчеркнул, что необходима дополнительная проверка ошибок - в исходном вопросе не указано, что делать в этих случаях, поэтому я ничего не сделал. Может быть, вы просто хотите перенести последнее известное значение вперед/назад? –

0

Вот альтернатива, не требующая сортировки. Это требует, чтобы идентификаторы были последовательными, хотя это можно обойти, если это не так.

Что он делает, это два оператора set, который получает основные (и предыдущие) суммы и тот, который устанавливает, пока не будет найдена следующая сумма. Здесь я использую последовательность id переменных, чтобы гарантировать, что она будет правильной записью, но вы могли бы написать это по-другому, если необходимо (отслеживать, какой цикл вы используете), если переменные id не являются последовательными или в порядке любого Сортировать.

Я использую проверку first.amount, чтобы убедиться, что мы не пытаемся выполнить второй оператор set больше, чем следовало бы (что рано или поздно заканчивалось).

Вам нужно сделать две вещи по-другому, если вы хотите, чтобы первая/последняя строки обрабатывались по-разному. Здесь я предполагаю, что prev_amount равно 0, если это первая строка, и я предполагаю, что last_amount отсутствует, что означает, что последняя строка просто повторяет последний prev_amount, а первая строка усредняется между 0 и next_amount. Вы можете по-разному относиться к другому, если вы выберете, я не знаю ваших данных.

data have; 
input Id Amount; 
datalines; 
1 10 
2 . 
3 20 
4 30 
5 . 
6 . 
7 40 
;;;; 
run; 

data want; 
    set have; 
    by amount notsorted; *so we can tell if we have consecutive missings; 
    retain prev_amount; *next_amount is auto-retained; 
    if not missing(amount) then prev_amount=amount; 
    else if _n_=1 then prev_amount=0; *or whatever you want to treat the first row as; 
    else if first.amount then do; 
    do until ((next_id > id and not missing(next_amount)) or (eof)); 
     set have(rename=(id=next_id amount=next_amount)) end=eof; 
    end; 
    amount = mean(prev_amount,next_amount); 
    end; 
    else amount = mean(prev_amount,next_amount); 
run; 
2

Я думаю, что то, что вы ищете, может быть больше похоже на интерполяцию. Хотя это не означает два ближайших значения, это может быть полезно.

Существует отличный инструмент для интерполяции в наборах данных, называемый proc expand. (Он также должен делать экстраполяцию, но я еще не пробовал это делать.) Это очень удобно, когда вы делаете серию дат и кумулятивных вычислений.

data have; 
input Id Amount; 
datalines; 
    1 10 
    2 . 
    3 20 
    4 30 
    5 . 
    6 . 
    7 40 
    ; 
run; 

proc expand data=have out=Expanded; 
    convert amount=amount_expanded/method=join; 
    id id; /*second is column name */ 
run; 

Более подробную информацию о прок расширения в документации: https://support.sas.com/documentation/onlinedoc/ets/132/expand.pdf

 Смежные вопросы

  • Нет связанных вопросов^_^