Введение

В данной лабораторной работе рассматриваются основные методы подготовки данных в языке R: обработка пропусков, удаление выбросов, работа с дубликатами, а также анализ мультиколлинеарности.

Установка компонентов

Установка и импорт необходимых компонентов

options(repos = "https://cran.r-project.org/")
install.packages(c("RANN", "caret", "mice", "car"))
## Устанавливаю пакеты в 'C:/Users/Olekander/AppData/Local/R/win-library/4.5'
## (потому что 'lib' не определено)
## пакет 'RANN' успешно распакован, MD5-суммы проверены
## пакет 'caret' успешно распакован, MD5-суммы проверены
## пакет 'mice' успешно распакован, MD5-суммы проверены
## пакет 'car' успешно распакован, MD5-суммы проверены
## 
## Скачанные бинарные пакеты находятся в
##  D:\temp\Rtmp6jYY8G\downloaded_packages
library(caret)
## Warning: пакет 'caret' был собран под R версии 4.5.3
## Загрузка требуемого пакета: ggplot2
## Загрузка требуемого пакета: lattice
library(mice)
## Warning: пакет 'mice' был собран под R версии 4.5.3
## 
## Присоединяю пакет: 'mice'
## Следующий объект скрыт от 'package:stats':
## 
##     filter
## Следующие объекты скрыты от 'package:base':
## 
##     cbind, rbind
library(car)
## Warning: пакет 'car' был собран под R версии 4.5.3
## Загрузка требуемого пакета: carData
## Warning: пакет 'carData' был собран под R версии 4.5.3
## Registered S3 method overwritten by 'car':
##   method           from
##   na.action.merMod lme4

Задание 1

Сформируйте свой собственный датасет с помощью функции c (конкатенация), в котором содержатся числовые данные и NA значения.

# Создаем вектор с числами и NA и выводим его
data1 <- c(10, 20, NA, 40, 50, NA, 70)
data1
## [1] 10 20 NA 40 50 NA 70

Задание 2

Проведите очистку данных с использованием функции is.na() [1]. И выведите “чистый” датасет.

# Проверяем, где находятся NA, создавая вектор с логическими данными, удаляем все NA и выводим измененный вектор
clean_data1 <- data1[!is.na(data1)]
clean_data1
## [1] 10 20 40 50 70

Задание 3

Сгенерируйте таблицу данных с числовыми и текстовые столбцами (аналогично с помощью функции c). Очистите данные с помощью функции complete.cases() [1].

# Создаем таблицу данных с NA среди них, выводим ее, очищаем данные с помощью
# complete.cases()
df <- data.frame(
  numbers = c(1, 2, NA, 4, 5),
  text = c("A", "B", "C", NA, "E")
)

df
##   numbers text
## 1       1    A
## 2       2    B
## 3      NA    C
## 4       4 <NA>
## 5       5    E
clean_df <- df[complete.cases(df), ]
#Запятая , означает: [строки, колонки]
#До запятой - условие для отбора строк (только TRUE)
#После запятой - пусто, значит берем все колонки
clean_df
##   numbers text
## 1       1    A
## 2       2    B
## 5       5    E

Задание 4

Проанализируйте датасет airquality с пропусками из пакета caret. С использованием функции preProcess из пакета caret заполните пропуски предсказанными значениями (среднее, медиана) [2].

data("airquality")

# Определяем строки с пропусками
ind <- apply(airquality, 1, function(x) sum(is.na(x))) > 0

