Простой способ сделать взвешенную горячую колоду в Stata? - PullRequest
0 голосов
/ 15 ноября 2018

Я бы хотел провести простую вменяемую колоду горячих колод в Stata. В SAS эквивалентная команда будет выглядеть следующим образом (и обратите внимание, что это более новая функция SAS, начиная с SAS / STAT 14.1 в 2015 году или около того):

proc surveyimpute method=hotdeck(selection=weighted); 

Для ясности, основные требования:

  1. Расчеты в большинстве случаев основаны на строках или одновременны. Если строка 1 жертвует x строке 3, то она также должна пожертвовать y.

  2. Должен учитывать вес. Донор с весом = 2 должен быть в два раза более вероятным, чем донор с весом = 1

Я предполагаю, что отсутствующие данные имеют прямоугольную форму. Другими словами, если набор потенциально отсутствующих переменных состоит из x и y, то либо оба отсутствуют, либо ни один отсутствует. Вот некоторый код для генерации данных примера.

global miss_vars "wealth income"
global weight    "weight"

set obs 6
gen id = _n
gen type = id > 3
gen income = 5000 * _n
gen wealth = income * 4 + 500 * uniform()
gen weight = 1
replace weight = 4 if mod(id-1,3) == 0

// set income & wealth missing every 3 rows
gen impute = mod(_n,3) == 0
foreach v in $miss_vars {
    replace `v' = . if impute == 1
}

Данные выглядят так:

            id       type     income     wealth     weight     impute
  1.         1          0       5000   20188.03          4          0
  2.         2          0      10000   40288.81          1          0
  3.         3          0          .          .          1          1
  4.         4          1      20000   80350.85          4          0
  5.         5          1      25000   100378.8          1          0
  6.         6          1          .          .          1          1

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

Например, строка 3 может выглядеть как одна из следующих пост-горячей палубы (поскольку она заполняет как доход, так и богатство из строки 1 или из строки 2 (но, напротив, никогда не получит доход из строки 1 и богатство из строки 2) ):

  3.         3          0       5000   20188.03          1          1
  3.         3          0      10000   40288.81          1          1

Кроме того, поскольку строка 1 имеет вес = 4, а строка 2 имеет вес = 1, строка 1 должна быть донором 80% времени, а строка 2 должна быть донором 20% времени.

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

Вот несколько кратких заметок о том, как Адриан Мандер и Дэвид Клэйтон упомянули в приведенных выше комментариях @PearlySpencer (плюс последующую версию) адриан Мандер и Дэвид Клейтон:

Похоже, есть пара версий:1003 *

Насколько я могу судить, оба онипредназначен для создания Приблизительной байесовской начальной загрузки , которая, по сути, является версией горячей колоды с несколькими вменениями.К сожалению, ни один из них, похоже, не справляется с весами выборки (или обследования).Второй из двух ("whotdeck") имеет параметр для весов, но, похоже, он предназначен для прогнозирования "пропущенности" и не имеет никакого отношения к весам выборки / опроса.

Первый (("hotdeck "), по крайней мере, похоже на стандартную hotdeck, поэтому может использоваться таким образом, если вам не нужны веса.Второй ("whotdeck"), вероятно, также выполняет простую хотдек, но синтаксис был немного хитрее, и мне не удалось заставить его это сделать (что, вероятно, я провал, и в любом случае не стучатьэто, как кажется, предназначено для более сложных ситуаций).

Я написал Адриану Мандеру по электронной почте, и он сказал, что не использует stackoverflow, но я мог бы написать его ответ по электронной почте на мой вопрос об использовании примера/ опрос весов с помощью hotdeck или whotdeck:

Интересная проблема: если весовые коэффициенты являются весовыми частотами, то проще всего сделать расширение freq_weight и затем использовать hotdeck.

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

0 голосов
/ 16 ноября 2018

Вот краткий и простой подход, который также должен быть довольно быстрым даже для больших наборов данных, поскольку он выполняет только 2 сортировки, и нет ничего более дорогого в вычислительном отношении.Вот код с минимальными комментариями, и ниже приведен тот же код, но с более обширными комментариями:

gen sort_order = uniform()

// save recipient rows to file, keep donors
preserve
keep if impute == 1
save recipients, replace
restore
keep if impute == 0

// prep donor cells
sort type sort_order
by type:  gen weight_sum = sum($weight)
by type:  gen impute_weight = $weight / weight_sum[_N]
by type:  replace impute_weight = sum(impute_weight)
drop weight_sum

// bring back recipient rows and sort entire data set    
append using recipients
replace sort_order = impute_weight if impute_weight != .
gsort type -sort_order

// replace missing values via a simple replace
foreach v in $miss_vars {
   by type: replace `v' = `v'[_n-1] if impute == 1
}

// extra kludge step necessary to handle top rows
gsort type sort_order
foreach v in $miss_vars {
   by type: replace `v' = `v'[_n-1] if `v' == .
}

Кажется, это хорошо работает для тестового примера, но я не тестировал на больших и более сложных случаях,Как отмечалось в вопросе, я ожидаю, что это должно дать те же результаты, что и метод SAS:

proc surveyimpute method=hotdeck(selection=weighted);

Обратите внимание, что если вы не хотите использовать веса, вы можете просто установить их как столбециз них (например, gen weight = 1).

А вот и тот же код, с дополнительными комментариями:

gen sort_order = uniform()

// split off and save the recipient rows
preserve
keep if impute == 1
save recipients, replace

// restore full dataset and keep only donor rows
restore
keep if impute == 0

// set up the donor rows.  the key idea here is to set up such 
// that each donor row represents a probability interval where
// the ordering of the intervals in a cell in random (based on
// the variable "sort_order" and the width of the interval is
// proportional to the weight
sort type sort_order
by type:  gen weight_sum = sum($weight)
by type:  gen impute_weight = $weight / weight_sum[_N]
by type:  replace impute_weight = sum(impute_weight)
drop weight_sum

// append with recipients so we again have a full datasets
// with both donors and recipients
append using recipients

// now we intersperse the donors and recipients using "sort_order"
// which is based on randomness and weight for the donors and
// is purely random for the recipients
replace sort_order = impute_weight if impute_weight != .
gsort type -sort_order

// fill recipient variables from donor rows.  conceptually
// this is very simple.  each recipient row is in within the
// range of some donor cell.  in practice, that is simply 
// the nearest preceding donor cell 
foreach v in $miss_vars {
   by type: replace `v' = `v'[_n-1] if impute == 1
}

// however, there's a minor practical issue that recipient
// cells that are in the range of the first donor cell need
// to be filled by the nearest successive donor cell, which
// can be done by reversing the sort and then filling from
// the nearest preceding donor cell
gsort type sort_order
foreach v in $miss_vars {
   by type: replace `v' = `v'[_n-1] if `v' == .
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...