Comparison of Desk and Field Departments Base and Overtime Salary
Introduction
Author: Soleil Short
The Montgomery County Employee Salaries – 2025 dataset from the Montgomery County Database contains the salary information for all Montgomery County employees in the year 2025. It has categorical information like department, department name, division, gender, and grade. It also has quantitative information like base salary, overtime pay, and longevity pay.
Montgomery County has countless departments, but what I want to explore is how pay differs between a desk job, like Human Resources and Finance, compare to a field job like Police and Fire and Rescue. I want to look at which departments get paid more based on Base Salary, and how would that change the way overtime pay looks?
I recognize that both departments could have desk and field roles, however, here I am viewing them as a single entity.
Rows: 10632 Columns: 8
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (8): Department, Department Name, Division, Gender, Base Salary, 2025 Ov...
ℹ 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.
First, I’m going to filter the departments to the ones I named.
employee_filter <-filter(employee_sal, `Department Name`%in%c("Department of Finance", "Office of Human Resources", "Department of Police", "Fire and Rescue Services"))
Now I have my filtered, selected, and grouped data set and I can start creating my first graph.
Boxplot
First the box plot to compare lowest and highest pay, and to see the median with all four departments, and the outliers.
ggplot(employee_final) +geom_boxplot(aes(x =`Base Salary`/1000, y =`Department Name`, fill =`Department Name`)) +scale_fill_manual(values =c("#0A24A3","#E35E2B", "#BA3907", "#1315BA"),labels =c("Finance (Desk Job)","Police (Field Job)","Fire & Rescue (Field Job)", "Human Resources (Desk Job)")) +labs(x ="Base Salary (in Thousands of Dollars)", y ="Department Name", title ="Base Salary by Department in Montgomery County 2025", caption ="Source: data.montgomerycountymd.gov",fill ="Job Type") +theme_bw()
The thick vertical line within each box shows the median base salary for that department. Looking at the boxplot, we can see that the Department of Finance has the highest median base salary, and the Office of Human Resources has the second highest. This is telling us that these desk-based roles have higher baseline pay compared to field-based departments. However, the field-based departments have a larger salary distribution. All four of the departments show outliers past $200,000. This could represent high ranking roles within the departments.
Correlation between base salary and overtime pay.
Now we will be looking at how this can change with overtime pay.
Building Linear Regression Model
regress_model <-lm(`2025 Overtime Pay`~`Base Salary`, data = employee_final)summary(regress_model)
Call:
lm(formula = `2025 Overtime Pay` ~ `Base Salary`, data = employee_final)
Residuals:
Min 1Q Median 3Q Max
-41839 -14472 -6550 6444 293254
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.424e+02 1.325e+03 0.334 0.738
`Base Salary` 1.556e-01 1.222e-02 12.738 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 24350 on 3348 degrees of freedom
Multiple R-squared: 0.04622, Adjusted R-squared: 0.04594
F-statistic: 162.3 on 1 and 3348 DF, p-value: < 2.2e-16
The model equation I got is:
Overtime Pay = 0.1556(Base.Salary) + 442.4
This is saying that for every additional dollar in the base salary, overtime increased by 16 cents (.1556 rounded up).
P-value: The P-value is a very small number, 2.2e-16, and next to base salary, it is accompanied by three asterisks. This means that there is a highly significant relationship between base salary and overtime pay, revealing a connection between the two.
Adjusted R-Squared: The adjusted R-Squared value is 4.59%, meaning that only 4.59% of the overtime pay can be explained for the base salary and 95.41% is unexplained by the base salary. This reveals an actual weak connection between the two, showing that the differences could be explained by job type, like desk and field work.
Diagnostic Plot
plot(regress_model)
The Residuals vs Fitted plot evaluates whether a linear model is appropriate for this data. In my graph, the line is relatively horizontal, indicating that the linear plot is appropriate. This plot also shows that a lot of the employees are earning $0 in overtime pay.
The Q-Q Residuals plot is meant to show whether the distribution is relatively normal. At the end of the Q-Q plot, the distribution goes further away from the line, showing that the distribution is not normal.
The Scale-Location Plot is meant to show homogeneous variance, meaning the groups have similar amounts of variability. Looking at my scale-location plot, it does not have homogenous variance because as we move along to the right and get to the middle of the graph, the dots start to spread out more. The aligned dots on the left side represent the $0 overtime pay values.
Residuals vs Leverage Plot are meant to show which outliers greatly impact the model by pulling the regression towards it. As we can see, row 876 is the furthest from 0, and this indicates that it has a high leverage. Removing the anomalies could change how the model looks.
Conclusion
To clean up the data, I first used the filter () function to select only the departments I will be using in my graph and models. If I didn’t do this, I would have unwanted data, and I wouldn’t be able to find the answers I’m looking for. Next, I used the select () function and the group_by() function. What the select () function does is select wanted columns and remove the rest; I selected Department Name, base salary, and 2025 Overtime Pay. I then used to group_by() function to group all the departments together. Lastly, to finish up cleaning the data, I used the gsub() function and as.numeric function. What this does is allow me to remove “$” and”,” from my Base salary and 2025 Overtime Pay columns. They needed to be removed because even though on the website they are classified as numbers, R doesn’t see them as numbers, so they had to be removed, and then the as.numeric tells R to see those columns as numbers. I was then able to make my visualization and models.
The biggest surprise in the visualization is desk-based departments having a higher median base salary than field-based departments. I had initially assumed it would be the other way around because the field-based departments have more hands-on roles I thought would make the median higher than the desk-based departments, but that wasn’t the case.
Something I could not get to this time, but I wish included was the grade aspect of the salaries. In the original dataset, there is a column called “Grade”, and it refers to the grade given to Montgomery County employees that determines the minimum and maximum salary for that position. For example, an employee with an N5 grade past July 13, 2025, has the maximum salary of $57,576, and an employee having a grade of N40 past July 13, 2025, has the maximum salary of $217,901. It would’ve been interesting to see how grades affect base salary in each department. This information found: https://assets.montgomerycountymd.gov/files/2026-06/FY27-GSS.pdf