@@ -22,13 +22,13 @@ These problems induce **selection** biases that present challenges to interpre
22222323To illustrate how social scientists have thought about estimating the prevalence of such embarrassing activities and opinions, this lecture describes a classic approach of S. L. Warner {cite}`warner1965randomized`.
242425-Warner used elementary probability to construct a way to protect the privacy of **individual** respondents to surveys while still estimating the fraction of a **collection** of individuals who have a socially stichmatized characteristic or who engage in a socially stimatized activity.
25+Warner used elementary probability to construct a way to protect the privacy of **individual** respondents to surveys while still estimating the fraction of a **collection** of individuals who have a socially stigmatized characteristic or who engage in a socially stigmatized activity.
262627-Warner's idea was to add **noise** between the respondent's answer and the **signal** about that answer that the survey taker ultimately receives.
27+Warner's idea was to add **noise** between the respondent's answer and the **signal** about that answer that the survey maker ultimately receives.
282829-Knowing about the structure of the noise assures the respondent that survey taker does not observe his answer.
29+Knowing about the structure of the noise assures the respondent that the survey maker does not observe his answer.
303031-Statistical properties of the noise injection procedure provide the a respondent **plausible deniability**.
31+Statistical properties of the noise injection procedure provide the respondent **plausible deniability**.
32323333Related ideas underlie modern **differential privacy** systems.
3434@@ -83,7 +83,7 @@ $$
8383\log(L)= n_1 \log \left[\pi p + (1-\pi)(1-p)\right] + (n-n_{1}) \log \left[(1-\pi) p +\pi (1-p)\right]
8484$$ (eq:two)
858586-The first-order necessary condition for maximimizng the log likelihood function with respect to $\pi$ is:
86+The first-order necessary condition for maximizing the log likelihood function with respect to $\pi$ is:
87878888$$
8989\frac{(n-n_1)(2p-1)}{(1-\pi) p +\pi (1-p)}=\frac{n_1 (2p-1)}{\pi p + (1-\pi)(1-p)}
@@ -197,48 +197,55 @@ under different values of $\pi_A$ and $n$:
197197198198```{code-cell} ipython3
199199class Comparison:
200- def __init__(self,A,n):
200+ def __init__(self, A, n):
201201 self.A = A
202202 self.n = n
203- TaTb = np.array([[0.95,1],[0.9,1],[0.7,1],[0.5,1],[1,0.95],[1,0.9],[1,0.7],[1,0.5],[0.95,0.95],[0.9,0.9],[0.7,0.7],[0.5,0.5]])
204- self.p_arr = np.array([0.6,0.7,0.8,0.9])
205- self.p_map = dict(zip(self.p_arr,["MSE Ratio: p=" + str(x) for x in self.p_arr]))
206- self.template = pd.DataFrame(columns = self.p_arr)
203+ TaTb = np.array([[0.95, 1], [0.9, 1], [0.7, 1],
204+ [0.5, 1], [1, 0.95], [1, 0.9],
205+ [1, 0.7], [1, 0.5], [0.95, 0.95],
206+ [0.9, 0.9], [0.7, 0.7], [0.5, 0.5]])
207+ self.p_arr = np.array([0.6, 0.7, 0.8, 0.9])
208+ self.p_map = dict(zip(self.p_arr, [f"MSE Ratio: p = {x}" for x in self.p_arr]))
209+ self.template = pd.DataFrame(columns=self.p_arr)
207210 self.template[['T_a','T_b']] = TaTb
208- self.template['Bias']=None
211+ self.template['Bias'] = None
209212210213 def theoretical(self):
214+ A = self.A
215+ n = self.n
211216 df = self.template.copy()
212- df['Bias']=self.A*(df['T_a']+df['T_b']-2)+(1-df['T_b'])
217+ df['Bias'] = A * (df['T_a'] + df['T_b'] - 2) + (1 - df['T_b'])
213218 for p in self.p_arr:
214- df[p] = (1 / (16 * (p - 1/2)**2) - (self.A - 1/2)**2)/self.n / \
215- (df['Bias']**2 + ((self.A * df['T_a'] + (1 - self.A)*(1 - df['T_b']))*(1 - self.A*df['T_a'] - (1 - self.A)*(1 - df['T_b'])) / self.n))
219+ df[p] = (1 / (16 * (p - 1/2)**2) - (A - 1/2)**2) / n / \
220+ (df['Bias']**2 + ((A * df['T_a'] + (1 - A) * (1 - df['T_b'])) * (1 - A * df['T_a'] - (1 - A) * (1 - df['T_b'])) / n))
216221 df[p] = df[p].round(2)
217- df = df.set_index(["T_a", "T_b","Bias"]).rename(columns=self.p_map)
222+ df = df.set_index(["T_a", "T_b", "Bias"]).rename(columns=self.p_map)
218223 return df
219224220225 def MCsimulation(self, size=1000, seed=123456):
226+ A = self.A
227+ n = self.n
221228 df = self.template.copy()
222229 np.random.seed(seed)
223- sample = np.random.rand(size, self.n) <= self.A
224- random_device = np.random.rand(size, self.n)
230+ sample = np.random.rand(size, self.n) <= A
231+ random_device = np.random.rand(size, n)
225232 mse_rd = {}
226233 for p in self.p_arr:
227234 spinner = random_device <= p
228- rd_answer = sample*spinner + (1-sample)*(1-spinner)
235+ rd_answer = sample * spinner + (1 - sample) * (1 - spinner)
229236 n1 = rd_answer.sum(axis=1)
230- pi_hat = (p-1)/(2*p-1) + n1 / self.n / (2*p-1)
231- mse_rd[p] = np.sum((pi_hat - self.A)**2)
237+ pi_hat = (p - 1) / (2 * p - 1) + n1 / n / (2 * p - 1)
238+ mse_rd[p] = np.sum((pi_hat - A)**2)
232239 for inum, irow in df.iterrows():
233240 truth_a = np.random.rand(size, self.n) <= irow.T_a
234241 truth_b = np.random.rand(size, self.n) <= irow.T_b
235- trad_answer = sample * truth_a + (1-sample) * (1-truth_b)
236- pi_trad = trad_answer.sum(axis=1) / self.n
237- df.loc[inum,'Bias'] = pi_trad.mean() - self.A
238- mse_trad = np.sum((pi_trad - self.A)**2)
242+ trad_answer = sample * truth_a + (1 - sample) * (1 - truth_b)
243+ pi_trad = trad_answer.sum(axis=1) / n
244+ df.loc[inum, 'Bias'] = pi_trad.mean() - A
245+ mse_trad = np.sum((pi_trad - A)**2)
239246 for p in self.p_arr:
240- df.loc[inum,p] = (mse_rd[p] / mse_trad).round(2)
241- df = df.set_index(["T_a", "T_b","Bias"]).rename(columns=self.p_map)
247+ df.loc[inum, p] = (mse_rd[p] / mse_trad).round(2)
248+ df = df.set_index(["T_a", "T_b", "Bias"]).rename(columns=self.p_map)
242249 return df
243250```
244251@@ -249,10 +256,10 @@ Let's put the code to work for parameter values
249256250257We can generate MSE Ratios theoretically using the above formulas.
251258252-We can also perform a Monte-Carlo simulation of the MSE Ratio.
259+We can also perform a Monte Carlo simulation of the MSE Ratio.
253260254261```{code-cell} ipython3
255-cp1 = Comparison(0.6,1000)
262+cp1 = Comparison(0.6, 1000)
256263df1_theoretical = cp1.theoretical()
257264df1_theoretical
258265```
@@ -264,7 +271,7 @@ df1_mc
264271265272The theoretical calculations do a good job of predicting the Monte Carlo results.
266273267-We see that in many situations, especially when the bias is not small, the MSE of the randomized-samplijng methods is smaller than that of the non-randomized sampling method.
274+We see that in many situations, especially when the bias is not small, the MSE of the randomized-sampling methods is smaller than that of the non-randomized sampling method.
268275269276These differences become larger as $p$ increases.
270277@@ -278,7 +285,7 @@ For example, for another situation described in Warner {cite}`warner1965randomiz
278285we can use the code
279286280287```{code-cell} ipython3
281-cp2=Comparison(0.5,1000)
288+cp2 = Comparison(0.5, 1000)
282289df2_theoretical = cp2.theoretical()
283290df2_theoretical
284291```
@@ -296,7 +303,7 @@ We can also revisit a calculation in the concluding section of Warner {cite}`wa
296303We use the code
297304298305```{code-cell} ipython3
299-cp3=Comparison(0.6,2000)
306+cp3 = Comparison(0.6, 2000)
300307df3_theoretical = cp3.theoretical()
301308df3_theoretical
302309```
@@ -310,8 +317,7 @@ Evidently, as $n$ increases, the randomized response method does better perform
310317311318## Concluding Remarks
312319313-{doc}`This quantecon lecture <util_rand_resp>` describes some alternative randomized response surveys.
320+{doc}`This QuantEcon lecture <util_rand_resp>` describes some alternative randomized response surveys.
314321315322That lecture presents the utilitarian analysis of those alternatives conducted by Lars Ljungqvist
316323{cite}`ljungqvist1993unified`.
317-