{"word_count": 804, "character_count": 5880}
Since our Fall 2020 session will be 100% online (and off-site), I have to work hard this summer to prepare online quizz and exams. I started intensively to play with Achim's awesome r-exams package. But there are still a few things that I wanted to add, so I will post a series of posts on my blogs to keep tracks of updated functions I will write. Most of them a modification of R internal functions, so the code is hard to read. Here is the file, and I will update it frequentlyurl = "http://freakonometrics.free.fr/onlineExams.R"source(url)I have updated the summary function (more precisely the summary.lm function). To see how it works, consider a simple regressionlibrary(car)reg = lm(prestige ~ women, data=Prestige)my_summary(reg)Call:lm(formula = prestige ~ women, data = Prestige)Residuals:    Min      1Q  Median      3Q     Max -33.444 -12.391  -4.126  13.034  39.185 Coefficients:            Estimate Std. Error t value Pr(&#62;|t|)    (Intercept) 48.69300    2.30760  21.101    2e-16 ***women       -0.06417    0.05385  -1.192    0.236    ---Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1Residual standard error: 17.17 on 100 degrees of freedomMultiple R-squared:  0.014,Adjusted R-squared:  0.004143F-statistic:  1.42 on 1 and 100 DF,  p-value: 0.2362A classical question I ask in my quizz is to hide the [latex]p[/latex]-value of the F-test, and ask what it is (to make sure that students understand the equivalence between the F and the t test, in a simple regression). To hide the [latex]p[/latex]-value, usemy_summary(reg, Fisher=TRUE)Call:lm(formula = prestige ~ women, data = Prestige)Residuals:    Min      1Q  Median      3Q     Max -33.444 -12.391  -4.126  13.034  39.185 Coefficients:            Estimate Std. Error t value Pr(&#62;|t|)    (Intercept) 48.69300    2.30760  21.101    2e-16 ***women       -0.06417    0.05385  -1.192    0.236    ---Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1Residual standard error: 17.17 on 100 degrees of freedomMultiple R-squared:  0.014,Adjusted R-squared:  0.004143F-statistic:  1.42 on 1 and 100 DF,  p-value: ■■■■■(and then, in a multiple choice exam, I ask if it is 1%, 5%, 12%, 23%, 47%, for example). That one was easy, since all those lines are based on the cat function, so I just modify it, if necessaryif(Fisher) cat("\nF-statistic:", formatC(x$fstatistic[1L],     digits = digits), "on", x$fstatistic[2L], "and",         x$fstatistic[3L], "DF,  p-value:", "■■■■■")    if(!Fisher) cat("\nF-statistic:", formatC(x$fstatistic[1L],     digits = digits), "on", x$fstatistic[2L], "and",                    x$fstatistic[3L], "DF,  p-value:", format.pval(pf(x$fstatistic[1L],                    x$fstatistic[2L], x$fstatistic[3L], lower.tail = FALSE),                    digits = digits))(here I use the unicode 'black square' symbol to hide numbers). Of course, I can hide the value of [latex]\sigma[/latex], or the (adjusted or not) [latex]R ^2[/latex], etc.Now, a little bit more tricky: what if we want to change the regression table, with the coefficients, their standard deviation, etc.  It is tricky since those values are numeric, with an appropriate format (not too many digits), but it can be done easily since that formating is done through the printCoefmat function.  So in my code, I have my internal function, where I ask to put some 'black square' (and the good number to keep a readable format) at some specific locations. Consider a more complex regressionreg = lm(prestige ~ ., data=Prestige)and assume that we want to hide the value of the intercet, [latex]\widehat{\beta}_0[/latex] (i.e. located at [latex](1,1)[/latex] in the matrix) and the [latex]p[/latex]-value of the t-test for the fourth one (i.e. located at [latex](4,4)[/latex] in the matrix - since the first colum is [latex]\widehat{\beta}_3[/latex], the second one its standard deviation, the thirst one the [latex]t[/latex] value, and then, the fourth one, the [latex]p[/latex]-value of the test). I use the following two vectorsvligne = c(1,4),vcolonne = c(1,4)with rows and columns in the matrix (of course, the two should have the same length). Then, the good thing is that the printCoefmat function convert numerical values into characters (to have things that look like columns actually). So we simply have to remove numerical digits, and use squares insteadCf2=Cf  if(length(vligne)&#62;0){      for(i in 1:length(vligne)){      long = nchar(Cf[vligne[i],vcolonne[i]])      Cf2[vligne[i],vcolonne[i]] = paste(rep("■",long),collapse = "")    }}Then, we print the updated version of the tableprint.default(Cf2, quote = quote, right = right, na.print = na.print,...)For example, here, it would bemy_summary(reg, vligne=c(1,4), vcolonne=c(1,4))Call:lm(formula = prestige ~ ., data = Prestige)Residuals:     Min       1Q   Median       3Q      Max -12.9863  -4.9813   0.6983   4.8690  19.2402 Coefficients:              Estimate Std. Error t value Pr(&#62;|t|)    (Intercept) ■■■■■■■■■■  8.018e+00  -1.513  0.13380    education    3.933e+00  6.535e-01   6.019 3.64e-08 ***income       9.946e-04  2.601e-04   3.824  0.00024 ***women        1.310e-02  3.019e-02   0.434  ■■■■■■■    census       1.156e-03  6.183e-04   1.870  0.06471 .  typeprof     1.077e+01  4.676e+00   2.303  0.02354 *  typewc       2.877e-01  3.139e+00   0.092  0.92718    ---Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1Residual standard error: 7.037 on 91 degrees of freedom  (4 observations deleted due to missingness)Multiple R-squared:  0.841,Adjusted R-squared:  0.8306F-statistic: 80.25 on 6 and 91 DF,  p-value: &#60; 2.2e-16Of course, it is hand made, I do not check for typos (like you should not ask to put squares in the seventh column), but that works well enough to generate random regressions in a quizz (or identical regressions on subsamples of a large dataset), and to hide values, in a quizz.