Part 1

Question 1

Below is a function that ought to return “I’m an even number!” if x is an even number. However, we’re having trouble receiving a value despite x == 4, which we know is an even number. Fix the code chunk and explain why this error is occurring. You will have to change the eval=FALSE option in the code chunk header to get the chunk to knit in your PDF.

NOTE: %% is the “modulo” operator, which returns the remainder when you divide the left number by the right number. For example, try 2 %% 2 (should equal 0 as 2/2 = 1 with no remainder) and 5 %% 2 (should equal 1 as 5/2 = 2 with a remainder of 1).

return_even <- function(x){
  if (x %% 2 == 0) {
    return("I'm an even number!")
  }
}

x <- 6
return_even(x)
## [1] "I'm an even number!"

EXPLAIN THE ISSUE HERE: The issue is that there is no argument called in the return_even brackets (hence the error code that argument “x” is missing). An x needs to be inserted in the return_even () for it to run the function for the x value provided and return the even phrase if it’s even.

Question 2

R functions are not able to access global variables unless we provide them as inputs.

Below is a function that determines if a number is odd and adds 1 to that number. The function ought to return that value, but we can’t seem to access the value. Debug the code and explain why this error is occurring. Does it make sense to try and call odd_add_1 after running the function?

return_odd <- function(y){
  if (y %% 2 != 0) {
    odd_add_1 <- y + 1
  }
}

return <- return_odd(3)
return 
odd_add_1

EXPLAIN THE ISSUE HERE: The main problem is that there is no variable saved to create an output. We need to define a variable that equals return_odd (3) - or the function when y=3. I have adjusted the code to name that variable return. Now when y=3 the function will add 1 to that value and we have saved that to a variable name return that will output a 4. We can’t call odd_add_1 because it is a local variable and only has meaning inside of the function and cannot be accessed outside of the function (i.e. not a global variable)

Question 3

BMI calculations and conversions: - metric: \(BMI = weight (kg) / [height (m)]^2\) - imperial: \(BMI = 703 * weight (lbs) / [height (in)]^2\) - 1 foot = 12 inches - 1 cm = 0.01 meter

Below is a function bmi_imperial() that calculates BMI and assumes the weight and height inputs are from the imperial system (height in feet and weight in pounds).

df_colorado <- read_csv("data/colorado_data.csv")
## Rows: 24 Columns: 5
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (2): location, gender
## dbl (3): height, weight, date
## 
## ℹ 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.
bmi_imperial <- function(height, weight){
  bmi = (703 * weight)/(height * 12)^2
  return(bmi)
}

# calculate bmi for the first observation
colorado_1 <- bmi_imperial(df_colorado$height[1], df_colorado$weight[1])
colorado_1
## [1] 42.62802

Write a function called bmi_metric() that calculates BMI based on the metric system. You can test your function with the Taiwan data set excel file in the data folder, which has height in cm and weight in kg.

df_taiwan <- read_excel("data/taiwan_data.xlsx")

bmi_metric <- function(height_cm, weight_kg) {
  height_m <- height_cm / 100     #convert height from cm to m
  bmi <- weight_kg / (height_m^2) }

taiwan_1 <- bmi_metric(df_taiwan$height[1], df_taiwan$weight[1])
taiwan_1
## [1] 21.45357

Question 4

Can you write a function called calculate_bmi() that combines both of the BMI functions? You will need to figure out a way to determine which calculation to perform based on the values in the data.

calculate_bmi <- function (height, weight) {
  if (height >=10) {    #if height is >10 then must be metric
     height <- height / 100     #convert height from cm to m
  bmi <- weight / (height^2) }
  else if (height <10) {   #if height is <10 then runs imperial
     bmi = (703 * weight)/(height * 12)^2
  }
}

# test
colorado_1 <- calculate_bmi(df_colorado$height[1], df_colorado$weight[1])
colorado_1
## [1] 42.62802
taiwan_1 <- calculate_bmi(df_taiwan$height[1], df_taiwan$weight[1])
taiwan_1
## [1] 21.45357

