Список используемых packages для выполнения этой работы

library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.0.3
## -- Attaching packages --------------- tidyverse 1.3.0 --
## v ggplot2 3.3.2     v purrr   0.3.4
## v tibble  3.0.3     v dplyr   1.0.2
## v tidyr   1.1.2     v stringr 1.4.0
## v readr   1.4.0     v forcats 0.5.0
## Warning: package 'ggplot2' was built under R version 4.0.3
## Warning: package 'tidyr' was built under R version 4.0.3
## Warning: package 'readr' was built under R version 4.0.3
## Warning: package 'forcats' was built under R version 4.0.3
## -- Conflicts ------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(corrplot)
## Warning: package 'corrplot' was built under R version 4.0.3
## corrplot 0.84 loaded
library(car)
## Warning: package 'car' was built under R version 4.0.3
## Loading required package: carData
## Warning: package 'carData' was built under R version 4.0.3
## 
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
## 
##     recode
## The following object is masked from 'package:purrr':
## 
##     some
library(caret)
## Warning: package 'caret' was built under R version 4.0.3
## Loading required package: lattice
## 
## Attaching package: 'caret'
## The following object is masked from 'package:purrr':
## 
##     lift
library(factoextra)
## Warning: package 'factoextra' was built under R version 4.0.3
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa

Визуализируем наши данные, которые представляют из себя описание состава красных вин и их качество (от 0 до 10). Для этого мы построили график изображающий на диагонали распределение переменных и на пересечениях строит зависимости между переменными и регрессионную прямую.

df_red <- read.csv('red_wine.csv', header = TRUE, sep = ',') %>% na.omit()
head(df_red)
##   fixed.acidity volatile.acidity citric.acid residual.sugar chlorides
## 1           7.4             0.70        0.00            1.9     0.076
## 2           7.8             0.88        0.00            2.6     0.098
## 3           7.8             0.76        0.04            2.3     0.092
## 4          11.2             0.28        0.56            1.9     0.075
## 5           7.4             0.70        0.00            1.9     0.076
## 6           7.4             0.66        0.00            1.8     0.075
##   free.sulfur.dioxide total.sulfur.dioxide density   pH sulphates alcohol
## 1                  11                   34  0.9978 3.51      0.56     9.4
## 2                  25                   67  0.9968 3.20      0.68     9.8
## 3                  15                   54  0.9970 3.26      0.65     9.8
## 4                  17                   60  0.9980 3.16      0.58     9.8
## 5                  11                   34  0.9978 3.51      0.56     9.4
## 6                  13                   40  0.9978 3.51      0.56     9.4
##   quality
## 1       5
## 2       5
## 3       5
## 4       6
## 5       5
## 6       5
scatterplotMatrix(df_red, cex.main = 1000)

Помимо этого для большей наглядности и подготовки для работы с линейной регрессией (в частности для проверки мультиколлинеарности считаем корреляцию между переменными).

M <- cor(df_red)
corrplot(M, method = "circle")

Теперь для полноценной работы с линейной регрессией и попыткой определить значимые переменные, влияющие на качество красного вина, разделим нашу выборку на train(80%) и test(20%). После этого пытаемся сделать линейную модель зависимости качества вина от всех остальных параметров (заранее отметив что на первых двух графиках выделяются зависимые между сабой переменные, которые в последствии надо убрать). После этого проверяем нашу модель на тестовой выборке. Отмечаем для себя RMSE и R2.

