Задание 1-2: Создание датасета и очистка с is.na()

my_vector <- c(10, 25, NA, 15, 30, NA, 42, 55, NA, 18)
print("Исходный датасет (вектор):")
## [1] "Исходный датасет (вектор):"
print(my_vector)
##  [1] 10 25 NA 15 30 NA 42 55 NA 18
print("Индексы пропусков (TRUE - пропуск):")
## [1] "Индексы пропусков (TRUE - пропуск):"
print(is.na(my_vector))
##  [1] FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE
print("Очищенный датасет (без NA):")
## [1] "Очищенный датасет (без NA):"
print(my_vector[!is.na(my_vector)])
## [1] 10 25 15 30 42 55 18

Задание 3: Очистка data.frame с complete.cases()

df <- data.frame(
  ID = 1:10,
  Value = c(5.1, 6.3, NA, 4.8, 7.2, NA, 5.9, 8.0, NA, 6.6),
  Category = c("A", "B", "B", NA, "A", "C", "C", "B", NA, "A"),
  Score = c(85, NA, 92, 78, 88, 95, NA, 89, 76, 91),
  stringsAsFactors = FALSE
)
print("Исходная таблица данных:")
## [1] "Исходная таблица данных:"
print(df)
##    ID Value Category Score
## 1   1   5.1        A    85
## 2   2   6.3        B    NA
## 3   3    NA        B    92
## 4   4   4.8     <NA>    78
## 5   5   7.2        A    88
## 6   6    NA        C    95
## 7   7   5.9        C    NA
## 8   8   8.0        B    89
## 9   9    NA     <NA>    76
## 10 10   6.6        A    91
complete_rows <- complete.cases(df)
print("Логический вектор полных строк (TRUE - нет пропусков):")
## [1] "Логический вектор полных строк (TRUE - нет пропусков):"
print(complete_rows)
##  [1]  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE  TRUE
clean_df <- df[complete_rows, ]
print("Очищенная таблица данных (только полные строки):")
## [1] "Очищенная таблица данных (только полные строки):"
print(clean_df)
##    ID Value Category Score
## 1   1   5.1        A    85
## 5   5   7.2        A    88
## 8   8   8.0        B    89
## 10 10   6.6        A    91

Задание 4: Импьютация с caret (airquality)

library(caret)
library(datasets)
data("airquality")
print("Структура исходного датасета airquality:")
## [1] "Структура исходного датасета airquality:"
str(airquality)
## 'data.frame':    153 obs. of  6 variables:
##  $ Ozone  : int  41 36 12 18 NA 28 23 19 8 NA ...
##  $ Solar.R: int  190 118 149 313 NA NA 299 99 19 194 ...
##  $ Wind   : num  7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ...
##  $ Temp   : int  67 72 74 62 56 66 65 59 61 69 ...
##  $ Month  : int  5 5 5 5 5 5 5 5 5 5 ...
##  $ Day    : int  1 2 3 4 5 6 7 8 9 10 ...
print("Количество NA в каждом столбце:")
## [1] "Количество NA в каждом столбце:"
colSums(is.na(airquality))
##   Ozone Solar.R    Wind    Temp   Month     Day 
##      37       7       0       0       0       0
df_for_impute <- airquality[, 1:4]
print("Первые несколько строк данных до импьютации:")
## [1] "Первые несколько строк данных до импьютации:"
head(df_for_impute, 10)
##    Ozone Solar.R Wind Temp
## 1     41     190  7.4   67
## 2     36     118  8.0   72
## 3     12     149 12.6   74
## 4     18     313 11.5   62
## 5     NA      NA 14.3   56
## 6     28      NA 14.9   66
## 7     23     299  8.6   65
## 8     19      99 13.8   59
## 9      8      19 20.1   61
## 10    NA     194  8.6   69
set.seed(123)
preProc_median <- preProcess(df_for_impute, method = "medianImpute")
df_median_imputed <- predict(preProc_median, df_for_impute)
print("Первые несколько строк после импьютации медианой:")
## [1] "Первые несколько строк после импьютации медианой:"
head(df_median_imputed, 10)
##    Ozone Solar.R Wind Temp
## 1   41.0     190  7.4   67
## 2   36.0     118  8.0   72
## 3   12.0     149 12.6   74
## 4   18.0     313 11.5   62
## 5   31.5     205 14.3   56
## 6   28.0     205 14.9   66
## 7   23.0     299  8.6   65
## 8   19.0      99 13.8   59
## 9    8.0      19 20.1   61
## 10  31.5     194  8.6   69
print("Проверка NA после импьютации медианой:")
## [1] "Проверка NA после импьютации медианой:"
colSums(is.na(df_median_imputed))
##   Ozone Solar.R    Wind    Temp 
##       0       0       0       0