Question 5

Use your function calculate_bmi() to answer the following questions:

What is the average BMI of the individuals in the Colorado data set?

df_colorado$bmi <- mapply(calculate_bmi, df_colorado$height, df_colorado$weight)

average_bmi_colorado <- mean(df_colorado$bmi, na.rm = TRUE)  #average BMI

average_bmi_colorado
## [1] 45.60881

What is the average BMI of the individuals in the Taiwan data set?

df_taiwan$bmi <- mapply(calculate_bmi, df_taiwan$height, df_taiwan$weight)

average_bmi_taiwan <- mean(df_taiwan$bmi, na.rm = TRUE)  #average BMI

average_bmi_taiwan
## [1] 22.99287

Question 6

Combine the Colorado and Taiwan data sets into one data frame and calculate the BMI for every row using your calculate_bmi() function. Print the first six rows and the last six rows of that new data set.

#Have to convert date columns to match each other in date format
df_colorado$date <- as.Date(as.character(df_colorado$date), format = "%Y%d%m")
df_taiwan$date <- as.Date(df_taiwan$date, format = "%d-%b-%y")


#Combine the datasets (already calculated the bmi for each row in the above code under bmi)
combined_df <- bind_rows (df_colorado, df_taiwan)

head(combined_df,6)
tail (combined_df, 6)

Question 7

Make a boxplot that shows the BMI distribution of the combined data, separated by location on the x-axis. Use a theme of your choice, put a title on your graph, and hide the y-axis title.

NOTE: These data are for practice only and are not representative populations, which is why we aren’t comparing them with statistical tests. It would not be responsible to draw any conclusions from this graph!

boxplot <-  ggplot (combined_df, aes (x=location, y = bmi, fill = location)) +
  geom_boxplot() +
  theme_minimal () + 
  labs (title = "Distribution of BMI for Taiwan and Colorado") + #Add title
  theme (
    axis.title.y = element_blank(),  #hide y-axis title
    legend.position = "none")

boxplot

Part 2

Question 8

Recall the patient data from a healthcare facility that we used in Part 2 of Problem Set 7.

We had four tables that were relational to each other and the following keys linking the tables together:

  • patient_id: patients, schedule
  • visit_id: schedule, visits
  • doctor_id: visits, doctors

Use a join to find out which patients have no visits on the schedule.

no_visits <- patients %>%
  left_join(schedule, by = "patient_id")  %>%
  left_join (visits, by = "visit_id")  %>%
  filter(is.na(visit_id))  #filters for rows that return na (no matching visits)

no_visits

Question 9

With this data, can you tell if those patients with no visits on the schedule have been assigned to a doctor? Why or why not?

# your code here? (optional)

YOUR ANSWER HERE: No, you cannot. There is no doctor associated with the patients in the patients file. Only the patients that have visits scheduled in the visits file are assigned a doctor. Thus if there is no visit, there is no doctor data for them.

Question 10

Assume those patients need primary care and haven’t been assigned a doctor yet. Which primary care doctors have the least amount of visits? Rank them from least to most visits.

# Join visits and doctors to count visits per doctor
doctor_visit_counts <- visits %>%
  left_join(doctors, by = "doctor_id") %>%
  group_by(doctor_id, doctor) %>%
  summarise(visit_count = n()) %>%
  arrange(visit_count)  # Rank from least to most
## `summarise()` has grouped output by 'doctor_id'. You can override using the
## `.groups` argument.
doctor_visit_counts

Part 3

Recall in Problem Set 5, Part 2, we were working with data from New York City that tested children under 6 years old for elevated blood lead levels (BLL). [You can read more about the data on their website]).

About the data:

All NYC children are required to be tested for lead poisoning at around age 1 and age 2, and to be screened for risk of lead poisoning, and tested if at risk, up until age 6. These data are an indicator of children younger that 6 years of age tested in NYC in a given year with blood lead levels (BLL) of 5 mcg/dL or greater. In 2012, CDC established that a blood lead level of 5 mcg/dL is the reference level for exposure to lead in children. This level is used to identify children who have blood lead levels higher than most children’s levels. The reference level is determined by measuring the NHANES blood lead distribution in US children ages 1 to 5 years, and is reviewed every 4 years.

