Updating the Data Table

Adding new columns for the two hypotheses.

wildlife <- wildlife |>
  mutate(Animal_Native = if_else(str_detect(Species_Status, "Native"), "Y", "N")) |>
  mutate(Animal_Found = if_else(str_detect(Final_Ranger_Action, "Unfounded"), 0, 1)) |>
  mutate(Animal_Found_YN = if_else(str_detect(Final_Ranger_Action, "Unfounded"), "Not Found", "Found")) |>
  mutate(Animal_Healthy = if_else(str_detect(Animal_Condition, "Healthy"), "Y", "N")) |>
  mutate(DT_Initial = as.POSIXct(DT_Initial, format = "%m/%d/%Y %H:%M")) |>
  mutate(
      Business_Hours = case_when(
        hour(DT_Initial) >= 0 & hour(DT_Initial) < 8 ~ "Not Business Hours",
        hour(DT_Initial) >= 8 & hour(DT_Initial) < 17 ~ "Business Hours",
        hour(DT_Initial) >= 17 & hour(DT_Initial) < 24 ~ "Not Business Hours"
      )
  )

Hypothesis 1: Neyman-Pearson

Response Duration for Native Animals vs Others

It might be expected that park rangers are more equipped to deal with animals that are native to the area that they are working in. To ensure that the rangers have proper training on handling all animals, no matter how exotic or unique they may be, it is worthwhile to see if response calls take more time for non-native animals. A longer response time could hint that further education could be required on how to handle certain non-native animals, or perhaps there are changes in equipment or procedures that may need made to better handle non-native animals. To investigate this, I have devised the below null hypothesis.

\[ H_0: \text{Native Animals will have the same average response duration as other species types.} \]

Based on the box plots below, the averages for native species compared to non-native species look very, very similar. This is a good sign for proper training and procedures for non-native species types.

wildlife |>
  ggplot() +
  geom_boxplot(mapping = 
                 aes(x = log(Response_Duration), 
                     y = Animal_Native)) +
  labs(title = "Response Time by Species Type",
       x = "Log of Response Duration",
       y = "Is the Animal Native?") +
  theme_minimal()
## Warning: Removed 9 rows containing non-finite outside the scale range
## (`stat_boxplot()`).

Looking somewhat closer, we can see the actual average response duration is 1.52 hours (91.2 minutes) vs 1.39 hours (83.6 minutes). This is less than a 10 minute difference is average response duration is relatively small.

avg_response_duration <- wildlife |>
  group_by(Animal_Native) |>
  summarize(avg_response_duration = mean(Response_Duration)) |>
  arrange(Animal_Native)

avg_response_duration
## # A tibble: 2 × 2
##   Animal_Native avg_response_duration
##   <chr>                         <dbl>
## 1 N                              1.52
## 2 Y                              1.39

Effect Size (Cohen’s D)

The below calculates Cohen’s D for the response duration. Given the estimate of -0.078, a negligible effect, it could still be worth doing a hypothesis test, as there is still doubt means between the two groups.

cohen.d(d = filter(wildlife, Animal_Native == "N") |> pluck("Response_Duration"),
        f = filter(wildlife, Animal_Native == "Y") |> pluck("Response_Duration"))
## 
## Cohen's d
## 
## d estimate: 0.07837526 (negligible)
## 95 percent confidence interval:
##      lower      upper 
## 0.02188696 0.13486356
coh_d = -0.07837526

print(coh_d)
## [1] -0.07837526

Choosing a Significance Level

For this test, I have chosen an \(\alpha\) value of 0.10. This is a much more lenient than the standard 0.05, and I will admit to it being somewhat arbitrary. The risk of wrongly rejecting the null hypothesis (i.e. we conclude there is a difference in response durations for native versus non-native animals when there is none), is not particularly costly. If the null hypothesis was rejected, it would indicate that time and money needs to be spent further educating and supplying the urban rangers to more effeciently handle whichever species group (native or non-native) has longer response duration. While this risk is not nothing, the cost of training and potential equipment is not particularly hazardous or costly. Also, based on the preliminary stats that I have run, I believe that if there is an effect, it is likely to be weak, and by widening the significance level, it opens up a greater chance of detecting that effect.