set.seed(06101998)
training.samples <- df_red$quality %>% createDataPartition(p = 0.8, list = FALSE)
train.data  <- df_red[training.samples, ]
test.data <- df_red[-training.samples, ]
model1 <- lm(quality ~., data = train.data)
predictions_model1 <- model1 %>% predict(test.data)
summary(model1)
## 
## Call:
## lm(formula = quality ~ ., data = train.data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.79745 -0.36668 -0.05426  0.43909  2.08489 
## 
## Coefficients:
##                        Estimate Std. Error t value Pr(>|t|)    
## (Intercept)           1.704e+01  2.390e+01   0.713 0.476095    
## fixed.acidity         3.367e-02  2.924e-02   1.152 0.249683    
## volatile.acidity     -1.096e+00  1.316e-01  -8.329  < 2e-16 ***
## citric.acid          -1.558e-01  1.651e-01  -0.944 0.345456    
## residual.sugar        8.877e-03  1.686e-02   0.527 0.598623    
## chlorides            -1.733e+00  4.729e-01  -3.664 0.000259 ***
## free.sulfur.dioxide   6.210e-03  2.449e-03   2.535 0.011355 *  
## total.sulfur.dioxide -3.982e-03  8.455e-04  -4.710 2.75e-06 ***
## density              -1.352e+01  2.438e+01  -0.555 0.579228    
## pH                   -2.223e-01  2.129e-01  -1.044 0.296676    
## sulphates             9.463e-01  1.258e-01   7.520 1.03e-13 ***
## alcohol               2.641e-01  3.005e-02   8.790  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.6445 on 1269 degrees of freedom
## Multiple R-squared:  0.3681, Adjusted R-squared:  0.3626 
## F-statistic:  67.2 on 11 and 1269 DF,  p-value: < 2.2e-16
data.frame(
    RMSE = RMSE(predictions_model1, test.data$quality),
    R2 = R2(predictions_model1, test.data$quality)
)
##        RMSE        R2
## 1 0.6662178 0.3220679

Теперь мы хотим проверить наверняка и попытаться избавиться от зависимых независимых переменных). Для этого сначала воспользуемся коэффициентом вздутия.

vif(model1)
##        fixed.acidity     volatile.acidity          citric.acid 
##             7.796089             1.736642             3.121401 
##       residual.sugar            chlorides  free.sulfur.dioxide 
##             1.744058             1.549066             2.015661 
## total.sulfur.dioxide              density                   pH 
##             2.242904             6.536405             3.352275 
##            sulphates              alcohol 
##             1.447917             3.181133

Среди полученных значений явно выделяются 2 величины fixed.acidity и density, у которых значения самые большие (и в некоторых источниках предлагают отказываться от значений >5). Это мы и делаем. Для этого мы делаем новую модель, из которой мы убираем выбранные нами переменные. Проведя аналогичные действия как с первой моделью мы также отмечаем для себя RMSE и R2. При этом видно, что хоть и не значительно, но RMSE уменьшился, а R2 увеличился. Это говорит о том, что идем мы в верном направлении.

model2 <- lm(quality ~. -density - fixed.acidity, data = train.data)
predictions_model2 <- model2 %>% predict(test.data)
summary(model2)
## 
## Call:
## lm(formula = quality ~ . - density - fixed.acidity, data = train.data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.74367 -0.37009 -0.04875  0.43969  2.08744 
## 
## Coefficients:
##                        Estimate Std. Error t value Pr(>|t|)    
## (Intercept)           4.3033640  0.5131936   8.385  < 2e-16 ***
## volatile.acidity     -1.0677823  0.1270737  -8.403  < 2e-16 ***
## citric.acid          -0.0502360  0.1368241  -0.367  0.71356    
## residual.sugar        0.0046681  0.0132739   0.352  0.72514    
## chlorides            -1.9122592  0.4510455  -4.240 2.40e-05 ***
## free.sulfur.dioxide   0.0065145  0.0024303   2.681  0.00744 ** 
## total.sulfur.dioxide -0.0042908  0.0008099  -5.298 1.38e-07 ***
## pH                   -0.3951199  0.1485622  -2.660  0.00792 ** 
## sulphates             0.9437973  0.1217132   7.754 1.81e-14 ***
## alcohol               0.2737183  0.0193343  14.157  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.6444 on 1271 degrees of freedom
## Multiple R-squared:  0.3673, Adjusted R-squared:  0.3628 
## F-statistic: 81.97 on 9 and 1271 DF,  p-value: < 2.2e-16
data.frame(
    RMSE = RMSE(predictions_model2, test.data$quality),
    R2 = R2(predictions_model2, test.data$quality)
)
##        RMSE       R2
## 1 0.6649895 0.324596

