在Stata中进行加权热台插补的简单方法吗?

时间:2018-11-15 16:44:02

标签: sas stata imputation

我想在Stata中进行简单的加权热平台插补。在SAS中,等效命令如下(并且请注意,这是一个较新的SAS功能,大约在2015年从SAS / STAT 14.1开始):

proc surveyimpute method=hotdeck(selection=weighted); 

那么,为了清楚起见,基本要求是:

  1. 输入大多基于行或同时进行。如果第1行向第3行捐赠了x,那么它也必须捐赠y

  2. 必须考虑重量。体重= 2的供体被选为体重= 1的供体的可能性应该是两倍

我假设丢失的数据是矩形的。换句话说,如果一组可能缺少的变量由xy组成,则两者都将丢失或都不丢失。这是一些用于生成样本数据的代码。

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 :(得分:0)

这是一种简洁明了的方法,即使对于大型数据集也应该是相当快的,因为它只进行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' == .
}

答案 1 :(得分:0)

以下是有关@PearlySpencer的评论中提到的由Adrian Mander和David Clayton编写的有关社区贡献的热甲板例程的一些简短说明(以及后续版本):

似乎有几个版本:

据我所知,这两个都是用来做近似贝叶斯引导程序的,它实际上是Hotdeck的多输入版本。  不幸的是,它们似乎都不处理样本(或调查)权重。这两个中的第二个(“ whotdeck”)确实具有权重参数,但这似乎是为了预测“缺失”,与样本/调查权重无关。

第一个(“ hotdeck”)至少看起来像是一个标准的hotdeck,因此如果不需要重量,可以用这种方式使用。第二个(“ whotdeck”)可能也做一个简单的hotdeck,但是语法有点棘手,我没有成功做到这一点(这对我来说可能是一个失败,无论如何不是敲门它似乎是为更复杂的情况而设计的。)

我给Adrian Mander发了电子邮件,他说他不使用stackoverflow,但是我可以将他的电子邮件回复发布到我的有关使用hotdeck或whotdeck使用样本/调查权重的问题:

  

有趣的问题,如果权重是频率权重,那么最简单的方法是展开freq_weight,然后使用hotdeck。

     

也许可以用一行代码来完成它,使其与其他类型的权重一起工作,因为当前插补是通过生成随机数然后对数据进行排序来对数据集的行进行随机排序来完成的。您需要生成权重来生成随机数,然后可能将权重乘以随机数然后排序(我认为这种事情是可行的,但是这个想法已经浮现在我的脑海,所以需要考虑一下)。