Задание 5: Обнаружение и удаление выбросов

set.seed(456)
data1 <- c(rnorm(40, mean = 10, sd = 2), 25, 30)
data2 <- c(rnorm(40, mean = 50, sd = 5), 10, 75)
print("Сгенерированные данные (data1):")
## [1] "Сгенерированные данные (data1):"
print(data1)
##  [1]  7.312957 11.243551 11.601749  7.222215  8.571286  9.351878 11.381286
##  [8] 10.501096 12.014705 11.146469  8.168379 12.622195 11.977453 13.307857
## [15]  7.118390 13.894713 13.473872 10.774967 14.560068 13.075767  9.050792
## [22]  6.565382  7.146339 10.416472  9.928328 12.268569  9.074290  9.343232
## [29] 12.969079  7.821244  8.942412  8.812414  6.002169 10.592306 10.341251
## [36] 13.631305  8.678794  9.719496  9.152042  9.922528 25.000000 30.000000
print("Сгенерированные данные (data2):")
## [1] "Сгенерированные данные (data2):"
print(data2)
##  [1] 49.85529 51.96519 48.75193 50.41725 60.39437 50.60426 50.59075 53.85027
##  [9] 44.12299 52.04519 46.67525 48.71738 53.39391 54.48422 53.09178 53.65727
## [17] 47.93413 57.78907 52.70849 52.88575 38.72645 45.08970 48.99716 54.47965
## [25] 49.78228 58.23654 57.81650 42.84311 47.27703 46.14373 49.15006 49.79619
## [33] 41.39730 57.22053 49.89993 51.35116 49.43533 45.72556 44.83129 51.11013
## [41] 10.00000 75.00000
remove_outliers <- function(x) {
  outliers <- boxplot.stats(x)$out
  outlier_indices <- which(x %in% outliers)
  if (length(outlier_indices) > 0) {
    cat("Найдены выбросы на позициях:", paste(outlier_indices, collapse=", "), "со значениями:", paste(outliers, collapse=", "), "\n")
    return(x[-outlier_indices])
  } else {
    cat("Выбросов не найдено.\n")
    return(x)
  }
}

par(mfrow=c(1,2))
boxplot(data1, main="Data1 с выбросами", col="lightblue", horizontal=TRUE)
boxplot(data2, main="Data2 с выбросами", col="lightgreen", horizontal=TRUE)

clean_data1 <- remove_outliers(data1)
## Найдены выбросы на позициях: 41, 42 со значениями: 25, 30
clean_data2 <- remove_outliers(data2)
## Найдены выбросы на позициях: 41, 42 со значениями: 10, 75
par(mfrow=c(1,2))
boxplot(clean_data1, main="Data1 без выбросов", col="lightblue", horizontal=TRUE)
boxplot(clean_data2, main="Data2 без выбросов", col="lightgreen", horizontal=TRUE)

par(mfrow=c(1,1))

Задание 6: Удаление дублирующихся строк

