The exercises are part of the Fundamentals of R course. For more, see the R for the Rest of Us website.
Load the tidyverse
and janitor
packages.
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
## ✔ ggplot2 3.1.1 ✔ purrr 0.3.2
## ✔ tibble 2.1.1 ✔ dplyr 0.8.0.1
## ✔ tidyr 0.8.3.9000 ✔ stringr 1.4.0
## ✔ readr 1.3.1 ✔ forcats 0.4.0
## ── Conflicts ────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
library(janitor)
Import the NHANES data to a data frame called nhanes
. Then, use the clean_names
function to create clean names for all of your variables.
nhanes <- read_csv("data/nhanes.csv") %>%
clean_names()
## Parsed with column specification:
## cols(
## .default = col_character(),
## ID = col_double(),
## Age = col_double(),
## Weight = col_double(),
## Height = col_double(),
## BMI = col_double(),
## DaysPhysHlthBad = col_double(),
## DaysMentHlthBad = col_double(),
## SleepHrsNight = col_double(),
## PhysActiveDays = col_double(),
## TVHrsDay = col_logical()
## )
## See spec(...) for full column specifications.
## Warning: 4859 parsing failures.
## row col expected actual file
## 5001 TVHrsDay 1/0/T/F/TRUE/FALSE 2_hr 'data/nhanes.csv'
## 5002 TVHrsDay 1/0/T/F/TRUE/FALSE More_4_hr 'data/nhanes.csv'
## 5003 TVHrsDay 1/0/T/F/TRUE/FALSE 4_hr 'data/nhanes.csv'
## 5004 TVHrsDay 1/0/T/F/TRUE/FALSE 4_hr 'data/nhanes.csv'
## 5005 TVHrsDay 1/0/T/F/TRUE/FALSE 1_hr 'data/nhanes.csv'
## .... ........ .................. ......... .................
## See problems(...) for more details.
With select
we can select variables from the larger data frame.
Use select
to show just the marital_status
variable.
nhanes %>%
select(marital_status)
We can also use select
for multiple variables.
Use select
to show marital_status
and education
.
nhanes %>%
select(marital_status, education)
Used within select
, the contains
function selects variable with certain text in the variable name.
Use the contains
function to select variables that ask how many days in the last 30 days the respondent had bad physical and mental health (you should be able to figure out which variables these are from the names).
nhanes %>%
select(contains("hlth_bad"))
Used within select
, the starts_with
function selects variable with certain text in the variable name.
Use the starts_with
function to select variables that start with the letter h.
nhanes %>%
select(starts_with("h"))
We can select
a range of columns using the var1:var2 pattern. select
all the variables from health_gen
to the end.
nhanes %>%
select(health_gen:smoke_now)
We can drop variables using the -var format. Drop the education
variable.
nhanes %>%
select(-education)
We can drop a set of variables using the -(var1:var2) format. Drop the variables from health_gen
to the end.
nhanes %>%
select(-(health_gen:smoke_now))
We use mutate
we make new variables or change existing ones.
Create a new variable with a specific value
Create a new variable called completed_survey
and make all responses to it “Yes”.
nhanes %>%
mutate(completed_survey = "Yes")
Copy your code from above and then add a line where you select only the completed_survey
variable. Don’t forget the pipe (%>%)!
nhanes %>%
mutate(completed_survey = "Yes") %>%
select(completed_survey)
Create a new variable based on other variables
Create a new variable called pct_days_phys_health_bad
and calculate it as the percentage of self-reported days of bad physical health in the last 30 days. Remember that the days_phys_hlth_bad
variable is a measure of the number of self-reported days of bad physical health in the last 30 days. Then, use select
to show the days_phys_hlth_bad
and pct_days_phys_health_bad
variables.
nhanes %>%
mutate(pct_days_phys_health_bad = days_phys_hlth_bad / 30) %>%
select(days_phys_hlth_bad, pct_days_phys_health_bad)
Change an existing variable
Round the height
variable to a whole number. Then, use select
to show only the height
variable.
nhanes %>%
mutate(height = round(height, digits = 0)) %>%
select(height)
We use filter
to choose a subset of cases.
Use filter
to keep only respondents who are divorced. Then, use select
to show only the marital_status
variable.
nhanes %>%
filter(marital_status == "Divorced") %>%
select(marital_status)
Use filter
to keep only respondents who are not divorced. Then, use select
to show only the marital_status
variable.
nhanes %>%
filter(marital_status != "Divorced") %>%
select(marital_status)
Use filter
to keep only respondents who are divorced or separated. Then, use select
to show only the marital_status
variable.
nhanes %>%
filter(marital_status == "Divorced" | marital_status == "Separated") %>%
select(marital_status)
Use %in%
within the filter
function to keep only those who are divorced, separated, or widowed. Then, use select
to show only the marital_status
variable.
nhanes %>%
filter(marital_status %in% c("Divorced", "Separated", "Widowed")) %>%
select(marital_status)
We can chain together multiple filter
functions. Doing it this way, we don’t have create complex logic in one line.
Create a chain that keeps only those are college grads (line #1). Then, filter
to keep only those who are divorced, separated, or widowed. Finally, use select
to show only the education
and marital_status
variables.
nhanes %>%
filter(education == "College Grad") %>%
filter(marital_status %in% c("Divorced", "Separated", "Widowed")) %>%
select(education, marital_status)
We can use Use <
, >
, <=
, and =>
for numeric data.
Use filter
to only show those reported at least 5 days of physical activity in the last 30 days (this is the phys_active_days
variable). Then, use select
to keep only the phys_active_days
and the days_phys_hlth_bad
variables.
nhanes %>%
filter(phys_active_days >= 5) %>%
select(phys_active_days, days_phys_hlth_bad)
We can drop NAs
with !is.na
Do the same thing as above, but drop responses that don’t have a response for days_phys_hlth_bad
. Then, use select
to keep only the phys_active_days
and the days_phys_hlth_bad
variables.
nhanes %>%
filter(phys_active_days >= 5) %>%
filter(!is.na(days_phys_hlth_bad)) %>%
select(phys_active_days, days_phys_hlth_bad)
You can also drop NAs
with drop_na
Do the same thing as above, but use drop_na
instead of !is.na
. Make sure you get the same result!
nhanes %>%
filter(phys_active_days >= 5) %>%
drop_na(days_phys_hlth_bad) %>%
select(phys_active_days, days_phys_hlth_bad)
With summarize
, we can go from a complete dataset down to a summary.
Get the mean hours of sleep per night that respondents say they get.
nhanes %>%
summarize(mean_hours_sleep = mean(sleep_hrs_night, na.rm = TRUE))
We can have multiple arguments in each usage of summarize
.
In addition to calculating the mean hours of sleep per night, calculate the number of responses.
nhanes %>%
summarize(mean_hours_sleep = mean(sleep_hrs_night, na.rm = TRUE),
number_of_responses = n())
summarize
becomes truly powerful when paired with group_by
, which enables us to perform calculations on each group.
Calculate the mean hours of sleep for females and males using group_by
and summarize
.
nhanes %>%
group_by(gender) %>%
summarize(mean_hours_sleep = mean(sleep_hrs_night, na.rm = TRUE))
We can use group_by
with multiple groups.
Use group_by
for gender
and work
(whether or not respondents are working) before calculating mean hours of sleep.
nhanes %>%
group_by(gender, work) %>%
summarize(mean_hours_sleep = mean(sleep_hrs_night, na.rm = TRUE),
number_of_observations = n())
If we just want to count the number of things per group, we can use count
.
Use count
to show the number of responses by highest level of education completed (education
).
nhanes %>%
count(education)
We can also count by multiple groups.
Use count
to show the number of responses for education
and phys_active
.
nhanes %>%
count(education, phys_active)
With arrange
, we can reorder rows in a data frame based on the values of one or more variables. R arranges in ascending order by default.
Use count
to show the number of responses by education level. Then, use arrange
to order by the number of responses.
nhanes %>%
count(education) %>%
arrange(n)
We can also arrange in descending order using desc
.
Do the same thing as above, but put it in descending order using desc
.
nhanes %>%
count(education) %>%
arrange(desc(n))
We often use arrange
at the end of chains to display things in order.
Create a chain that does the following:
filter
to only include those age 30 or oldergroup_by
to create a male and female groupsummarize
to calculate a new variable called mean_bad_mental_health_days
for males and femalesmutate
to round mean_bad_mental_health_days
to one decimal placearrange
to put mean_bad_mental_health_days
in descending ordernhanes %>%
filter(age >= 30) %>%
group_by(gender) %>%
summarize(mean_bad_mental_health_days = mean(days_ment_hlth_bad, na.rm = TRUE)) %>%
mutate(mean_bad_mental_health_days = round(mean_bad_mental_health_days, digits = 1)) %>%
arrange(desc(mean_bad_mental_health_days))
Sometimes you want to save the results of your work to a new data frame.
Copy the code above and save it to a new data frame called mental_health_over_30
.
mental_health_over_30 <- nhanes %>%
filter(age >= 30) %>%
group_by(gender) %>%
summarize(mean_bad_mental_health_days = mean(days_ment_hlth_bad, na.rm = TRUE)) %>%
mutate(mean_bad_mental_health_days = round(mean_bad_mental_health_days, digits = 1)) %>%
arrange(desc(mean_bad_mental_health_days))
Sometimes you want your results in a crosstab. We can use the tabyl
function in janitor
package to make crosstabs automatically.
Create a crosstab of gender
and health_gen
.
nhanes %>%
tabyl(gender, health_gen)
Add a drop_na
before your line with tabyl
to get rid of all NAs.
nhanes %>%
drop_na(gender, health_gen) %>%
tabyl(gender, health_gen)
janitor
has a set of functions that all start with adorn_
that add a number of things to our crosstabs. We call them after tabyl
. For example, adorn_totals
.
Use the code above and then add totals using adorn_totals
in the rows and columns.
nhanes %>%
drop_na(gender, health_gen) %>%
tabyl(gender, health_gen) %>%
adorn_totals(where = c("row", "col"))
We can add adorn_percentages
to add percentages.
Use the code above and then add percentages using adorn_percentages
.
nhanes %>%
drop_na(gender, health_gen) %>%
tabyl(gender, health_gen) %>%
adorn_totals(where = c("row", "col")) %>%
adorn_percentages()
We can then format these percentages using adorn_pct_formatting
.
Use the code above and then format the percentages using adorn_pct_formatting
. Add arguments so that the percentages are rounded to 1 digit. Note that R uses the “half to even” rounding method by default so if you want to round, say, 14.5 to 15 you must use the rounding
argument (type ?adorn_pct_formatting in the console to learn more).
nhanes %>%
drop_na(gender, health_gen) %>%
tabyl(gender, health_gen) %>%
adorn_totals(where = c("row", "col")) %>%
adorn_percentages() %>%
adorn_pct_formatting(digits = 1,
rounding = "half up")
If we want to include the n alongside percentages, we can use adorn_ns
.
Use the code above and then add a line with adorn_ns
to include the n.
nhanes %>%
drop_na(gender, health_gen) %>%
tabyl(gender, health_gen) %>%
adorn_totals(c("row", "col")) %>%
adorn_percentages() %>%
adorn_pct_formatting(digits = 1,
rounding = "half up") %>%
adorn_ns()
We can add titles to our crosstabs using adorn_title
.
Use the code above and then add a title using adorn_title
. Use the placement
argument and see what you get.
nhanes %>%
drop_na(gender, health_gen) %>%
tabyl(gender, health_gen) %>%
adorn_totals(c("row", "col")) %>%
adorn_percentages() %>%
adorn_pct_formatting(digits = 0,
rounding = "half up") %>%
adorn_ns() %>%
adorn_title(placement = "combined")
We can also do three (or more) way crosstabs automatically by adding more variables to the tabyl
function.
Use the code above, but add a third variable (age_decade
) to the line with drop_na
and the line with tabyl
. You should get a series of crosstabs.
nhanes %>%
drop_na(gender, health_gen, age_decade) %>%
tabyl(gender, health_gen, age_decade) %>%
adorn_totals(c("row", "col")) %>%
adorn_percentages() %>%
adorn_pct_formatting(digits = 0, rounding = "half up") %>%
adorn_ns() %>%
adorn_title()
## $`10-19`
## health_gen
## gender Excellent Fair Good Poor Vgood Total
## female 9% (46) 9% (47) 44% (223) 1% (4) 37% (190) 100% (510)
## male 17% (94) 7% (40) 33% (181) 1% (3) 42% (233) 100% (551)
## Total 13% (140) 8% (87) 38% (404) 1% (7) 40% (423) 100% (1061)
##
## $`20-29`
## health_gen
## gender Excellent Fair Good Poor Vgood Total
## female 12% (69) 13% (76) 38% (219) 2% (11) 34% (197) 100% (572)
## male 15% (93) 11% (66) 40% (244) 1% (6) 34% (208) 100% (617)
## Total 14% (162) 12% (142) 39% (463) 1% (17) 34% (405) 100% (1189)
##
## $`30-39`
## health_gen
## gender Excellent Fair Good Poor Vgood Total
## female 12% (66) 15% (82) 41% (229) 2% (9) 31% (173) 100% (559)
## male 11% (63) 10% (59) 45% (265) 0% (2) 34% (197) 100% (586)
## Total 11% (129) 12% (141) 43% (494) 1% (11) 32% (370) 100% (1145)
##
## $`40-49`
## health_gen
## gender Excellent Fair Good Poor Vgood Total
## female 12% (68) 13% (76) 41% (240) 2% (12) 33% (192) 100% (588)
## male 11% (69) 17% (108) 42% (275) 2% (10) 29% (190) 100% (652)
## Total 11% (137) 15% (184) 42% (515) 2% (22) 31% (382) 100% (1240)
##
## $`50-59`
## health_gen
## gender Excellent Fair Good Poor Vgood Total
## female 9% (47) 14% (75) 32% (174) 5% (29) 41% (224) 100% (549)
## male 10% (61) 20% (126) 39% (248) 4% (27) 28% (177) 100% (639)
## Total 9% (108) 17% (201) 36% (422) 5% (56) 34% (401) 100% (1188)
##
## $`60-69`
## health_gen
## gender Excellent Fair Good Poor Vgood Total
## female 14% (62) 13% (60) 34% (151) 4% (19) 35% (156) 100% (448)
## male 13% (54) 12% (52) 41% (170) 5% (19) 30% (124) 100% (419)
## Total 13% (116) 13% (112) 37% (321) 4% (38) 32% (280) 100% (867)
##
## $`70+`
## health_gen
## gender Excellent Fair Good Poor Vgood Total
## female 7% (24) 15% (47) 40% (130) 4% (12) 34% (108) 100% (321)
## male 14% (31) 18% (39) 36% (78) 5% (11) 27% (60) 100% (219)
## Total 10% (55) 16% (86) 39% (208) 4% (23) 31% (168) 100% (540)