Далее я решил проверить, можно ли явно зависимые величины (чисто из логических умозаключений и первых двух графиков) попыцтаться тоже убрать, не обращая внимание на их низкий коэффициент вздутия. Очевидно, что free.sulfur.dioxide и total.sulfur.dioxide зависимы (это видно и из графиков), также я посчитал, что количество кислот (помимо fixed.acidity) можно выразить и через pH (поэтому вообще поидеи можно отказаться от описания концентрации различных кислот потому что это физически отображается на pH). И еще мне показалось логичным отказаться от плотности (и без ее коэффициента вздутия), которая также зависит от количества алкоголя и концентраций кислот, которые зависят от pH. Таким образом дополнительно я решил убрать еще 2 независимые переменные: free.sulfur.dioxide, citric.acid. Проделав тот же набор действий, что и с первой моделью, снова выписываем RMSE и R2. Которые опять уменьшилось и увеличилось соответственно. Можно сделать вывод, что зависимость между независимыми переменными действительно влияют на качество линейной модели (хотя мне не повезло это увидеть во всей красе, видимо из-за нехватки признаков, которых очень много есть у вина для оценки его качества).

model3 <- lm(quality ~. -density - fixed.acidity - free.sulfur.dioxide - citric.acid, data = train.data)
predictions_model3 <- model3 %>% predict(test.data)
summary(model3)
## 
## Call:
## lm(formula = quality ~ . - density - fixed.acidity - free.sulfur.dioxide - 
##     citric.acid, data = train.data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.63638 -0.36801 -0.05703  0.44142  1.99835 
## 
## Coefficients:
##                        Estimate Std. Error t value Pr(>|t|)    
## (Intercept)           4.0307212  0.4480041   8.997  < 2e-16 ***
## volatile.acidity     -1.0792712  0.1110950  -9.715  < 2e-16 ***
## residual.sugar        0.0086697  0.0130971   0.662   0.5081    
## chlorides            -1.9071384  0.4468489  -4.268 2.12e-05 ***
## total.sulfur.dioxide -0.0028446  0.0005949  -4.782 1.94e-06 ***
## pH                   -0.3098178  0.1298307  -2.386   0.0172 *  
## sulphates             0.9366437  0.1215091   7.708 2.55e-14 ***
## alcohol               0.2749784  0.0189926  14.478  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.6459 on 1273 degrees of freedom
## Multiple R-squared:  0.3634, Adjusted R-squared:  0.3599 
## F-statistic: 103.8 on 7 and 1273 DF,  p-value: < 2.2e-16
data.frame(
    RMSE = RMSE(predictions_model3, test.data$quality),
    R2 = R2(predictions_model3, test.data$quality)
)
##        RMSE        R2
## 1 0.6623937 0.3301312

Далее было интересно попробовать метод понижения размерности, хотя бы потому, что он мне понадобится для решения задач в моей курсовой. Для начала я посмотрел на то как у меня вообще распределена величина - качество вина. На графике ниже видно, что качество вин в основном равняется 5,6,7. Поэтому чтобы упростить работу с понижением размерности и улучшить визуальную составляющую моего последнего графика я решил посмотреть именно на те данные качество которых равнялось 5, 6 или 7. После этого, убрав из моих данных столбцы с выброшенными переменными, я запустил PCA. Дальше я построил стандартный для этого метода график отношения процентов объясненной дисперсии от числа dimention. На нем видно. После я построил график переменных. Положительно коррелированные переменные указывают на одну и ту же сторону графика. Отрицательные коррелированные переменные указывают на противоположные стороны графика. Окрашены они по вклады в компоненты. Ну и на последок было интересно как же легли мои точки на этот график. Собственно последний график и показывает расположение отдельных точек из 3 групп с разным качеством. При этом можно увидеть (в идеале конечно сделать кластеризацию), что ак минимум 5 и 7 качества неплохо разделяются, хотя и группа 6 впринципе похоже, что тоже имеет некоторую собственную область. Это говорит о том, что впринципе можно найти такие независимые переменные, которые могли бы приближенно различать несколько разных вин по качеству. нууууу, теперь и машинку можно ) (шучу).

p = ggplot(data = df_red, aes (quality, fill=quality))
p + geom_bar()

df_red_pca = df_red[df_red$quality == c(5,6,7), ]
c <- c(8, 1, 6, 3, 12)
res.pca <- prcomp(df_red_pca[-c], scale = TRUE, center = TRUE)
fviz_eig(res.pca)

groups <- as.factor(df_red_pca$quality)
fviz_pca_var(res.pca,
             col.var = "contrib",
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE
)

fviz_pca_ind(res.pca,
             col.ind = groups,
             addEllipses = TRUE,
             ellipse.type = "confidence",
             legend.title = "Groups",
             repel = TRUE
             )
## Warning: ggrepel: 449 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps