In this lab, we will explore and visualize the data using the tidyverse suite of packages, and perform statistical inference using infer. The data can be found in the companion package for OpenIntro resources, openintro.
Let’s load the packages.
library(tidyverse)
library(openintro)
library(infer)
Every two years, the Centers for Disease Control and Prevention conduct the Youth Risk Behavior Surveillance System (YRBSS) survey, where it takes data from high schoolers (9th through 12th grade), to analyze health patterns. You will work with a selected group of variables from a random sample of observations during one of the years the YRBSS was conducted.
Load the yrbss
data set into your workspace.
data('yrbss', package='openintro')
There are observations on 13 different variables, some categorical and some numerical. The meaning of each variable can be found by bringing up the help file:
?yrbss
ls(yrbss)
## [1] "age" "gender"
## [3] "grade" "height"
## [5] "helmet_12m" "hispanic"
## [7] "hours_tv_per_school_day" "physically_active_7d"
## [9] "race" "school_night_hours_sleep"
## [11] "strength_training_7d" "text_while_driving_30d"
## [13] "weight"
The cases in this set are listed via ls(yrbss). There are 13,583 cases in this dataset
Remember that you can answer this question by viewing the data in the data viewer or by using the following command:
glimpse(yrbss)
## Rows: 13,583
## Columns: 13
## $ age <int> 14, 14, 15, 15, 15, 15, 15, 14, 15, 15, 15...
## $ gender <chr> "female", "female", "female", "female", "f...
## $ grade <chr> "9", "9", "9", "9", "9", "9", "9", "9", "9...
## $ hispanic <chr> "not", "not", "hispanic", "not", "not", "n...
## $ race <chr> "Black or African American", "Black or Afr...
## $ height <dbl> NA, NA, 1.73, 1.60, 1.50, 1.57, 1.65, 1.88...
## $ weight <dbl> NA, NA, 84.37, 55.79, 46.72, 67.13, 131.54...
## $ helmet_12m <chr> "never", "never", "never", "never", "did n...
## $ text_while_driving_30d <chr> "0", NA, "30", "0", "did not drive", "did ...
## $ physically_active_7d <int> 4, 2, 7, 0, 2, 1, 4, 4, 5, 0, 0, 0, 4, 7, ...
## $ hours_tv_per_school_day <chr> "5+", "5+", "5+", "2", "3", "5+", "5+", "5...
## $ strength_training_7d <int> 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 3, 0, 0, 7, ...
## $ school_night_hours_sleep <chr> "8", "6", "<5", "6", "9", "8", "9", "6", "...
You will first start with analyzing the weight of the participants in kilograms: weight
.
Using visualization and summary statistics, describe the distribution of weights. The summary
function can be useful.
summary(yrbss$weight)
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 29.94 56.25 64.41 67.91 76.20 180.99 1004
sum(is.na(yrbss))
## [1] 9476
Next, consider the possible relationship between a high schooler’s weight and their physical activity. Plotting the data is a useful first step because it helps us quickly visualize trends, identify strong associations, and develop research questions.
First, let’s create a new variable physical_3plus
, which will be coded as either “yes” if they are physically active for at least 3 days a week, and “no” if not.
yrbss <- yrbss %>%
mutate(physical_3plus = ifelse(yrbss$physically_active_7d > 2, "yes", "no"))
physical_3plus
and weight
. Is there a relationship between these two variables? What did you expect and why?Yes, there is a relationship between physical activity and weight. We see that the weights are pretty similar, but there is a higher concentration of weight measures clustered together for those who exercise than those who don’t. For those that don’t exercise, we see more outliers in weight. The data is more normally distribured for those who exercise than for those who don’t, but both sets of data appear to be normally distributed.
yrbss_plot <- yrbss %>%
mutate(physical_3plus = ifelse(yrbss$physically_active_7d > 2, "yes", "no")) %>%
na.exclude()
ggplot(yrbss_plot, aes(x=weight, y=physical_3plus)) + geom_boxplot() + theme_bw()
The box plots show how the medians of the two distributions compare, but we can also compare the means of the distributions using the following to first group the data by the physical_3plus
variable, and then calculate the mean weight
in these groups using the mean
function while ignoring missing values by setting the na.rm
argument to TRUE
.
yrbss %>%
group_by(physical_3plus) %>%
summarise(mean_weight = mean(weight, na.rm = TRUE))
## # A tibble: 3 x 2
## physical_3plus mean_weight
## <chr> <dbl>
## 1 no 66.7
## 2 yes 68.4
## 3 <NA> 69.9
There is an observed difference, but is this difference statistically significant? In order to answer this question we will conduct a hypothesis test.
summarize
command above by defining a new variable with the definition n()
.The two conditions for inference are normality and independence. According to the data, we can see that it is a representative sample of many students across national, state,and tribal territories. All students are independent of each other. According to the box plots above, we can also see that the data appears to be normally distributed.
yrbss %>%
group_by(physical_3plus) %>%
summarise(freq = table(weight)) %>%
summarise(n = sum(freq))
## # A tibble: 3 x 2
## physical_3plus n
## <chr> <int>
## 1 no 4022
## 2 yes 8342
## 3 <NA> 215
H0: Students who are physically active 3 or more days per week have the same average weight as those who are not physically active 3 or more days per week. HA: Students who are physically active 3 or more days per week have a different average weight than those who don’t exercise 3x/wk.
Next, we will introduce a new function, hypothesize
, that falls into the infer
workflow. You will use this method for conducting hypothesis tests.
But first, we need to initialize the test, which we will save as obs_diff
.
obs_diff <- yrbss %>%
specify(weight ~ physical_3plus) %>%
calculate(stat = "diff in means", order = c("yes", "no"))
Notice how you can use the functions specify
and calculate
again like you did for calculating confidence intervals. Here, though, the statistic you are searching for is the difference in means, with the order being yes - no != 0
.
After you have initialized the test, you need to simulate the test on the null distribution, which we will save as null
.
set.seed(999)
null_dist <- yrbss %>%
specify(weight ~ physical_3plus) %>%
hypothesize(null = "independence") %>%
generate(reps = 1000, type = "permute") %>%
calculate(stat = "diff in means", order = c("yes", "no"))
Here, hypothesize
is used to set the null hypothesis as a test for independence. In one sample cases, the null
argument can be set to “point” to test a hypothesis relative to a point estimate.
Also, note that the type
argument within generate
is set to permute
, whichis the argument when generating a null distribution for a hypothesis test.
We can visualize this null distribution with the following code:
ggplot(data = null_dist, aes(x = stat)) +
geom_histogram()
null
permutations have a difference of at least obs_stat
?visualize(null_dist) +
shade_p_value(obs_stat = obs_diff, direction = "two_sided")
Now that the test is initialized and the null distribution formed, you can calculate the p-value for your hypothesis test using the function get_p_value
.
null_dist %>%
get_p_value(obs_stat = obs_diff, direction = "two_sided")
## # A tibble: 1 x 1
## p_value
## <dbl>
## 1 0
This the standard workflow for performing hypothesis tests.
'Standard Deviation'
## [1] "Standard Deviation"
yrbss %>%
group_by(physical_3plus) %>%
summarise(sd_weight = sd(weight, na.rm = TRUE))
## # A tibble: 3 x 2
## physical_3plus sd_weight
## <chr> <dbl>
## 1 no 17.6
## 2 yes 16.5
## 3 <NA> 17.6
'Mean'
## [1] "Mean"
yrbss %>%
group_by(physical_3plus) %>%
summarise(mean_weight = mean(weight, na.rm = TRUE))
## # A tibble: 3 x 2
## physical_3plus mean_weight
## <chr> <dbl>
## 1 no 66.7
## 2 yes 68.4
## 3 <NA> 69.9
'Sample size: N'
## [1] "Sample size: N"
yrbss %>%
group_by(physical_3plus) %>%
summarise(freq = table(weight)) %>%
summarise(n = sum(freq))
## # A tibble: 3 x 2
## physical_3plus n
## <chr> <int>
## 1 no 4022
## 2 yes 8342
## 3 <NA> 215
mean_not_active <- 66.67389
n_not_active <- 4022
sd_not_active <- 17.63805
mean_active <- 68.44847
n_active <- 8342
sd_active <- 16.47832
z = 1.96
#CI for those not active
upper_ci_not_act <- mean_not_active + z*(sd_not_active/sqrt(n_not_active))
lower_ci_not_act <- mean_not_active - z*(sd_not_active/sqrt(n_not_active))
#CI for those active
upper_ci_act <- mean_active + z*(sd_active/sqrt(n_active))
lower_ci_act <- mean_active - z*(sd_active/sqrt(n_active))
c("Those not active:", lower_ci_not_act, upper_ci_not_act)
## [1] "Those not active:" "66.1287781694363" "67.2190018305637"
c("Those active:", lower_ci_act, upper_ci_act)
## [1] "Those active:" "68.0948523684916" "68.8020876315084"
height
) and interpret it in context.From a 95% CI, we can say the average height of the students of the population is between 1.689m and 1.693m.
tb <- as.data.frame(table(yrbss$height))
freq <- sum(tb$Freq)
mean_height <- mean(yrbss$height, na.rm = TRUE)
sd_height <- sd(yrbss$height, na.rm = TRUE)
sample_height <- yrbss %>%
summarise(freq = table(height)) %>%
summarise(n = sum(freq, na.rm = TRUE))
height_upper <- mean_height + z*(sd_height/sqrt(sample_height))
height_lower <- mean_height - z*(sd_height/sqrt(sample_height))
c(height_lower,height_upper)
## $n
## [1] 1.689411
##
## $n
## [1] 1.693071
*** 9. Calculate a new confidence interval for the same parameter at the 90% confidence level. Comment on the width of this interval versus the one obtained in the previous exercise.
Greater lower-bound value yet smaller upper bound value for CI at 90% confidence level. Taking the difference of the two confidence intervals from 90% and 95%, we see they have the same difference from each other. Therefore, the width of these two intervals is the same.
z2 <- 1.645
height_upper_2 <- mean_height + z2*(sd_height/sqrt(sample_height))
height_lower_2 <- mean_height - z2*(sd_height/sqrt(sample_height))
c(height_lower_2 ,height_upper_2)
## $n
## [1] 1.689705
##
## $n
## [1] 1.692777
Difference between both CI’s:
x <- abs(height_lower_2 - height_lower)
y <- abs(height_upper_2 - height_upper)
c(x,y)
## $n
## [1] 0.0002940511
##
## $n
## [1] 0.0002940511
HO: There is no difference in average height of those who are physically active at least 3 days per week, and those who aren’t. HA: There is a difference…
obs_diff_hgt <- yrbss %>%
specify(height ~ physical_3plus) %>%
calculate(stat = "diff in means", order = c("yes", "no"))
set.seed(45698)
null_dist_hgt <- yrbss %>%
specify(height ~ physical_3plus) %>%
hypothesize(null = "independence") %>%
generate(reps = 1000, type = "permute") %>%
calculate(stat = "diff in means", order = c("yes", "no"))
visualize(null_dist_hgt) +
shade_p_value(obs_stat = obs_diff_hgt, direction = "two_sided")
null_dist_hgt %>%
get_p_value(obs_stat = obs_diff_hgt, direction = "two_sided")
## # A tibble: 1 x 1
## p_value
## <dbl>
## 1 0
# Non active
mean_height_2 <- 1.6665
samples_2 <- 4022
sd_height_2 <- 0.1029
# Active
mean_height_2a <- 1.7032
samples_2a <- 8342
sd_height_2a <- 0.1033
z_2 = 1.96
#Non Active
upper_non_active <- mean_height_2 + z*(sd_height_2/sqrt(samples_2))
lower_non_active <- mean_height_2 - z*(sd_height_2/sqrt(samples_2))
c("Non-active heights:", lower_non_active, upper_non_active)
## [1] "Non-active heights:" "1.66331982943891" "1.66968017056109"
#Active
upper_active <- mean_height_2a + z*(sd_height_2a/sqrt(samples_2a))
lower_active <- mean_height_2a - z*(sd_height_2a/sqrt(samples_2a))
c("Active heights:", lower_active, upper_active)
## [1] "Active heights:" "1.70098322660715" "1.70541677339285"
With a confidence level of 95%, the average height of students who are physically active at least 3 days/week, is between ~1.701m and 1.705m. The average height of students who are not physically active is between ~1.663m and ~1.670m.
Because the p-value is less than 0.05, we reject the null hypothesis. Thus, there is a difference of those who are physically active at least 3x/week.
hours_tv_per_school_day
there are.There are 7 options for this survey
yrbss %>%group_by(hours_tv_per_school_day)%>% summarise(n())
## # A tibble: 8 x 2
## hours_tv_per_school_day `n()`
## <chr> <int>
## 1 <1 2168
## 2 1 1750
## 3 2 2705
## 4 3 2139
## 5 4 1048
## 6 5+ 1595
## 7 do not watch 1840
## 8 <NA> 338
Q: Is there evidence that students who are heavier than the mean weight sleep more than students who weight less than the mean weight?
HO: There is a relationship between weight and sleep
HA: There is no relationship between weight and sleep
95% confident level
Conditions:
-Independent sample-yes - Normality - yes
Results:
Because our P-value is equal to our alpha, 0.05, we cannot reject the null hypothesis. Therefore, we cannot determine there exists a relationship between weight and sleep.
yrbss <- yrbss %>%
mutate(sleep_less = ifelse(yrbss$school_night_hours_sleep < 6, "yes", "no"))
weight_less <- yrbss %>%
select(weight, sleep_less) %>%
filter(sleep_less == "yes") %>%
na.omit()
weight_more <- yrbss %>%
select(weight, sleep_less) %>%
filter(sleep_less == "no") %>%
na.omit()
boxplot(weight_less$weight, weight_more$weight,
names = c("less_sleep", "more_sleep"))
mn <- mean(weight_less$weight)
sd <- sd(weight_less$weight)
max <- max(weight_less$weight)
max
## [1] 180.99
mn1 <- mean(weight_more$weight)
sd2 <- sd(weight_more$weight)
max2 <- max(weight_more$weight)
mean_diff <- mn1 - mn
sd <-
sqrt(
((mn1^2) / nrow(weight_more)) +
((mn^2) / nrow(weight_less))
)
df <- 2492-1
t <- qt(.05/2, df, lower.tail = FALSE)
upper_ci <- mean_diff + t * sd
lower_ci <- mean_diff - t * sd
c(lower_ci ,upper_ci)
## [1] -4.666506 1.442799
p_value <- 2*pt(t,df, lower.tail = FALSE)
p_value
## [1] 0.05