# Смотрим строки с NA
airquality[ind, ]
##     Ozone Solar.R Wind Temp Month Day
## 5      NA      NA 14.3   56     5   5
## 6      28      NA 14.9   66     5   6
## 10     NA     194  8.6   69     5  10
## 11      7      NA  6.9   74     5  11
## 25     NA      66 16.6   57     5  25
## 26     NA     266 14.9   58     5  26
## 27     NA      NA  8.0   57     5  27
## 32     NA     286  8.6   78     6   1
## 33     NA     287  9.7   74     6   2
## 34     NA     242 16.1   67     6   3
## 35     NA     186  9.2   84     6   4
## 36     NA     220  8.6   85     6   5
## 37     NA     264 14.3   79     6   6
## 39     NA     273  6.9   87     6   8
## 42     NA     259 10.9   93     6  11
## 43     NA     250  9.2   92     6  12
## 45     NA     332 13.8   80     6  14
## 46     NA     322 11.5   79     6  15
## 52     NA     150  6.3   77     6  21
## 53     NA      59  1.7   76     6  22
## 54     NA      91  4.6   76     6  23
## 55     NA     250  6.3   76     6  24
## 56     NA     135  8.0   75     6  25
## 57     NA     127  8.0   78     6  26
## 58     NA      47 10.3   73     6  27
## 59     NA      98 11.5   80     6  28
## 60     NA      31 14.9   77     6  29
## 61     NA     138  8.0   83     6  30
## 65     NA     101 10.9   84     7   4
## 72     NA     139  8.6   82     7  11
## 75     NA     291 14.9   91     7  14
## 83     NA     258  9.7   81     7  22
## 84     NA     295 11.5   82     7  23
## 96     78      NA  6.9   86     8   4
## 97     35      NA  7.4   85     8   5
## 98     66      NA  4.6   87     8   6
## 102    NA     222  8.6   92     8  10
## 103    NA     137 11.5   86     8  11
## 107    NA      64 11.5   79     8  15
## 115    NA     255 12.6   75     8  23
## 119    NA     153  5.7   88     8  27
## 150    NA     145 13.2   77     9  27
# Заполнение медианой
pPmI <- preProcess(airquality, method = "medianImpute")
airquality_imp <- predict(pPmI, airquality)

