Porting an R analysis
Inputs
RunningThis analysis of 250 students in 12 schools was written in R with dplyr and tidyr. phplyr keeps the function and argument names, so the translation is mostly syntax: bare column names become strings or col(), = becomes :, and .default becomes default. The inputs change the pass mark and the study-time bands; the code below shows the defaults.
The R original:
clean <- schools |>
filter(!is.na(score), study_hours > 0) |>
mutate(
hours_band = case_when(study_hours < 4 ~ "low", study_hours < 8 ~ "mid", .default = "high"),
gain = score - prior_score,
passed = as.integer(score >= 75)
)
clean |>
group_by(school) |>
summarize(n = n(), mean_gain = mean(gain), pass_rate = mean(passed)) |>
arrange(desc(mean_gain))
$clean = $schools |>
filter(col('score')->isNa()->not(), col('study_hours')->gt(0)) |>
mutate(
hours_band: case_when([col('study_hours')->lt(4), 'low'], [col('study_hours')->lt(8), 'mid'], default: 'high'),
gain: col('score')->sub(col('prior_score')),
passed: if_else(col('score')->ge(75), 1, 0),
);
$gains = $clean |>
group_by('school') |>
summarize(n: n(), mean_gain: mean('gain'), pass_rate: mean('passed')) |>
arrange(desc('mean_gain'));
$clean = phplyr($schools)
->filter(col('score')->isNa()->not(), col('study_hours')->gt(0))
->mutate(
hours_band: case_when([col('study_hours')->lt(4), 'low'], [col('study_hours')->lt(8), 'mid'], default: 'high'),
gain: col('score')->sub(col('prior_score')),
passed: if_else(col('score')->ge(75), 1, 0),
)
->get();
$gains = phplyr($clean)
->groupBy('school')
->summarize(n: n(), mean_gain: mean('gain'), pass_rate: mean('passed'))
->arrange(desc('mean_gain'))
->get();
- Students
- 250
- Pass rate
- 39.6%
- Mean gain
- 12.21
Schools by mean gain
| school | n | mean_gain | pass_rate |
|---|---|---|---|
| school-07 | 19 | 24.287 | 0.842 |
| school-10 | 25 | 14.138 | 0.320 |
| school-02 | 24 | 13.641 | 0.458 |
| school-09 | 16 | 13.367 | 0.500 |
| school-03 | 15 | 12.912 | 0.333 |
| school-11 | 23 | 12.286 | 0.348 |
| school-06 | 27 | 12.231 | 0.481 |
| school-05 | 20 | 11.338 | 0.550 |
| school-01 | 18 | 9.904 | 0.389 |
| school-12 | 20 | 8.681 | 0.150 |
| school-08 | 21 | 8.667 | 0.095 |
| school-04 | 22 | 5.893 | 0.318 |
Mean gain and pass rate by study-time band
Reshaping works the same way. pivot_longer() gives one row per student and test, and pivot_wider() spreads the band counts into columns.
Prior and final scores
| test | mean | sd |
|---|---|---|
| final | 71.989 | 10.314 |
| prior | 59.777 | 12.441 |
Students per school and band
| school | high | low | mid |
|---|---|---|---|
| school-01 | 7 | 4 | 7 |
| school-02 | 8 | 8 | 8 |
| school-03 | 5 | 3 | 7 |
| school-04 | 13 | 1 | 8 |
| school-05 | 9 | 6 | 5 |
| school-06 | 15 | 4 | 8 |
| school-07 | 9 | 4 | 6 |
| school-08 | 5 | 6 | 10 |
| school-09 | 5 | 3 | 8 |
| school-10 | 7 | 8 | 10 |
| school-11 | 8 | 9 | 6 |
| school-12 | 4 | 9 | 7 |
With the phit extension loaded, lm() and glm() fit models to the table, as R's functions do.
$fit = $clean |> lm('score ~ study_hours + prior_score');
$logit = $clean |> glm('passed ~ study_hours + prior_score', family: 'binomial');
$fit = phplyr($clean)->lm('score ~ study_hours + prior_score');
$logit = phplyr($clean)->glm('passed ~ study_hours + prior_score', family: 'binomial');
Linear model of the final score
| Term | Estimate | Std. error | t | p | 95% CI |
|---|---|---|---|---|---|
| (Intercept) | 45.3014 | 2.3222 | 19.51 | < 0.0001 | [40.727, 49.875] |
| study_hours | 1.5691 | 0.2054 | 7.64 | < 0.0001 | [1.165, 1.974] |
| prior_score | 0.2730 | 0.0530 | 5.15 | < 0.0001 | [0.168, 0.377] |
n = 250, R² = 0.5972, σ = 6.5719, log-likelihood = -823.93
Logistic model of passing (score ≥ 75)
| Term | Estimate | Std. error | z | p | 95% CI |
|---|---|---|---|---|---|
| (Intercept) | -6.9865 | 1.2400 | -5.63 | < 0.0001 | [-9.417, -4.556] |
| study_hours | 0.5688 | 0.0991 | 5.74 | < 0.0001 | [0.375, 0.763] |
| prior_score | 0.0395 | 0.0235 | 1.68 | 0.0922 | [-0.006, 0.086] |
n = 250, log-likelihood = -98.13, AIC = 202.3, deviance = 196.26
Script: site/vignettes/port-r-script.php in phpstats/phplyr@d319dc5.