df_dup <- data.frame(
  ID = c(1, 2, 3, 1, 4, 2, 5, 3),
  Value = c("A", "B", "C", "A", "D", "B", "E", "C"),
  Score = c(10, 20, 30, 10, 40, 20, 50, 30),
  stringsAsFactors = FALSE
)
print("Исходная таблица с дубликатами:")
## [1] "Исходная таблица с дубликатами:"
print(df_dup)
##   ID Value Score
## 1  1     A    10
## 2  2     B    20
## 3  3     C    30
## 4  1     A    10
## 5  4     D    40
## 6  2     B    20
## 7  5     E    50
## 8  3     C    30
df_unique <- unique(df_dup)
print("Результат unique() (все уникальные строки):")
## [1] "Результат unique() (все уникальные строки):"
print(df_unique)
##   ID Value Score
## 1  1     A    10
## 2  2     B    20
## 3  3     C    30
## 5  4     D    40
## 7  5     E    50
print(paste("Количество строк после unique():", nrow(df_unique)))
## [1] "Количество строк после unique(): 5"
duplicate_rows <- duplicated(df_dup)
print("Логический вектор duplicated() (TRUE - дубликат):")
## [1] "Логический вектор duplicated() (TRUE - дубликат):"
print(duplicate_rows)
## [1] FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE  TRUE
df_dup_removed <- df_dup[!duplicate_rows, ]
print("Результат !duplicated() (первые вхождения каждой уникальной строки):")
## [1] "Результат !duplicated() (первые вхождения каждой уникальной строки):"
print(df_dup_removed)
##   ID Value Score
## 1  1     A    10
## 2  2     B    20
## 3  3     C    30
## 5  4     D    40
## 7  5     E    50
print(paste("Количество строк после !duplicated():", nrow(df_dup_removed)))
## [1] "Количество строк после !duplicated(): 5"
duplicate_rows_last <- duplicated(df_dup, fromLast = TRUE)
df_dup_removed_last <- df_dup[!duplicate_rows_last, ]
print("Результат !duplicated(..., fromLast=TRUE) (последние вхождения каждой уникальной строки):")
## [1] "Результат !duplicated(..., fromLast=TRUE) (последние вхождения каждой уникальной строки):"
print(df_dup_removed_last)
##   ID Value Score
## 4  1     A    10
## 5  4     D    40
## 6  2     B    20
## 7  5     E    50
## 8  3     C    30
print("Сравнение:")
## [1] "Сравнение:"
print("unique() сохранил порядок первого появления каждой уникальной строки, удалив все повторы.")
## [1] "unique() сохранил порядок первого появления каждой уникальной строки, удалив все повторы."
print("!duplicated() сделал то же самое, что и unique() по умолчанию.")
## [1] "!duplicated() сделал то же самое, что и unique() по умолчанию."
print("!duplicated(fromLast=TRUE) сохранил порядок последнего появления каждой уникальной строки.")
## [1] "!duplicated(fromLast=TRUE) сохранил порядок последнего появления каждой уникальной строки."

Задание 7: Обработка пропусков с MICE

library(mice)
data("airquality")
df_mice_clean <- airquality[, 1:4]
names(df_mice_clean) <- c("Ozone", "Solar", "Wind", "Temp")
print("Датасет airquality для анализа:")
## [1] "Датасет airquality для анализа:"
head(df_mice_clean, 15)
##    Ozone Solar Wind Temp
## 1     41   190  7.4   67
## 2     36   118  8.0   72
## 3     12   149 12.6   74
## 4     18   313 11.5   62
## 5     NA    NA 14.3   56
## 6     28    NA 14.9   66
## 7     23   299  8.6   65
## 8     19    99 13.8   59
## 9      8    19 20.1   61
## 10    NA   194  8.6   69
## 11     7    NA  6.9   74
## 12    16   256  9.7   69
## 13    11   290  9.2   66
## 14    14   274 10.9   68
## 15    18    65 13.2   58
print("Сводка по пропускам:")
## [1] "Сводка по пропускам:"
summary(df_mice_clean)
##      Ozone            Solar            Wind             Temp      
##  Min.   :  1.00   Min.   :  7.0   Min.   : 1.700   Min.   :56.00  
##  1st Qu.: 18.00   1st Qu.:115.8   1st Qu.: 7.400   1st Qu.:72.00  
##  Median : 31.50   Median :205.0   Median : 9.700   Median :79.00  
##  Mean   : 42.13   Mean   :185.9   Mean   : 9.958   Mean   :77.88  
##  3rd Qu.: 63.25   3rd Qu.:258.8   3rd Qu.:11.500   3rd Qu.:85.00  
##  Max.   :168.00   Max.   :334.0   Max.   :20.700   Max.   :97.00  
##  NA's   :37       NA's   :7
md.pattern(df_mice_clean)

