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)
library(statsr)
## Warning: package 'statsr' was built under R version 4.0.3
library(psych)
set.seed(12548)
To create your new lab report, in RStudio, go to New File -> R Markdown… Then, choose From Template and then choose Lab Report for OpenIntro Statistics Labs
from the list of templates.
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)
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
## starting httpd help server ... done
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", "...
There at 13,583 rows which is also the number of cases in this sample. There are 13 cases in this data set ## Exploratory data analysis
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
`` 2. How many observations are we missing weights from?
sum(is.na(yrbss))
## [1] 9476
There are 9,476 missing values.
Under the observations of weights we have 1004 missing values.
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?yrbss2 <- yrbss %>%
mutate(physical_3plus = ifelse(yrbss$physically_active_7d > 2, "yes", "no")) %>%
na.exclude()
ggplot(yrbss2, aes(x=weight, y=physical_3plus)) + geom_boxplot() + theme_bw()
The relationship between a student’s weight and if they are physically active at least 3 times per week seems to show that those who are not physically active at least 3 times per week weigh less than those who are physically active at least 3 times per week. This is interesting as I would have expected those who were physically active at least 3 times per week to weigh less than those who were not physically active at least 3 times per week. These results are quite contarary to the way things are assume that people who exercise would weigh less.
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))
## `summarise()` ungrouping output (override with `.groups` argument)
## # 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()
. There are two conditions - independence and normality. Based on the information the data is a representative sample of many students across national, state, tribal, and local school systems and is independent. The sample size and distribution of the boxplots would help us verify normality. We can assume With a sample size well over 1000 and no particularly outliers that the condition is satisfied.yrbss %>%
group_by(physical_3plus) %>%
summarise(freq = table(weight)) %>%
summarise(n = sum(freq))
## `summarise()` regrouping output by 'physical_3plus' (override with `.groups` argument)
## `summarise()` ungrouping output (override with `.groups` argument)
## # 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 when compared to those who are not physically active 3 or more days per week.
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(5487954)
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
, which is 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()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
null
permutations have a difference of at least obs_stat
? The result is a very small number, close to zero.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")
## Warning: Please be cautious in reporting a p-value of 0. This result is an
## approximation based on the number of `reps` chosen in the `generate()` step. See
## `?get_p_value()` for more information.
## # A tibble: 1 x 1
## p_value
## <dbl>
## 1 0
This the standard workflow for performing hypothesis tests.
yrbss %>%
group_by(physical_3plus) %>%
summarise(sd_weight = sd(weight, na.rm = TRUE))
## `summarise()` ungrouping output (override with `.groups` argument)
## # A tibble: 3 x 2
## physical_3plus sd_weight
## <chr> <dbl>
## 1 no 17.6
## 2 yes 16.5
## 3 <NA> 17.6
The sd is 17.638 for those who do are not physically active at least 3 days per week and 16.478 for those who are.
#means of the weights
yrbss %>%
group_by(physical_3plus) %>%
summarise(mean_weight = mean(weight, na.rm = TRUE))
## `summarise()` ungrouping output (override with `.groups` argument)
## # 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 for each category
yrbss %>%
group_by(physical_3plus) %>%
summarise(freq = table(weight)) %>%
summarise(n = sum(freq))
## `summarise()` regrouping output by 'physical_3plus' (override with `.groups` argument)
## `summarise()` ungrouping output (override with `.groups` argument)
## # A tibble: 3 x 2
## physical_3plus n
## <chr> <int>
## 1 no 4022
## 2 yes 8342
## 3 <NA> 215
xnot3 <- 66.67389
nnot3 <- 4022
snot3 <- 17.63805
x3 <- 68.44847
n3 <- 8342
s3 <- 16.47832
z = 1.96
uci_not <- xnot3 + z*(snot3/sqrt(nnot3))
lci_not <- xnot3 - z*(snot3/sqrt(nnot3))
uci_not
## [1] 67.219
lci_not
## [1] 66.12878
u_ci <- x3 + z*(s3/sqrt(n3))
l_ci <- x3 - z*(s3/sqrt(n3))
u_ci
## [1] 68.80209
l_ci
## [1] 68.09485
With 95% confident that students who exercise at least three times a week have an average weight between 68.09 kg and 68.8 kg. Also those students who do not exercise at least three times a week have an average weight between 66.13 kg and 67.22 kg with 95% confident. * * *
height
) and interpret it in context.tb <- as.data.frame(table(yrbss$height))
freq <- sum(tb$Freq)
x_h <- mean(yrbss$height, na.rm = TRUE)
sd_h <- sd(yrbss$height, na.rm = TRUE)
n_h <- yrbss %>%
summarise(freq = table(height)) %>%
summarise(n = sum(freq, na.rm = TRUE))
u_h <- x_h + z*(sd_h/sqrt(n_h))
l_h <- x_h - z*(sd_h/sqrt(n_h))
u_h
## n
## 1 1.693071
l_h
## n
## 1 1.689411
With 95% confident that the average height of the students in this population is between 1.689m and 1.693m.
t1 <- 1.645
uh1 <- x_h + t1*(sd_h/sqrt(n_h))
lh1 <- x_h - t1*(sd_h/sqrt(n_h))
uh1
## n
## 1 1.692777
lh1
## n
## 1 1.689705
The new confidence interval is 1.689705 to 1.692777. Our intervals at a 95% confidence level were 1.689411 and 1.693071. We can find a slight difference in these two confidence intervals.
r_95 <- (u_h - l_h)
r_90 <- (uh1 - lh1)
r_95
## n
## 1 0.003659302
r_90
## n
## 1 0.0030712
Also the 95% confidence interval has a slightly larger range than the confidence interval 90%.
HA: There is a difference in the average height of those who are physically active at least 3 days per week and those who are not.
obs_diff_hgt <- yrbss %>%
specify(height ~ physical_3plus) %>%
calculate(stat = "diff in means", order = c("yes", "no"))
## Warning: Removed 1219 rows containing missing values.
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"))
## Warning: Removed 1219 rows containing missing values.
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")
## Warning: Please be cautious in reporting a p-value of 0. This result is an
## approximation based on the number of `reps` chosen in the `generate()` step. See
## `?get_p_value()` for more information.
## # A tibble: 1 x 1
## p_value
## <dbl>
## 1 0
Because p-value is very small, smaller than 0.05, we should reject the null hypothesis.
x_t <- 1.6665
n_t <- 4022
s_t <- 0.1029
x_yt <- 1.7032
n_yt <- 8342
s_yt <- 0.1033
z = 1.96
ut <- x_t + z*(s_t/sqrt(n_t))
lt <- x_t - z*(s_t/sqrt(n_t))
ut
## [1] 1.66968
lt
## [1] 1.66332
uyt <- x_yt + z*(s_yt/sqrt(n_yt))
lyt <- x_yt - z*(s_yt/sqrt(n_yt))
uyt
## [1] 1.705417
lyt
## [1] 1.700983
With 95% confident that the average height of students who are physically active at least 3 days per week is between 1.705 and 1.701 and the average height of students who are not physically active at least 3 days per week is between 1.670 and 1.663.
hours_tv_per_school_day
there are.yrbss %>%group_by(hours_tv_per_school_day)%>% summarise(n())
## `summarise()` ungrouping output (override with `.groups` argument)
## # 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
There are 7 different options, plus NA
Q: Is there evidence that students who are shorter than the mean height sleep less than students who are taller than the mean height?
HO: There is no relationship between the mean height and sleep bewteen students.
95% confident level
Conditions:
-Independent sample-yes - Normality - yes
results - The P-value of > 0.05 the null hypothesis must be rejected but it could lead to Type 1 error.
yrbss <- yrbss %>%
mutate(sleep_less = ifelse(yrbss$school_night_hours_sleep < 6, "yes", "no"))
height_less <- yrbss %>%
select(height, sleep_less) %>%
filter(sleep_less == "no") %>%
na.omit()
height_more <- yrbss %>%
select(height, sleep_less) %>%
filter(sleep_less == "yes") %>%
na.omit()
boxplot(height_less$height, height_more$height,
names = c("less_sleep", "more_sleep"))
mn <- mean(height_less$height)
sd <- sd(height_less$height)
max <- max(height_less$height)
mn1 <- mean(height_more$height)
sd2 <- sd(height_more$height)
max2 <- max(height_more$height)
meandiff <- mn1 - mn
sd <-
sqrt(
((mn1^2) / nrow(height_more)) +
((mn^2) / nrow(height_less))
)
df <- 2492-1
t <- qt(.05/2, df, lower.tail = FALSE)
u<- meandiff + t * sd
l<- meandiff - t * sd
u
## [1] 0.06780798
l
## [1] -0.08195098
pv <- 2*pt(t,df, lower.tail = FALSE)
pv
## [1] 0.05
the null hypothes can be rejected because p-value is 0.05