── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 3.5.2 ✔ tibble 3.3.0
✔ lubridate 1.9.4 ✔ tidyr 1.3.1
✔ purrr 1.1.0
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Show Code
library(knitr)library(kableExtra)
Attaching package: 'kableExtra'
The following object is masked from 'package:dplyr':
group_rows
Show Code
library(ggplot2)library(plotly)
Attaching package: 'plotly'
The following object is masked from 'package:ggplot2':
last_plot
The following object is masked from 'package:stats':
filter
The following object is masked from 'package:graphics':
layout
Show Code
library(corrplot)
corrplot 0.95 loaded
Show Code
library(car)
Loading required package: carData
Attaching package: 'car'
The following object is masked from 'package:dplyr':
recode
The following object is masked from 'package:purrr':
some
Show Code
library(broom)library(GGally)library(patchwork)library(tinytex)# Set theme for plotstheme_set(theme_minimal() +theme(plot.title =element_text(hjust =0.5, size =14, face ="bold"),plot.subtitle =element_text(hjust =0.5, size =12)))
# Create a tidy ANOVA tableanova_tidy <-tidy(anova_table) %>%mutate(term =case_when( term =="A_Length"~"A: Rotor Length", term =="B_Width"~"B: Rotor Width", term =="C_Clip"~"C: Paper Clip", term =="A_Length:B_Width"~"AB: Length × Width", term =="A_Length:C_Clip"~"AC: Length × Clip", term =="B_Width:C_Clip"~"BC: Width × Clip", term =="A_Length:B_Width:C_Clip"~"ABC: Length × Width × Clip", term =="Residuals"~"Error",TRUE~ term ),across(where(is.numeric), round, 4) ) %>%select(Source = term, DF = df, SS = sumsq, MS = meansq, `F-value`= statistic, `p-value`= p.value)
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `across(where(is.numeric), round, 4)`.
Caused by warning:
! The `...` argument of `across()` is deprecated as of dplyr 1.1.0.
Supply arguments directly to `.fns` through an anonymous function instead.
# Previously
across(a:b, mean, na.rm = TRUE)
# Now
across(a:b, \(x) mean(x, na.rm = TRUE))
if (abs(A_effect) >0.1) {cat("**Rotor Length (A):**", ifelse(A_effect >0, "Longer rotors increase", "Longer rotors decrease"), "flight time by", round(abs(A_effect), 3), "seconds on average.\n")}
**Rotor Length (A):** Longer rotors increase flight time by 0.681 seconds on average.
Show Code
if (abs(B_effect) >0.1) {cat("**Rotor Width (B):**", ifelse(B_effect >0, "Wider rotors increase", "Wider rotors decrease"), "flight time by", round(abs(B_effect), 3), "seconds on average.\n")}
**Rotor Width (B):** Wider rotors decrease flight time by 0.527 seconds on average.
Show Code
if (abs(C_effect) >0.1) {cat("**Paper Clip (C):**", ifelse(C_effect >0, "Adding a paper clip increases", "Adding a paper clip decreases"), "flight time by", round(abs(C_effect), 3), "seconds on average.\n")}
**Paper Clip (C):** Adding a paper clip decreases flight time by 0.402 seconds on average.
Optimal Settings
Show Code
# Find optimal settings for maximum and minimum flight timeoptimal_max <- treatment_means %>%filter(mean_response ==max(mean_response))optimal_min <- treatment_means %>%filter(mean_response ==min(mean_response))cat("### Optimal Settings:\n\n")
cat("- Rotor Length:", ifelse(optimal_min$A_Length ==1, "8.5 cm (Long)", "7.5 cm (Short)"), "\n")
- Rotor Length: 7.5 cm (Short)
Show Code
cat("- Rotor Width:", ifelse(optimal_min$B_Width ==1, "5.0 cm (Wide)", "3.5 cm (Narrow)"), "\n")
- Rotor Width: 5.0 cm (Wide)
Show Code
cat("- Paper Clip:", ifelse(optimal_min$C_Clip ==1, "2 clips", "0 clips"), "\n")
- Paper Clip: 0 clips
Show Code
cat("- Average flight time:", round(optimal_min$mean_response, 3), "seconds\n")
- Average flight time: 2.513 seconds
Final Model
Show Code
# Create reduced model with only significant terms (if any)significant_terms <- anova_tidy %>%filter(!is.na(`p-value`), `p-value`<0.05, Source !="Error") %>%pull(Source)if (length(significant_terms) >0) {cat("### Reduced Model with Significant Terms Only:\n")# Build model formula for significant terms formula_terms <-character()if ("A: Rotor Length"%in% significant_terms) formula_terms <-c(formula_terms, "A_Length")if ("B: Rotor Width"%in% significant_terms) formula_terms <-c(formula_terms, "B_Width")if ("C: Paper Clip"%in% significant_terms) formula_terms <-c(formula_terms, "C_Clip")if ("AB: Length × Width"%in% significant_terms) formula_terms <-c(formula_terms, "A_Length:B_Width")if ("AC: Length × Clip"%in% significant_terms) formula_terms <-c(formula_terms, "A_Length:C_Clip")if ("BC: Width × Clip"%in% significant_terms) formula_terms <-c(formula_terms, "B_Width:C_Clip")if ("ABC: Length × Width × Clip"%in% significant_terms) formula_terms <-c(formula_terms, "A_Length:B_Width:C_Clip")if (length(formula_terms) >0) { formula_string <-paste("Time_s ~", paste(formula_terms, collapse =" + ")) model_reduced <-lm(as.formula(formula_string), data = helicopter_coded)cat("**Reduced Model:**\n")print(summary(model_reduced))# Model comparisoncat("\n**Model Comparison:**\n") comparison <-anova(model_reduced, model_full)print(comparison) }} else {cat("### No statistically significant effects found at α = 0.05 level.\n")cat("Consider using the grand mean as the best predictor.\n")cat("Grand mean flight time:", round(mean(helicopter_coded$Time_s), 3), "seconds\n")}
### Reduced Model with Significant Terms Only:
**Reduced Model:**
Call:
lm(formula = as.formula(formula_string), data = helicopter_coded)
Residuals:
Min 1Q Median 3Q Max
-0.30500 -0.09708 -0.00167 0.06938 0.35500
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.21792 0.03401 94.621 < 2e-16 ***
A_Length 0.34042 0.03401 10.010 8.80e-09 ***
B_Width -0.26375 0.03401 -7.755 3.80e-07 ***
C_Clip -0.20125 0.03401 -5.918 1.33e-05 ***
A_Length:C_Clip -0.11875 0.03401 -3.492 0.0026 **
B_Width:C_Clip 0.09375 0.03401 2.757 0.0130 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.1666 on 18 degrees of freedom
Multiple R-squared: 0.9228, Adjusted R-squared: 0.9014
F-statistic: 43.03 on 5 and 18 DF, p-value: 2.157e-09
**Model Comparison:**
Analysis of Variance Table
Model 1: Time_s ~ A_Length + B_Width + C_Clip + A_Length:C_Clip + B_Width:C_Clip
Model 2: Time_s ~ A_Length * B_Width * C_Clip
Res.Df RSS Df Sum of Sq F Pr(>F)
1 18 0.49964
2 16 0.38340 2 0.11624 2.4255 0.1202
Conclusions
Show Code
cat("## Key Findings:\n\n")
## Key Findings:
Show Code
cat("1. **Design Summary:** This 2³ factorial experiment successfully evaluated the effects of rotor length, rotor width, and paper clip mass on paper helicopter flight time using the classic Box-Bisgaard-Fung methodology.\n\n")
1. **Design Summary:** This 2³ factorial experiment successfully evaluated the effects of rotor length, rotor width, and paper clip mass on paper helicopter flight time using the classic Box-Bisgaard-Fung methodology.
Show Code
cat("2. **Effect Magnitudes:** The largest effects in order of importance are:\n")
2. **Effect Magnitudes:** The largest effects in order of importance are:
Show Code
for (i in1:min(3, nrow(effects_summary))) {cat(" -", effects_summary$Effect[i], ":", sprintf("%+.3f", effects_summary$Estimate[i]), "seconds\n")}
- A (Length) : +0.681 seconds
- B (Width) : -0.527 seconds
- C (Clip) : -0.403 seconds
- Rotor Width: Narrower rotors increase flight time by 0.527 seconds on average
Show Code
if (abs(C_effect) >0.1) {cat(" - Paper Clips:", ifelse(C_effect >0, "Adding clips increases flight time", "Removing clips increases flight time"), "by", round(abs(C_effect), 3), "seconds on average\n")}
- Paper Clips: Removing clips increases flight time by 0.402 seconds on average
Show Code
cat("\n")
Show Code
cat("4. **Statistical Significance:** ")
4. **Statistical Significance:**
Show Code
if (nrow(significant_effects) >0) {cat("The following effects were statistically significant (p < 0.05):\n")for (effect in significant_effects$Source) {cat(" -", effect, "\n") }} else {cat("No effects were statistically significant at the α = 0.05 level.\n")}
The following effects were statistically significant (p < 0.05):
- A: Rotor Length
- B: Rotor Width
- C: Paper Clip
- AC: Length × Clip
- BC: Width × Clip
Show Code
cat("\n")
Show Code
cat("5. **Optimal Conditions for Maximum Flight Time:**\n")
5. **Optimal Conditions for Maximum Flight Time:**