Package: nonprobest
NonProbEstPython package for statistical inference from non-probability samples.User guideInstallationNonProbEst is available at the Python Package Index (PyPI).pipinstallnonprobestRunning the examplesIn order to run the code included in this guide, the following imports are required.importnonprobestasnpeimportpandasaspdimportnumpyasnpfromnumpy.randomimportdefault_rngfromxgboostimportXGBRegressor,XGBClassifierfromsklearn.naive_bayesimportBernoulliNBfromsklearn.neural_networkimportMLPRegressorAlso, the following code creates some simulated data as assumed in the examples.rng=default_rng(0)pop_size=10000n=1000N=2000np_sample=rng.standard_normal(n*5).reshape(-1,5)p_sample=rng.standard_normal(N*3).reshape(-1,3)population=rng.standard_normal(pop_size*3).reshape(-1,3)weights=[pop_size/N*0.8]*int(N/2)+[pop_size/N*1.2]*int(N/2)defto_category(num_series):returnpd.Series(np.where(num_series>0,"Yes","No"),dtype="category",copy=False)np_sample=pd.DataFrame(np_sample,columns=["A","B","cat","target","target_cat"],copy=False)p_sample=pd.DataFrame(p_sample,columns=["A","B","cat"],copy=False)population=pd.DataFrame(population,columns=["A","B","cat"],copy=False)np_sample["target_cat"]=to_category(np_sample["target_cat"])np_sample["cat"]=to_category(np_sample["cat"])p_sample["cat"]=to_category(p_sample["cat"])population["cat"]=to_category(population["cat"])p_sample["weights"]=weightsIn general,np_sampleandp_samplemust be Pandas DataFrames. In a real example, the user has to verify the covariates. This implies making sure they have the same names in both DataFrame, same data types and same categories (if categorical).All the code may be found in thetest script. Also, check theguide scriptfor code applying NonProbEst to real data.CalibrationCalibration requires a sample and its known population totals.population_totalsmust be a Pandas Series.population_totals=pd.Series({"A":10,"B":5})Additionally, the user must pass either the total population size...calibration_weights=npe.calibration_weights(np_sample,population_totals,population_size=pop_size)...or the initial weights column name.calibration_weights2=npe.calibration_weights(p_sample,population_totals,weights_column="weights")The resulting weights are a numpy array which may be used for estimation as usual.mean_estimation=np.average(np_sample["target"],weights=calibration_weights)proportion_estimation=np.average(np_sample["target_cat"]=="Yes",weights=calibration_weights)Propensity Score AdjustmentPSA requiresnp_sample,p_sampleandpopulation_size.psa_weights=npe.psa_weights(np_sample,p_sample,pop_size)The user may also pass a weights column for thep_sample.psa_weights=npe.psa_weights(np_sample,p_sample,pop_size,weights_column="weights")By default, columns with the same name will be selected as covariates. This may be dangerous. It is preferable to manually select the covariates after having verified them.psa_weights=npe.psa_weights(np_sample,p_sample,pop_size,weights_column="weights",covariates=["A","B","cat"])By default, regularized logistic regression is applied. However, the user may choose any model supporting sample weights and compatible with the scikit-learn API.psa_weights2=npe.psa_weights(np_sample,p_sample,pop_size,weights_column="weights",model=XGBClassifier(enable_categorical=True,tree_method="hist"))For models requiring only numerical data without missing values,make_preprocess_estimatoradds some default preprocessing.psa_weights3=npe.psa_weights(np_sample,p_sample,pop_size,weights_column="weights",model=npe.make_preprocess_estimator(BernoulliNB()))The result is a dictionary with thenp_sampleandp_samplePSA weights as numpy arrays. The weights for thenp_samplemay be used for estimation as usual.mean_estimation=np.average(np_sample["target"],weights=psa_weights["np"])proportion_estimation=np.average(np_sample["target_cat"]=="Yes",weights=psa_weights["np"])Statistical MatchingMatching requiresnp_sample,p_sampleandtarget_column(fromnp_sample).mean_estimation=np.average(np_sample["target"],weights=psa_weights["np"])proportion_estimation=np.average(np_sample["target_cat"]=="Yes",weights=psa_weights["np"])It the target variable is categorical, a target category is required and probabilities are returned.cat_matching_values=npe.matching_values(np_sample,p_sample,"target_cat","Yes")By default, columns with the same name will be selected as covariates. This may be dangerous. It is preferable to manually select the covariates after having verified them.matching_values=npe.matching_values(np_sample,p_sample,"target",covariates=["A","B","cat"])By default, ridge regression (or regularized logistic regression for categorical values) is applied. However, the user may choose any model compatible with the scikit-learn API.matching_values2=npe.matching_values(np_sample,p_sample,"target",model=XGBRegressor(enable_categorical=True,tree_method="hist"))For models requiring only numerical data without missing values,make_preprocess_estimatoradds some default preprocessing.matching_values3=npe.matching_values(np_sample,p_sample,"target",model=npe.make_preprocess_estimator(MLPRegressor()))The result is a dictionary with thep_sampleandnp_sampleimputed values (or probabilities if categorical) as numpy arrays. The values for thep_samplemay be used for estimation as usual.mean_estimation=np.average(matching_values["p"],weights=p_sample["weights"])proportion_estimation=np.average(cat_matching_values["p"],weights=p_sample["weights"])Doubly robustThe parameters are analogous tomatching.doubly_robust_estimation=npe.doubly_robust_estimation(np_sample,p_sample,"target",covariates=["A","B","cat"])cat_doubly_robust_estimation=npe.doubly_robust_estimation(np_sample,p_sample,"target_cat","Yes",covariates=["A","B","cat"])Default models are aplied. As usual, custom ones may be specified.doubly_robust_estimation2=npe.doubly_robust_estimation(np_sample,p_sample,"target",psa_model=XGBClassifier(enable_categorical=True,tree_method="hist"),matching_model=XGBRegressor(enable_categorical=True,tree_method="hist"))The estimated mean/proportion is directly returned by the method.TrainingTraining is the recommended method. The parameters and returning values are analogous tomatching, except now there are 2 models the user may optionally specify.training_values=npe.training_values(np_sample,p_sample,"target",psa_model=XGBClassifier(enable_categorical=True,tree_method="hist"),matching_model=XGBRegressor(enable_categorical=True,tree_method="hist"))The imputed values for thep_samplemay be used for estimation as usual.Kernel weightingKernel weighting parameters are analogous topsa.kw_weights=npe.kw_weights(np_sample,p_sample,pop_size,weights_column="weights",covariates=["A","B","cat"])A numpy array with the estimated weights for thenp_sampleis returned.proportion_estimation=np.average(np_sample["target_cat"]=="Yes",weights=kw_weights)Working with census dataThe exact same methods can be used when the "probabilistic sample" includes the whole population instead.imputed_values=npe.training_values(np_sample,population,"target")cat_imputed_values=npe.training_values(np_sample,population,"target_cat","Yes")mean_estimation=np.average(imputed_values["p"])proportion_estimation=np.average(cat_imputed_values["p"])