Choosing a Power Level

Similar to the significance level, the \(\beta\) value, or rather the cost of wrongly assuming the null hypothesis (i.e. concluding there is no difference in response duration for native versus non-native animals), there is not much risk for this type II error. Most of the risk comes from not improving current abilities; if additional training is not deemed necessary based on this analysis, but there is room for improvement, then the urban rangers are losing out on the ability to help animals faster and more efficiently. Because of this, \(\beta\) has been set to 0.15

Choosing a Delta \(\Delta\)

The \(\Delta\) for this hypothesis test has been chosen as \(\Delta\) = .5 (30 minutes). Given the average length of a response is approximately 1.5 hours, any deviation past that 30 minute mark would denote a significant increase or decrease in time required to complete a response call.

test1 <- pwrss.t.2means(mu1 = coh_d, 
                       sd1 = 1,
                       kappa = 1,
                       power = .85, alpha = 0.1, 
                       alternative = "not equal")
##  Difference between Two means 
##  (Independent Samples t Test) 
##  H0: mu1 = mu2 
##  HA: mu1 != mu2 
##  ------------------------------ 
##   Statistical power = 0.85 
##   n1 = 2342 
##   n2 = 2342 
##  ------------------------------ 
##  Alternative = "not equal" 
##  Degrees of freedom = 4682 
##  Non-centrality parameter = -2.682 
##  Type I error rate = 0.1 
##  Type II error rate = 0.15
plot(test1)
## Warning in qt(1 - prob.extreme, df = df, ncp = ncp, lower.tail = TRUE): full
## precision may not have been achieved in 'pnt{final}'

Hypothesis 2: Fisher’s Significance Testing

Animals Found Based on Call Time

\[ H_0: \text{A call initiated outside of business hours is just as likely to have the animals found compared to a call initiated during business hours.} \]

This hypothesis will help to examine how likely an animal is to be found if a response is logged outside of standard business hours. If an animal is not found by the urban rangers, it could lead to adverse effects for that animal, other animal populations, and the community at large. By examining if there are differences in response effectiveness during and outside of business hours, we can begin to evaluate whether an “off-hours” response team may be worthwhile.

Given that there are two binary options (during business hours vs outside of business hours and animal found vs animal not found), I have opted for the Chi Squared test.

bh_table <- wildlife |>
  group_by(Business_Hours) |>
  summarize(Anim_Found = sum(Animal_Found),
            Anim_Not_Found = length(Animal_Found) - sum(Animal_Found))

bh_table
## # A tibble: 2 × 3
##   Business_Hours     Anim_Found Anim_Not_Found
##   <chr>                   <dbl>          <dbl>
## 1 Business Hours           4591           1158
## 2 Not Business Hours        426            210
chisq.test(select(bh_table, Anim_Found, Anim_Not_Found))
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  select(bh_table, Anim_Found, Anim_Not_Found)
## X-squared = 55.635, df = 1, p-value = 8.726e-14

This analysis shows and incredibly low p-value of 0.00000000000008726. This would indicate that the data in our sample is highly unlikely if we assumed the null hypothesis is true. Based on this p-value, I would reject the null hypothesis stating that calls outside of business hours are just as likely as calls during business hours to result in found animals.

This conclusion is also supported by the graph below, which shows the percentage of calls resulting in found animals vs not for calls during and outside of business hours.

wildlife |>
  ggplot(aes(x = Business_Hours, fill = Animal_Found_YN )) +
  geom_bar(position = "fill", stat = "count") +
  scale_fill_brewer(palette = "Set2") +
  labs(title = "Percentage of Animals Found by Call Time",
        x = "Was the Call During Business Hours?",
        y = "Percentage of Calls Successfully Found") +
  theme_minimal()