Question 11

Load in a cleaned-up version of the blood lead levels data:

bll_nyc_per_1000 <- read_csv("data/bll_nyc_per_1000.csv")
## Rows: 20 Columns: 3
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): borough_id
## dbl (2): time_period, bll_5plus_1k
## 
## ℹ 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.
head (bll_nyc_per_1000)

Create a formattable table (example below) that shows the elevated blood lead levels per 1000 tested across 2013-2016. If the BLL increases from the previous year, turn the text red. If the BLL decreases from the previous year, turn the text green. To accomplish this color changing, you may want to create three indicator variables that check the value between years (e.g. use if_else). If you’ve have used conditional formatting on excel/google sheets, the concept is the same, but with R.

Note: If you are using if_else (hint hint) and checking by the year, you will likely need to use the left quote, actute, backtip, to reference the variable.

We have also provided you a function that you can use within your formattable table to reference this indicator variable to help reduce the code. However, you do not have to use this, and feel free to change the hex colors.

# in the event that plotly was run below, detach plotly
# the option 'style' conflicts when both libraries are loaded
#detach("package:plotly", unload=TRUE)
library(formattable)
library(DT)

bll_wide <- bll_nyc_per_1000 %>%
  spread(key = time_period, value = bll_5plus_1k) %>%
  arrange(borough_id)


#apply colors for greater or less than
formatted_bll_wide <- bll_wide %>%
  formattable(
    list(
      `2014` = formatter("span", style = ~ paste("color:", ifelse(`2014` > `2013`, "#fd626e", "#03d584"))),
      `2015` = formatter("span", style = ~ paste("color:", ifelse(`2015` > `2014`, "#fd626e", "#03d584"))),
      `2016` = formatter("span", style = ~ paste("color:", ifelse(`2016` > `2015`, "#fd626e", "#03d584")))
    ),
    align = c("l", "c", "c", "c"), # Align columns as needed
    colnames = list(
      `Borough` = formatter("span", style = "font-weight: bold;"),
      `2013` = formatter("span", style = "font-weight: bold;"),
      `2014` = formatter("span", style = "font-weight: bold;"),
      `2015` = formatter("span", style = "font-weight: bold;"),
      `2016` = formatter("span", style = "font-weight: bold;")
    )
  )

#Rename borough_id
final_bll_wide <- formatted_bll_wide %>%
  rename(Borough = borough_id)

final_bll_wide
Borough 2013 2014 2015 2016
Bronx 20.1 18.7 15.7 15.0
Brooklyn 30.2 26.8 22.6 22.3
Manhattan 15.2 14.1 10.6 8.1
Queens 18.2 18.5 15.4 14.3
Staten Island 17.6 17.1 12.0 14.8

Question 12

Starting with the data frame bll_nyc_per_1000 create a table with the DT library showing elevated blood lead levels per 1000 tested in 2013-2016 by borough. Below is an example of the table to replicate.

library (shiny)
## 
## Attaching package: 'shiny'
## The following objects are masked from 'package:DT':
## 
##     dataTableOutput, renderDataTable
#rename columns
bll_clean <- bll_nyc_per_1000 %>%
  rename(Borough = borough_id, Year = time_period, 'BLL > 5' = bll_5plus_1k)

# Use DT to create table
datatable(bll_clean, options = list(pageLength = 10, autoWidth = TRUE), rownames = FALSE) %>%
 htmlwidgets::prependContent(
    tags$h3(style = "text-align: center;", "New York City: Elevated Blood Lead Levels 2013-2016 by Borough")
  )

New York City: Elevated Blood Lead Levels 2013-2016 by Borough

Part 4

Question 13

For this question, we will use suicide rates data that comes from the CDC.