##     Wind Temp Solar Ozone   
## 111    1    1     1     1  0
## 35     1    1     1     0  1
## 5      1    1     0     1  1
## 2      1    1     0     0  2
##        0    0     7    37 44
mice_imputed <- mice(df_mice_clean, m = 5, maxit = 20, method = 'pmm', seed = 123, printFlag = FALSE)
print("Результат импьютации MICE:")
## [1] "Результат импьютации MICE:"
print(mice_imputed)
## Class: mids
## Number of multiple imputations:  5 
## Imputation methods:
## Ozone Solar  Wind  Temp 
## "pmm" "pmm"    ""    "" 
## PredictorMatrix:
##       Ozone Solar Wind Temp
## Ozone     0     1    1    1
## Solar     1     0    1    1
## Wind      1     1    0    1
## Temp      1     1    1    0
df_complete_1 <- complete(mice_imputed, 1)
print("Заполненный датасет (импьютация №1):")
## [1] "Заполненный датасет (импьютация №1):"
head(df_complete_1, 20)
##    Ozone Solar Wind Temp
## 1     41   190  7.4   67
## 2     36   118  8.0   72
## 3     12   149 12.6   74
## 4     18   313 11.5   62
## 5      1   224 14.3   56
## 6     28   175 14.9   66
## 7     23   299  8.6   65
## 8     19    99 13.8   59
## 9      8    19 20.1   61
## 10    23   194  8.6   69
## 11     7     7  6.9   74
## 12    16   256  9.7   69
## 13    11   290  9.2   66
## 14    14   274 10.9   68
## 15    18    65 13.2   58
## 16    14   334 11.5   64
## 17    34   307 12.0   66
## 18     6    78 18.4   57
## 19    30   322 11.5   68
## 20    11    44  9.7   62
print("Проверка NA после импьютации:")
## [1] "Проверка NA после импьютации:"
print(colSums(is.na(df_complete_1)))
## Ozone Solar  Wind  Temp 
##     0     0     0     0

Задание 8: Диагностика мультиколлинеарности

library(car)
library(GGally)
set.seed(101)
n <- 100
x1 <- rnorm(n, mean = 50, sd = 10)
x2 <- rnorm(n, mean = 30, sd = 5)
x3 <- 0.9 * x2 + rnorm(n, mean = 0, sd = 2)
x4 <- rnorm(n, mean = 100, sd = 15)
y <- 5 + 0.4 * x1 + 0.8 * x2 + 0.1 * x3 + 1.5 * x4 + rnorm(n, mean = 0, sd = 10)
df_ml <- data.frame(y = y, x1 = x1, x2 = x2, x3 = x3, x4 = x4)

print("Матрица корреляций:")
## [1] "Матрица корреляций:"
cor_matrix <- cor(df_ml[, -1])
print(round(cor_matrix, 2))
##       x1   x2   x3    x4
## x1  1.00 0.11 0.09 -0.15
## x2  0.11 1.00 0.94  0.18
## x3  0.09 0.94 1.00  0.19
## x4 -0.15 0.18 0.19  1.00
ggpairs(df_ml[, -1], title = "Матрица корреляций")

model <- lm(y ~ x1 + x2 + x3 + x4, data = df_ml)
print("Сводка регрессионной модели:")
## [1] "Сводка регрессионной модели:"
summary(model)
## 
## Call:
## lm(formula = y ~ x1 + x2 + x3 + x4, data = df_ml)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -19.610  -6.749  -1.128   6.444  22.805 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  0.48486    9.76915   0.050  0.96052    
## x1           0.38135    0.10756   3.546  0.00061 ***
## x2           1.34961    0.57644   2.341  0.02131 *  
## x3          -0.35769    0.57069  -0.627  0.53231    
## x4           1.49225    0.06447  23.145  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 9.787 on 95 degrees of freedom
## Multiple R-squared:  0.8696, Adjusted R-squared:  0.8641 
## F-statistic: 158.4 on 4 and 95 DF,  p-value: < 2.2e-16
vif_values <- vif(model)
print("VIF (Variance Inflation Factor):")
## [1] "VIF (Variance Inflation Factor):"
print(vif_values)
##       x1       x2       x3       x4 
## 1.043238 8.658105 8.667380 1.069558
if (any(vif_values > 10)) {
  cat("Обнаружена сильная мультиколлинеарность для переменных с VIF > 10.\n")
}

model_corrected <- lm(y ~ x1 + x2 + x4, data = df_ml)
print("Сводка модели после удаления x3:")
## [1] "Сводка модели после удаления x3:"
summary(model_corrected)
## 
## Call:
## lm(formula = y ~ x1 + x2 + x4, data = df_ml)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -18.6771  -6.7193  -0.9819   6.4118  22.6183 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  1.20039    9.67149   0.124 0.901482    
## x1           0.38200    0.10721   3.563 0.000573 ***
## x2           1.01101    0.20044   5.044 2.15e-06 ***
## x4           1.48972    0.06414  23.224  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 9.756 on 96 degrees of freedom
## Multiple R-squared:  0.869,  Adjusted R-squared:  0.865 
## F-statistic: 212.4 on 3 and 96 DF,  p-value: < 2.2e-16
print("VIF для новой модели:")
## [1] "VIF для новой модели:"
print(vif(model_corrected))
##       x1       x2       x4 
## 1.043142 1.053546 1.065360