T-Test ToothGrowth

In short: In this article a t-test is conducted on the dataset ToothGrowth. The test examines whether there is a significant difference in average tooth growth between the two supplement types of Vitamin C (orange juice vs. ascorbic acid) at a dose of 0.5 mg/day. So we would like to check whether the delivery method has an impact on tooth growth at the same dosage.

This article shows an R example on how to conduct a t-test on the dataset ToothGrowth. For general information about t-tests please refer to the following article: T-Test.

The Dataset[edit]

The dataset ToothGrowth is provided in the R base package and contains information on the growth of teeth in guinea pigs and the different types and doses of treatment with vitamin C they received.

The variables we will look at in our analysis are:

  • len: a numeric variable containing the length of cells responsible for the growth of teeth in guinea pigs.
  • supp: a factorial variable indicating the type of vitamin C supplement the guinea pig received (VC for ascorbic acid, OJ for orange juice).
  • dose: a numeric variable containing the dose of vitamin c that was given to the guinea pig. It is saved as a numeric variable but only appears in the values 0.5, 1 and 2.

Inspecting the Dataset[edit]

The command head() displays the first entries of the data frame which provides an initial overview of the data. Set.the command str() display the internal structure of the data.

# Inspect the dataset
head(ToothGrowth)
str(ToothGrowth)

Output[edit]

> head(ToothGrowth)

len supp dose
1  4.2   VC  0.5
2 11.5   VC  0.5
3  7.3   VC  0.5
4  5.8   VC  0.5
5  6.4   VC  0.5
6 10.0   VC  0.5
> str(ToothGrowth)
'data.frame':	60 obs. of  3 variables:
 $ len : num  4.2 11.5 7.3 5.8 6.4 10 11.2 11.2 5.2 7 ...
 $ supp: Factor w/ 2 levels "OJ","VC": 2 2 2 2 2 2 2 2 2 2 ...
 $ dose: num  0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 ...

We can see directly that there are two different supplement groups, indicated by a factor with two levels. We can also see the data types in which the different variables are stored.

Splitting the Values[edit]

# Filter data for dose = 0.5
dose_05 <- subset(ToothGrowth, dose == 0.5)

# Split tooth length by supplement type
len_OJ <- dose_05$len[dose_05$supp == "OJ"]
len_VC <- dose_05$len[dose_05$supp == "VC"]

To perform the t-test, we’ll only use data with the dose 0.5 to have two groups to compare to each other. Therefore, we create a variable that only contains treatments with this dosage. In R, a variable is created by storing the data on the right side of the arrow under the name on the left side of the arrow. So let’s have a closer look at the variable dose_05. The code on the right-hand side translates as: Take the data from the ToothGrowth data set, but only if the value in the dose column is 0.5.

Now we can split this subset into the two different supplement groups. For len_OJ, we only take the values if the supplement is OJ, which stands for orange juice. We proceed similarly with the variable len_VC. Only now the criterion must be met that the supplement is called “VC” in the data.

Checking Assumptions[edit]

Before conducting the t-test we can examine the dataset and check for the different assumptions of a t-test to make sure that it produces valid results. The assumptions of a t-test are:

  • response variable should be continuous or ordinal
  • normal distribution for each factor or a sufficiently large sample size (≥ 30)
  • data must be drawn randomly from a representative sample
  • student’s t-test requires equal variance in the two groups; welch t-test can deal with unequal variance
#check for assumptions
shapiro.test(len_OJ)
shapiro.test(len_VC)

#equal variance between groups 
boxplot(len ~ supp, data = ToothGrowth,
        subset = dose == 0.5)

var.test(len ~ supp, data = ToothGrowth,
         subset = dose == 0.5)

We have already seen that the len values represent continuous data, and it is assumed that the observations were drawn randomly from a representative sample. The remaining assumptions can be tested using the Shapiro–Wilk test and the F-test, and additionally assessed by visual inspection using a boxplot.

The function shapiro.test() is used to examine whether the two groups are normally distributed. The function var.test() is applied to test whether the variances of the two groups are equal. Since the variance should only be tested for observations with a dosage of 0.5, subset = dose == 0.5 is specified in the code. Using a subset is a practical way to restrict the analysis to the relevant data.

Output[edit]

Fig. 1: A boxplot to compare tooth growth distributions
> Shapiro-Wilk normality test

data:  len_OJ
W = 0.89274, p-value = 0.182

> shapiro.test(len_VC)

	Shapiro-Wilk normality test

data:  len_VC
W = 0.89, p-value = 0.1696

> #equal variance between groups 
> boxplot(len ~ supp, data = ToothGrowth,
+         subset = dose == 0.5)
> var.test(len ~ supp, data = ToothGrowth,
+          subset = dose == 0.5)

	F test to compare two variances

data:  len by supp
F = 2.6364, num df = 9, denom df = 9, p-value = 0.1649
alternative hypothesis: true ratio of variances is not equal to 1
95 percent confidence interval:
  0.6548444 10.6141301
sample estimates:
ratio of variances 
            2.6364

The Shapiro-Wilk tests deliver a non-significant p-value which means we cannot reject the 0-hypothesis that the data is normally distributed. We thus assume a normal distribution of the tooth length. The p-value of the f-test is above 0,05, so the variance doesn’t differ significantly.

T-Test[edit]

# Perform an independent two-sample t-test

t_test_result <- t.test(len_OJ, len_VC)

# Print the test result

print(t_test_result)

To perform the t-test, the command t.test() is used. Since len_OJ and len_VC are compared with each other, they are placed inside the brackets of t.test(). This is a two-tailed test, which is why the order in which the two variables are specified does not matter.

By default, R uses Welch’s t-test, which can also be applied when the variances of the two groups differ. In this case, the variances are equal, so in theory the Student’s t-test could also be used but it is not necessary. The Student’s t-test is applied here: T-Test mtcars.

The results of the test on the right-hand side of the arrow are stored in the variable on the left-hand side. The results are then displayed in R using the print() command.

Output[edit]

Welch Two Sample t-test

data:  len_OJ and len_VC
t = 3.1697, df = 14.969, p-value = 0.006359
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 1.719057 8.780943
sample estimates:
mean of x mean of y 
    13.23      7.98

The two hypotheses of the t-test are:

HO: There is no difference in mean tooth length between the two supplement types (μ₁ = μ₂).

H1: There is a difference in mean tooth length between the two supplement types (μ₁ ≠ μ₂).

The p-value of 0.006359 is less than 0.05. Therefore, the null hypothesis can be rejected, indicating a statistically significant difference in mean tooth length between the two supplement groups. It can thus be concluded that tooth length differs between supplement types at a dosage of 0.5.

Visualisation[edit]

# Basic boxplot to compare tooth length distributions

boxplot(len ~ supp, data = ToothGrowth, subset = dose == 0.5,
        names = c("Orange Juice", "Vitamin C"),
        col = c("skyblue", "lightgreen"),
        main = "Tooth Growth by Supplement type",
        xlab = "Supplement Type",
        ylab = "Tooth Growth")

# Add mean points

points(x = c(1, 2),
       y = tapply(ToothGrowth$len[ToothGrowth$dose == 0.5],
                  ToothGrowth$supp[ToothGrowth$dose == 0.5],
                  mean),
       pch = 19, col = "red")

Output[edit]

The mean values are marked as red dots in the box plot. As can be seen, they differ clearly from one another, which is also confirmed by the T-test.

Fig. 2: A box plot to compare tooth length distributions


















The author of this entry is Hauke Haese. Last edited: 30.03.2026