This data topic is about the quality of wine and the physicochemical variables that contribute to wine’s quality. The variables are quality, fixed acidity, citric acid, volatile acidity, residual sugar, chlorides, free sulfur dioxide, total sulfur dioxide, density, pH, sulphates, alcohol percentage, and kfold. This data came from the CVRVV Collection on Vinho Verde Wine Physicochemical and Sensory Variables. The CVRVV is an organization that focuses on improving the quality of wine. I thought this topic was interesting because making wine can be a very delicate craft and I was intrigued by the amount of variables that go into making a good bottle of wine.
The dataset was basically clean so all I did was replace spaces for underscores in the column names and create a new categorical quality variable.
library(tidyverse)
library(plotly)
library(dplyr)
library(ggfortify)
library(htmltools)
library(GGally)
library(DataExplorer)
setwd("/Users/nnokigbo/Downloads")
wine <- read_csv("winequality-red-folds.csv")
## Rows: 1599 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl (13): fixed acidity, volatile acidity, citric acid, residual sugar, chlo...
##
## ℹ 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(wine)
## # A tibble: 6 Ă— 13
## `fixed acidity` `volatile acidity` `citric acid` `residual sugar` chlorides
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 8.9 0.48 0.53 4 0.101
## 2 9.4 0.685 0.11 2.7 0.077
## 3 10.2 0.23 0.37 2.2 0.057
## 4 7.3 0.73 0.24 1.9 0.108
## 5 8 0.62 0.35 2.8 0.086
## 6 8 0.67 0.3 2 0.06
## # ℹ 8 more variables: `free sulfur dioxide` <dbl>,
## # `total sulfur dioxide` <dbl>, density <dbl>, pH <dbl>, sulphates <dbl>,
## # alcohol <dbl>, quality <dbl>, kfold <dbl>
summary(wine)
## fixed acidity volatile acidity citric acid residual sugar
## Min. : 4.60 Min. :0.1200 Min. :0.000 Min. : 0.900
## 1st Qu.: 7.10 1st Qu.:0.3900 1st Qu.:0.090 1st Qu.: 1.900
## Median : 7.90 Median :0.5200 Median :0.260 Median : 2.200
## Mean : 8.32 Mean :0.5278 Mean :0.271 Mean : 2.539
## 3rd Qu.: 9.20 3rd Qu.:0.6400 3rd Qu.:0.420 3rd Qu.: 2.600
## Max. :15.90 Max. :1.5800 Max. :1.000 Max. :15.500
## chlorides free sulfur dioxide total sulfur dioxide density
## Min. :0.01200 Min. : 1.00 Min. : 6.00 Min. :0.9901
## 1st Qu.:0.07000 1st Qu.: 7.00 1st Qu.: 22.00 1st Qu.:0.9956
## Median :0.07900 Median :14.00 Median : 38.00 Median :0.9968
## Mean :0.08747 Mean :15.87 Mean : 46.47 Mean :0.9967
## 3rd Qu.:0.09000 3rd Qu.:21.00 3rd Qu.: 62.00 3rd Qu.:0.9978
## Max. :0.61100 Max. :72.00 Max. :289.00 Max. :1.0037
## pH sulphates alcohol quality
## Min. :2.740 Min. :0.3300 Min. : 8.40 Min. :3.000
## 1st Qu.:3.210 1st Qu.:0.5500 1st Qu.: 9.50 1st Qu.:5.000
## Median :3.310 Median :0.6200 Median :10.20 Median :6.000
## Mean :3.311 Mean :0.6581 Mean :10.42 Mean :5.636
## 3rd Qu.:3.400 3rd Qu.:0.7300 3rd Qu.:11.10 3rd Qu.:6.000
## Max. :4.010 Max. :2.0000 Max. :14.90 Max. :8.000
## kfold
## Min. :0.000
## 1st Qu.:1.000
## Median :2.000
## Mean :1.999
## 3rd Qu.:3.000
## Max. :4.000
As my project is dealing with all quantitative variables, I need to transform some into categorical variables. Quality is the response variable and is on a scale of 1-10. I will create a new column titles quality_desc from quality and place the ranges into groups of Bad, Okay, and Good.
# Mutating quality
wine <- wine |>
mutate(quality_desc = case_when((quality < 4) ~ "Bad",
(quality < 7) ~ "Okay",
(quality < 10) ~ "Good"))
# Replacing spaces with underscores
colnames(wine) = gsub(" ", "_", colnames(wine))
head(wine)
## # A tibble: 6 Ă— 14
## fixed_acidity volatile_acidity citric_acid residual_sugar chlorides
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 8.9 0.48 0.53 4 0.101
## 2 9.4 0.685 0.11 2.7 0.077
## 3 10.2 0.23 0.37 2.2 0.057
## 4 7.3 0.73 0.24 1.9 0.108
## 5 8 0.62 0.35 2.8 0.086
## 6 8 0.67 0.3 2 0.06
## # ℹ 9 more variables: free_sulfur_dioxide <dbl>, total_sulfur_dioxide <dbl>,
## # density <dbl>, pH <dbl>, sulphates <dbl>, alcohol <dbl>, quality <dbl>,
## # kfold <dbl>, quality_desc <chr>
Before we get started on our model, let’s check if any of the explanatory variables are dependent on each other.
#Checking collinearity
#plot_correlation(wine_mod)
ggpairs(wine, columns = 1:11)
There is no collinearity so now we can make the model.
Now that we’ve examined the dataset, let’s see what are the biggest factors in determining the quality of red wine.
fit1 <- lm(data = wine, quality ~ fixed_acidity + citric_acid + volatile_acidity + residual_sugar + chlorides + free_sulfur_dioxide + total_sulfur_dioxide + density + pH + sulphates + alcohol + kfold)
summary(fit1)
##
## Call:
## lm(formula = quality ~ fixed_acidity + citric_acid + volatile_acidity +
## residual_sugar + chlorides + free_sulfur_dioxide + total_sulfur_dioxide +
## density + pH + sulphates + alcohol + kfold, data = wine)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.68058 -0.36684 -0.04554 0.45130 2.02622
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 21.344851 21.216913 1.006 0.3146
## fixed_acidity 0.024490 0.025963 0.943 0.3457
## citric_acid -0.181650 0.147206 -1.234 0.2174
## volatile_acidity -1.083167 0.121123 -8.943 < 2e-16 ***
## residual_sugar 0.016411 0.015005 1.094 0.2742
## chlorides -1.887728 0.419804 -4.497 7.40e-06 ***
## free_sulfur_dioxide 0.004392 0.002172 2.022 0.0433 *
## total_sulfur_dioxide -0.003274 0.000729 -4.491 7.60e-06 ***
## density -17.234233 21.656744 -0.796 0.4263
## pH -0.415955 0.191658 -2.170 0.0301 *
## sulphates 0.916531 0.114356 8.015 2.12e-15 ***
## alcohol 0.276541 0.026492 10.438 < 2e-16 ***
## kfold -0.007975 0.011501 -0.693 0.4882
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.6481 on 1586 degrees of freedom
## Multiple R-squared: 0.3607, Adjusted R-squared: 0.3559
## F-statistic: 74.58 on 12 and 1586 DF, p-value: < 2.2e-16
It appears that fixed_acidity, citric acid, residual_sugar, density, and kfold have large p-values so we can remove them from the model and see how the model improves. The model’s current adjusted R-squared is 35.59%.
fit2 <- lm(data = wine, quality ~ volatile_acidity + chlorides + free_sulfur_dioxide + total_sulfur_dioxide + pH + sulphates + alcohol)
summary(fit2)
##
## Call:
## lm(formula = quality ~ volatile_acidity + chlorides + free_sulfur_dioxide +
## total_sulfur_dioxide + pH + sulphates + alcohol, data = wine)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.68918 -0.36757 -0.04653 0.46081 2.02954
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.4300987 0.4029168 10.995 < 2e-16 ***
## volatile_acidity -1.0127527 0.1008429 -10.043 < 2e-16 ***
## chlorides -2.0178138 0.3975417 -5.076 4.31e-07 ***
## free_sulfur_dioxide 0.0050774 0.0021255 2.389 0.017 *
## total_sulfur_dioxide -0.0034822 0.0006868 -5.070 4.43e-07 ***
## pH -0.4826614 0.1175581 -4.106 4.23e-05 ***
## sulphates 0.8826651 0.1099084 8.031 1.86e-15 ***
## alcohol 0.2893028 0.0167958 17.225 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.6477 on 1591 degrees of freedom
## Multiple R-squared: 0.3595, Adjusted R-squared: 0.3567
## F-statistic: 127.6 on 7 and 1591 DF, p-value: < 2.2e-16
The adjusted R-squared did improve from 35.59% to 35.67%. Now let’s get rid of the highest p-value, free sulfur dioxide, to see if the model can improve.
fit3 <- lm(data = wine, quality ~ volatile_acidity + chlorides + total_sulfur_dioxide + pH + sulphates + alcohol)
summary(fit3)
##
## Call:
## lm(formula = quality ~ volatile_acidity + chlorides + total_sulfur_dioxide +
## pH + sulphates + alcohol, data = wine)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.60575 -0.35883 -0.04806 0.46079 1.95643
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.2957316 0.3995603 10.751 < 2e-16 ***
## volatile_acidity -1.0381945 0.1004270 -10.338 < 2e-16 ***
## chlorides -2.0022839 0.3980757 -5.030 5.46e-07 ***
## total_sulfur_dioxide -0.0023721 0.0005064 -4.684 3.05e-06 ***
## pH -0.4351830 0.1160368 -3.750 0.000183 ***
## sulphates 0.8886802 0.1100419 8.076 1.31e-15 ***
## alcohol 0.2906738 0.0168108 17.291 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.6487 on 1592 degrees of freedom
## Multiple R-squared: 0.3572, Adjusted R-squared: 0.3548
## F-statistic: 147.4 on 6 and 1592 DF, p-value: < 2.2e-16
The adjusted R-squared decreased so it seems that fit2 was out best model.
autoplot(fit2, 1:4, nrow=2, ncol=2)
1. In the residuals plot, you can see that the blue line is relatively
horrizontal meaning that a linear plot would be appropriate for this
model.
The QQ plot shows that the distribution in relatively even and there are not too many outrageous outliers.
This plot was interesting as it shows a clear pattern that I am unsure how to analyze. However, observations that could be skewing the variance distribution are identified.
The Cook’s distance plot shows that very few outlies have high leverage in this model.
The equation for this model is
quality = -1.012(volatile_acidity) -2.017(chlorides) + 0.005(free_sulfur_dioxide) - 0.0034(total_sulfur_dioxide) -0.4826(pH) +0.8826(sulphates) + 0.2893(alchohol)
So let’s do a bit more exploring
library(viridis)
## Loading required package: viridisLite
PLOT <- ggplot(wine, aes(x=volatile_acidity, y = alcohol, color = quality_desc)) +
geom_point(alpha = 0.05) +
geom_hex() +
scale_fill_gradient2(name = "Counts of Cases in Hexagon") +
scale_color_manual(values = c("red", "green", "orange"), name = "Quality Description") +
labs(
x = "Volatile Acidity",
y = "Alcohol %",
title = "Hexbin Plot of Alcohol and Volatile Acidity in Wine based on Quality",
caption = "Source = CVRVV Collection on Vinho Verde Wine Physicochemical and Sensory Variables"
) + theme_classic()
PLOT
ggplotly(PLOT)
https://repositorium.sdum.uminho.pt/bitstream/1822/10029/1/wine5.pdf
This visual shows the relationship between alcohol and volatile acidity. It shows that the wines considered good quality typically have less volatile acidity and more alcohol which I found very interesting. I was confused by t4he scaled fitted plot and was unsure how to asses and analyze the results. I wish I would’ve found a way to make to plot a bit prettier. I liked my use of the hexplot because it worked with my large data frame. The scatterplot became cluttered and the hexagons helped simplify it.