The goal of this assignment is to evaluate a binary classification model using the provided dataset. Before writing any code, I read the article on classification metrics that was assigned, which explains confusion matrices, accuracy, precision, recall, and F1 score using a cancer diagnosis example.
My plan is to first calculate the null error rate, basically how accurate a model would be if it just guessed the majority class every time. The article’s example showed that a bad model can still get 95% accuracy if the data is imbalanced, so I want to check whether the penguin data has that same issue before trusting any accuracy numbers later.
Next, I’ll compute confusion matrices at three thresholds (0.2, 0.5, 0.8) by comparing “.pred_female” to each threshold myself, rather than using the “.pred_class” column that’s already in the file. From each confusion matrix I’ll calculate Accuracy, Precision, Recall, and F1.
The first challenge I anticipate is making sure I don’t mix up which class counts as “positive.” The second challenge will be figuring out a good way to present three confusion matrices and a metrics table clearly instead of just dumping numbers into the document. Once I have the results, I plan to think through the precision/recall tradeoff to explain when a lower or higher threshold would make more sense in practice.
To begin, we load the dataset from the GitHub url.
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.2.1 ✔ readr 2.2.0
✔ forcats 1.0.1 ✔ stringr 1.6.0
✔ ggplot2 4.0.3 ✔ tibble 3.3.1
✔ lubridate 1.9.5 ✔ tidyr 1.3.2
✔ purrr 1.2.2
── 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
Rows: 93 Columns: 3
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): .pred_class, sex
dbl (1): .pred_female
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
ggplot(penguins, aes(x = sex, fill = sex)) +geom_bar() +labs(title ="Distribution of Actual Class (sex)",x ="Actual Class", y ="Count") +theme_minimal()
The above bar chart visualizes class distributions (we previously confirmed majority class is male).
Task 2: Confusion Matrices at Multiple Thresholds
Computing predicted classes at each threshold (0.2, 0.5(default .pred_class) and 0.8).
The best threshold to use depends on the results we want or need to achieve. A 0.2 threshold gives the model a lot of leeway for making predictions and would be useful if we needed to ensure every single female penguin is checked - e.g. if there is a severe disease affecting that population.
On the other hand, if we need to be sure to only select female penguins, we would want to use a 0.8 threshold, which increases precision.
Conclusion
Creating a useful model entails deciding which factors are the most important. This assignment showed why a single number like accuracy isn’t enough to judge a model. The null error rate gave me a baseline to compare against, and calculating Precision, Recall, and F1 at three different thresholds showed how much the “right” answer depends on which mistake matters more in a given situation, missing a true case or acting on a false one.
AI Citation
Anthropic. (2026). Claude Sonnet 5 [Large language model]. https://claude.ai. Accessed September 13, 2026.