Replicate the graph below using plotly.

# issues with formattable and plotly together since the "style" option overlap
# https://stackoverflow.com/questions/39319427/using-formattable-and-plotly-simultaneously
#detach("package:formattable", unload=TRUE)

library(plotly)
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:formattable':
## 
##     style
## 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
library (dplyr)
df_suicide <- read_csv("data/Suicide Mortality by State.csv")
## Rows: 300 Columns: 6
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): STATE, NAME, URL
## dbl (2): YEAR, RATE
## num (1): DEATHS
## 
## ℹ 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.
# Define the line patterns for states
line_patterns <- c(
  "AZ" = "solid",
  "CA" = "dash",
  "FL" = "dot",
  "HI" = "dashdot",
  "MI" = "shortdash",
  "NY" = "longdashdot",
  "WY" = "dash"
)

# Add the line pattern as a column to the dataset
filter_suicide <- df_suicide %>%
  filter(STATE %in% c("AZ", "CA", "FL", "HI", "MI", "NY", "WY")) %>%
  mutate(dash_pattern = line_patterns[STATE])


plot <- plot_ly(
  filter_suicide,
  x = ~YEAR,
  y = ~RATE,
  type = 'scatter',
  mode = 'lines',
  color = ~STATE,   # Different color for each state
  line = list(dash = ~dash_pattern) # Use the dash pattern column 
) %>%
  layout(
    title = "Suicide Rates by State Over Time",
    xaxis = list(title = ""),
    yaxis = list(title = "Suicide Rate per 100,000")
  )

plot

Question 14

Create an interactive (choropleth) map with plotly similar to the one presented on the CDC website. On the CDC map you can hover over each state and see the state name in bold, the death rate, and deaths. We can do much of this with plotly. As a challenge, use only the 2018 data to create an interactive US map colored by the suicide rates of that state. When you hover over the state, you should see the state name in bold, the death rate, and the number of deaths.

Some key search terms that may help:

  • choropleth
  • hover text plotly r
  • hover text bold plotly r
  • plotly and html
  • html bold
  • html subtitle

Below is an image of an example final map when you hover over California.

Here is the shell of the map to get you started. Copy the plotly code into the chunk below this one and customize it.

# data pulled from CDC website described above 
df_suicide <- read_csv("data/Suicide Mortality by State.csv") %>%
  filter(YEAR == 2018)

plot_ly(df_suicide,
        type="choropleth",
        locationmode = "USA-states") %>%
  layout(geo=list(scope="usa")) 
# Data pulled from CDC website described above
df_suicide <- read_csv("data/Suicide Mortality by State.csv") %>%
  filter(YEAR == 2018) %>%
  mutate(hover_text = paste("<b>", NAME, "</b><br>",
                            "Death Rate: ", RATE, "<br>",
                            "Deaths: ", DEATHS))


plot_ly(df_suicide,
        type = "choropleth",
        locationmode = "USA-states",
        locations = df_suicide$STATE,  
        z = df_suicide$RATE,  # Set the variable for coloring
        text = df_suicide$hover_text,  # Set the hover text
        hoverinfo = "text",  
        colorscale = "Viridis",  
        colorbar = list(title = "Rate",
          tickvals = seq(0, max(df_suicide$RATE), by = 5),  
          ticktext = seq(0, max(df_suicide$RATE), by = 5),
          len = 0.5  #shrink colorbar
         )) %>%
  layout(
    geo = list(
      scope = "usa",  # Limit map to USA
      projection = list(type = "albers usa"),  # Set projection style
      showlakes = TRUE, 
      lakecolor = "rgb(255, 255, 255)"  # Set lake color to white
    ),
    title = "Suicide Mortality by State in 2018",
      annotations = list(
      text = "The number of deaths per 100,000 total population",  # Subtitle text
      x = 0.52,  # Positioning in the middle
      y = 1.02,  # Adjust vertical position
      showarrow = FALSE,
      font = list(size = 12)
    ),
    showlegend = FALSE
  )