# Сравнение: строки ДО и ПОСЛЕ (медиана)
airquality[ind, ]
##     Ozone Solar.R Wind Temp Month Day
## 5      NA      NA 14.3   56     5   5
## 6      28      NA 14.9   66     5   6
## 10     NA     194  8.6   69     5  10
## 11      7      NA  6.9   74     5  11
## 25     NA      66 16.6   57     5  25
## 26     NA     266 14.9   58     5  26
## 27     NA      NA  8.0   57     5  27
## 32     NA     286  8.6   78     6   1
## 33     NA     287  9.7   74     6   2
## 34     NA     242 16.1   67     6   3
## 35     NA     186  9.2   84     6   4
## 36     NA     220  8.6   85     6   5
## 37     NA     264 14.3   79     6   6
## 39     NA     273  6.9   87     6   8
## 42     NA     259 10.9   93     6  11
## 43     NA     250  9.2   92     6  12
## 45     NA     332 13.8   80     6  14
## 46     NA     322 11.5   79     6  15
## 52     NA     150  6.3   77     6  21
## 53     NA      59  1.7   76     6  22
## 54     NA      91  4.6   76     6  23
## 55     NA     250  6.3   76     6  24
## 56     NA     135  8.0   75     6  25
## 57     NA     127  8.0   78     6  26
## 58     NA      47 10.3   73     6  27
## 59     NA      98 11.5   80     6  28
## 60     NA      31 14.9   77     6  29
## 61     NA     138  8.0   83     6  30
## 65     NA     101 10.9   84     7   4
## 72     NA     139  8.6   82     7  11
## 75     NA     291 14.9   91     7  14
## 83     NA     258  9.7   81     7  22
## 84     NA     295 11.5   82     7  23
## 96     78      NA  6.9   86     8   4
## 97     35      NA  7.4   85     8   5
## 98     66      NA  4.6   87     8   6
## 102    NA     222  8.6   92     8  10
## 103    NA     137 11.5   86     8  11
## 107    NA      64 11.5   79     8  15
## 115    NA     255 12.6   75     8  23
## 119    NA     153  5.7   88     8  27
## 150    NA     145 13.2   77     9  27
airquality_imp[ind, ]
##     Ozone Solar.R Wind Temp Month Day
## 5    31.5     205 14.3   56     5   5
## 6    28.0     205 14.9   66     5   6
## 10   31.5     194  8.6   69     5  10
## 11    7.0     205  6.9   74     5  11
## 25   31.5      66 16.6   57     5  25
## 26   31.5     266 14.9   58     5  26
## 27   31.5     205  8.0   57     5  27
## 32   31.5     286  8.6   78     6   1
## 33   31.5     287  9.7   74     6   2
## 34   31.5     242 16.1   67     6   3
## 35   31.5     186  9.2   84     6   4
## 36   31.5     220  8.6   85     6   5
## 37   31.5     264 14.3   79     6   6
## 39   31.5     273  6.9   87     6   8
## 42   31.5     259 10.9   93     6  11
## 43   31.5     250  9.2   92     6  12
## 45   31.5     332 13.8   80     6  14
## 46   31.5     322 11.5   79     6  15
## 52   31.5     150  6.3   77     6  21
## 53   31.5      59  1.7   76     6  22
## 54   31.5      91  4.6   76     6  23
## 55   31.5     250  6.3   76     6  24
## 56   31.5     135  8.0   75     6  25
## 57   31.5     127  8.0   78     6  26
## 58   31.5      47 10.3   73     6  27
## 59   31.5      98 11.5   80     6  28
## 60   31.5      31 14.9   77     6  29
## 61   31.5     138  8.0   83     6  30
## 65   31.5     101 10.9   84     7   4
## 72   31.5     139  8.6   82     7  11
## 75   31.5     291 14.9   91     7  14
## 83   31.5     258  9.7   81     7  22
## 84   31.5     295 11.5   82     7  23
## 96   78.0     205  6.9   86     8   4
## 97   35.0     205  7.4   85     8   5
## 98   66.0     205  4.6   87     8   6
## 102  31.5     222  8.6   92     8  10
## 103  31.5     137 11.5   86     8  11
## 107  31.5      64 11.5   79     8  15
## 115  31.5     255 12.6   75     8  23
## 119  31.5     153  5.7   88     8  27
## 150  31.5     145 13.2   77     9  27
# Заполнение средним (ручной способ, так как meanImpute отсутствует в caret)
airquality_mean <- airquality
airquality_mean$Ozone[is.na(airquality_mean$Ozone)] <- mean(airquality$Ozone, na.rm = TRUE)
airquality_mean$Solar.R[is.na(airquality_mean$Solar.R)] <- mean(airquality$Solar.R, na.rm = TRUE)

# Сравнение строк после заполнения средним
airquality_mean[ind, ]
##        Ozone  Solar.R Wind Temp Month Day
## 5   42.12931 185.9315 14.3   56     5   5
## 6   28.00000 185.9315 14.9   66     5   6
## 10  42.12931 194.0000  8.6   69     5  10
## 11   7.00000 185.9315  6.9   74     5  11
## 25  42.12931  66.0000 16.6   57     5  25
## 26  42.12931 266.0000 14.9   58     5  26
## 27  42.12931 185.9315  8.0   57     5  27
## 32  42.12931 286.0000  8.6   78     6   1
## 33  42.12931 287.0000  9.7   74     6   2
## 34  42.12931 242.0000 16.1   67     6   3
## 35  42.12931 186.0000  9.2   84     6   4
## 36  42.12931 220.0000  8.6   85     6   5
## 37  42.12931 264.0000 14.3   79     6   6
## 39  42.12931 273.0000  6.9   87     6   8
## 42  42.12931 259.0000 10.9   93     6  11
## 43  42.12931 250.0000  9.2   92     6  12
## 45  42.12931 332.0000 13.8   80     6  14
## 46  42.12931 322.0000 11.5   79     6  15
## 52  42.12931 150.0000  6.3   77     6  21
## 53  42.12931  59.0000  1.7   76     6  22
## 54  42.12931  91.0000  4.6   76     6  23
## 55  42.12931 250.0000  6.3   76     6  24
## 56  42.12931 135.0000  8.0   75     6  25
## 57  42.12931 127.0000  8.0   78     6  26
## 58  42.12931  47.0000 10.3   73     6  27
## 59  42.12931  98.0000 11.5   80     6  28
## 60  42.12931  31.0000 14.9   77     6  29
## 61  42.12931 138.0000  8.0   83     6  30
## 65  42.12931 101.0000 10.9   84     7   4
## 72  42.12931 139.0000  8.6   82     7  11
## 75  42.12931 291.0000 14.9   91     7  14
## 83  42.12931 258.0000  9.7   81     7  22
## 84  42.12931 295.0000 11.5   82     7  23
## 96  78.00000 185.9315  6.9   86     8   4
## 97  35.00000 185.9315  7.4   85     8   5
## 98  66.00000 185.9315  4.6   87     8   6
## 102 42.12931 222.0000  8.6   92     8  10
## 103 42.12931 137.0000 11.5   86     8  11
## 107 42.12931  64.0000 11.5   79     8  15
## 115 42.12931 255.0000 12.6   75     8  23
## 119 42.12931 153.0000  5.7   88     8  27
## 150 42.12931 145.0000 13.2   77     9  27

