Introduction

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.

Loading variables and dataset

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

Cleaning and creating columns data

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>

Multiple linear regression model

Collinearity check

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.

Multiple Linear Regression 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.

Diagnostic Plots

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.

  1. The QQ plot shows that the distribution in relatively even and there are not too many outrageous outliers.

  2. 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.

  3. The Cook’s distance plot shows that very few outlies have high leverage in this model.

Equation

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)

Determining final visualization

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)

End questions

  1. Wine has always been a luxury. Making wine is a very delicate craft. Attributes such as taste, smell, and viscosity all go into making a good wine. CVRVV focuses on making wine the best it can be. The most important factor in making a goo wine is the alcohol percentage and the acidity rate. In my work, these variables really shined in the linear regression.

https://repositorium.sdum.uminho.pt/bitstream/1822/10029/1/wine5.pdf

  1. What the visualization represents, any interesting patterns or surprises that arise within the visualization, and anything that could have been shown that you could not get to work or that you wished you could have included.

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.