{{ message }}

Instantly share code, notes, and snippets.

# pietersv/rim_weights.md

Last active Jun 12, 2020
Calculate rim weights

# Rim weighting algorithm

The function below calculates a single respondent-level weight variable such that when applied as a weight, the marginal distribution of multiple elements yields the desired proportions. This can be useful to ensure that the results of a survey sample reflect the population distribution.

## Algorithms

Add this function within a Protobi data process:

```/**
* Calculate a single respondent-level  weight such that when weighting is applied
* multiple variables yield the desired marginal distribution
* @param protobi   Protobi instance with elements and data preset
* @param name      Name of weight variable to calculate within protobi.data()
* @param targets   Object specifying target marginal distributions for one or more elements
*    { <key> : { <val>: <proportion>, <val>:<proportion> } }
*/
Protobi.calculate_rim_weights = function(protobi, name, targets)  {

var rows = protobi.data() // assume rows have already been set

var weights = {}
rows.forEach(function(row) {
row.weight = 1;
})
protobi.setGlobalWeight(name)

// iterate 10 times. We could get fancier about convergence but good enough
for (var i=0; i<10; i++) {
// iterate over each attribute with weighting criteria
_.each(targets, function(vals, key) {
var marginal = protobi.getMarginal(key);
weights[key] = weights[key] || {}

for (var val in vals) {
var tgt = vals[val]
var wgt = _.get(weights, [key, val]) || 1
_.set(weights, [key, val], wgt * tgt / marginal.getPercent(val));
}

// now apply these weights so available for the next variable
rows.forEach(function(row, idx) {
row[name] = 1;
_.each(targets, function(vals, key) {
var dim = protobi.getDimension(key)
var val = dim.getValue(row)
if (dim.groupFn) val = dim.groupFn(val)
var factor = _.get(weights, [key, val]) || 1
row[name] *= factor
})
})
})
}

// normalize final weights
var sum_weight = rows.reduce(function(sum, row) {return sum + row[name]}, 0)
rows.forEach(function(row) {row[name] =rows.length * row[name] / sum_weight; })
return weights;

}```

## Example

The below example demonstrates how to apply the above function in data process. This program retrieves the data and elements for the project, calculates the weights and saves the data.

```Protobi.get_tables(["main", "OE"], function(err, data) {
if (err) return callback(err);

Protobi.get_elements(function(err, protobi) {
if (err) return callback(err);

var rows= data["main"] //primary data file
protobi.setData(rows);

Protobi.calculate_rim_weights(
protobi,
'weight', {
"s3":{
"1":0.49,
"2":0.51
},
"s2":{
"0":0.84,
"1":0.16
},
"region":{
"Northeast":0.17,
"Midwest":0.21,
"West":0.24,
"South":0.38,
}
})
return callback (null, rows)
})
})```