Задание 5

Сгенерируйте два числовых набора данных и добавьте в них выбросы. С использованием функции boxplot обнаружьте выбросы и удалить их [3, 4].

set.seed(123)

# Создаём базовые данные
data_a <- rnorm(50, mean = 10)
data_b <- rnorm(50, mean = 20)

# Добавляем выбросы
data_a <- c(data_a, 100, 120)
data_b <- c(data_b, -50, -70)

# Обнаружение выбросов
outliers_a <- boxplot.stats(data_a)$out
outliers_b <- boxplot.stats(data_b)$out

outliers_a
## [1] 100 120
outliers_b
## [1]  17.69083 -50.00000 -70.00000
# Визуализация с указанием выбросов
boxplot(data_a, main = "Data A")
mtext(paste("Выбросы:", paste(outliers_a, collapse=", ")), cex=0.7)

boxplot(data_b, main = "Data B")
mtext(paste("Выбросы:", paste(outliers_b, collapse=", ")), cex=0.7)

# Удаление выбросов
clean_a <- data_a[!data_a %in% outliers_a]
clean_b <- data_b[!data_b %in% outliers_b]

# Сравнение ДО и ПОСЛЕ
par(mfrow=c(1,2))
boxplot(data_a, main = "До удаления")
boxplot(clean_a, main = "После удаления")

Задание 6

Сгенерируйте таблицу данных, в которой дублируются строки. Удалите строки с использованием функций unique(), duplicated(). Сравните результаты [5].

# Создание таблицы с дублирующимися строками (строки 2-3 и 5-6 дублируются)
df_dup <- data.frame(
  x = c(1, 2, 2, 3, 4, 4),
  y = c("A", "B", "B", "C", "D", "D")
)

df_dup # Исходная таблица с дубликатами
##   x y
## 1 1 A
## 2 2 B
## 3 2 B
## 4 3 C
## 5 4 D
## 6 4 D
# Способ 1: unique() - возвращает уникальные строки
unique_df <- unique(df_dup)
# Способ 2: duplicated() - логический вектор, FALSE для первых вхождений
dup_removed <- df_dup[!duplicated(df_dup), ]

# Проверка, что результаты совпадают
identical(unique_df, dup_removed)
## [1] TRUE

Разница между методами: unique(): Просто возвращает уникальные строки Не показывает процесс отбора Удобно для быстрого результата

duplicated(): Показывает, какие строки дублируются !duplicated() оставляет только первые вхождения Дает больше контроля и информации

Задание 7

Обработайте пропуски в данных с использованием пакета mice [6].

# Применяем mice к airquality
imp <- mice(airquality, m = 2, maxit = 10, method = "pmm", seed = 123)
## 
##  iter imp variable
##   1   1  Ozone  Solar.R
##   1   2  Ozone  Solar.R
##   2   1  Ozone  Solar.R
##   2   2  Ozone  Solar.R
##   3   1  Ozone  Solar.R
##   3   2  Ozone  Solar.R
##   4   1  Ozone  Solar.R
##   4   2  Ozone  Solar.R
##   5   1  Ozone  Solar.R
##   5   2  Ozone  Solar.R
##   6   1  Ozone  Solar.R
##   6   2  Ozone  Solar.R
##   7   1  Ozone  Solar.R
##   7   2  Ozone  Solar.R
##   8   1  Ozone  Solar.R
##   8   2  Ozone  Solar.R
##   9   1  Ozone  Solar.R
##   9   2  Ozone  Solar.R
##   10   1  Ozone  Solar.R
##   10   2  Ozone  Solar.R
airquality_mice <- complete(imp)

# Сравнение ДО и ПОСЛЕ
print(head(airquality))
##   Ozone Solar.R Wind Temp Month Day
## 1    41     190  7.4   67     5   1
## 2    36     118  8.0   72     5   2
## 3    12     149 12.6   74     5   3
## 4    18     313 11.5   62     5   4
## 5    NA      NA 14.3   56     5   5
## 6    28      NA 14.9   66     5   6
print(colSums(is.na(airquality)))
##   Ozone Solar.R    Wind    Temp   Month     Day 
##      37       7       0       0       0       0
print(head(airquality_mice))
##   Ozone Solar.R Wind Temp Month Day
## 1    41     190  7.4   67     5   1
## 2    36     118  8.0   72     5   2
## 3    12     149 12.6   74     5   3
## 4    18     313 11.5   62     5   4
## 5     6     273 14.3   56     5   5
## 6    28     186 14.9   66     5   6
print(colSums(is.na(airquality_mice)))
##   Ozone Solar.R    Wind    Temp   Month     Day 
##       0       0       0       0       0       0

Преимущества MICE перед простой медианой: Учитывает контекст - значения зависят от других переменных Сохраняет вариативность - не все пропуски получают одинаковые значения Реалистичность - использует только существующие в данных значения

Задание 8

Разберите пример с мультиколлинеарностью [7].

# Создаем данные с мультиколлинеарностью (x2 сильно коррелирует с x1), проверяем корреляцию
set.seed(123)

x1 <- rnorm(100)
x2 <- x1 * 0.9 + rnorm(100, sd = 0.1)  # x2 коррелирует с x1
x3 <- rnorm(100)  # независимая переменная

df_multi <- data.frame(x1, x2, x3)
cor(df_multi)
##           x1         x2         x3
## x1  1.000000  0.9930810 -0.1291760
## x2  0.993081  1.0000000 -0.1254392
## x3 -0.129176 -0.1254392  1.0000000
# Регрессионная модель с мультиколлинеарностью
model <- lm(x1 ~ x2 + x3, data = df_multi)
summary(model)
## 
## Call:
## lm(formula = x1 ~ x2 + x3, data = df_multi)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.37309 -0.05931  0.01159  0.07465  0.21749 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  0.013165   0.010965   1.201    0.233    
## x2           1.101563   0.013329  82.646   <2e-16 ***
## x3          -0.004496   0.011540  -0.390    0.698    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1082 on 97 degrees of freedom
## Multiple R-squared:  0.9862, Adjusted R-squared:  0.9859 
## F-statistic:  3474 on 2 and 97 DF,  p-value: < 2.2e-16
# Расчет VIF (Variance Inflation Factor) - если VIF > 10, проблема мультиколлинеарности
vif(model)
##       x2       x3 
## 1.015987 1.015987

Вывод

В ходе лабораторной работы были изучены основные методы подготовки данных: очистка от пропусков, обработка выбросов, удаление дубликатов и анализ мультиколлинеарности.