Введение

В данной работе рассматриваются методы очистки и предобработки данных в R:


Задание 1. Собственный вектор с NA

my_vector <- c(10, 25, NA, 47, NA, 63, 8, NA, 99, 12)
cat("Исходный вектор:\n")
## Исходный вектор:
print(my_vector)
##  [1] 10 25 NA 47 NA 63  8 NA 99 12
cat("Количество элементов:", length(my_vector), "\n")
## Количество элементов: 10
summary(my_vector)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.     NAs 
##    8.00   11.00   25.00   37.71   55.00   99.00       3

Вывод: Вектор содержит 10 элементов, из которых 3 являются NA. Сводка показывает минимум, максимум, медиану и количество пропусков.


Задание 2. Очистка через is.na()

clean_vector <- my_vector[!is.na(my_vector)]
cat("=== Чистый вектор ===\n")
## === Чистый вектор ===
print(clean_vector)
## [1] 10 25 47 63  8 99 12
cat("Удалено NA:", sum(is.na(my_vector)), "\n")
## Удалено NA: 3

Вывод: Пропуски удалены, чистый вектор содержит 7 элементов. Метод is.na() позволяет отфильтровать отсутствующие значения.


Задание 3. Таблица данных и complete.cases()

df_raw <- data.frame(
  name   = c("Alex", "Maria", NA, "Ivan", "Olga", NA, "Petr"),
  age    = c(25, NA, 30, 45, NA, 28, 33),
  salary = c(50000, 60000, NA, 80000, 55000, NA, 70000)
)
cat("=== Исходная таблица ===\n")
## === Исходная таблица ===
print(df_raw)
##    name age salary
## 1  Alex  25  50000
## 2 Maria  NA  60000
## 3  <NA>  30     NA
## 4  Ivan  45  80000
## 5  Olga  NA  55000
## 6  <NA>  28     NA
## 7  Petr  33  70000
complete_mask <- complete.cases(df_raw)
df_clean <- df_raw[complete_mask, ]
cat("\n=== Чистая таблица ===\n")
## 
## === Чистая таблица ===
print(df_clean)
##   name age salary
## 1 Alex  25  50000
## 4 Ivan  45  80000
## 7 Petr  33  70000

Вывод: Используя complete.cases(), оставлены только строки без пропусков (3 строки). Метод удобен для быстрого фильтра.


Задание 4. Заполнение пропусков через preProcess (caret)

library(caret)
prep_median <- preProcess(airquality, method = "medianImpute")
data_median <- predict(prep_median, airquality)
colSums(is.na(data_median))
##   Ozone Solar.R    Wind    Temp   Month     Day 
##       0       0       0       0       0       0
# Заполнение средним вручную
data_mean <- airquality
for (col in names(data_mean)) {
  if (is.numeric(data_mean[[col]])) {
    col_mean <- mean(data_mean[[col]], na.rm = TRUE)
    data_mean[[col]][is.na(data_mean[[col]])] <- col_mean
  }
}
colSums(is.na(data_mean))
##   Ozone Solar.R    Wind    Temp   Month     Day 
##       0       0       0       0       0       0
comparison <- data.frame(
  Original = airquality$Ozone[1:10],
  Median   = data_median$Ozone[1:10],
  Mean     = round(data_mean$Ozone[1:10],1)
)
comparison
##    Original Median Mean
## 1        41   41.0 41.0
## 2        36   36.0 36.0
## 3        12   12.0 12.0
## 4        18   18.0 18.0
## 5        NA   31.5 42.1
## 6        28   28.0 28.0
## 7        23   23.0 23.0
## 8        19   19.0 19.0
## 9         8    8.0  8.0
## 10       NA   31.5 42.1

Вывод: Пропуски в датасете airquality заполнены медианой и средним. После обработки NA больше нет. Использование caret позволяет автоматизировать медианное заполнение.


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

set.seed(42)
set1 <- c(rnorm(50, 100, 10), 200, 250, -50)
set2 <- c(rnorm(50, 50, 5), 150, -20, 160)

outliers1 <- boxplot.stats(set1)$out
outliers2 <- boxplot.stats(set2)$out

clean1 <- set1[!set1 %in% outliers1]
clean2 <- set2[!set2 %in% outliers2]

cat("Выбросы в наборе 1:", outliers1, "\n")
## Выбросы в наборе 1: 200 250 -50
cat("Выбросы в наборе 2:", outliers2, "\n")
## Выбросы в наборе 2: 35.03455 150 -20 160
cat("Набор 1: было", length(set1), "-> стало", length(clean1), "\n")
## Набор 1: было 53 -> стало 50
cat("Набор 2: было", length(set2), "-> стало", length(clean2), "\n")
## Набор 2: было 53 -> стало 49
par(mfrow=c(1,2))
boxplot(set1, main="Набор 1 (до)", col="lightblue")
boxplot(set2, main="Набор 2 (до)", col="lightyellow")

par(mfrow=c(1,2))
boxplot(clean1, main="Набор 1 (после)", col="lightgreen")
boxplot(clean2, main="Набор 2 (после)", col="lightpink")

par(mfrow=c(1,1))

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


Задание 6. Удаление дубликатов

df_dupes <- data.frame(
  product  = c("Apple","Banana","Apple","Pear","Banana","Orange","Apple"),
  price    = c(30,50,30,40,50,60,30),
  quantity = c(5,3,5,7,3,2,5)
)
df_unique <- unique(df_dupes)
dup_mask <- duplicated(df_dupes)
df_no_dup <- df_dupes[!dup_mask, ]
cat("Исходно:", nrow(df_dupes), "строк\n")
## Исходно: 7 строк
cat("После unique():", nrow(df_unique), "строк\n")
## После unique(): 4 строк
cat("После duplicated():", nrow(df_no_dup), "строк\n")
## После duplicated(): 4 строк

Вывод: Оба метода позволяют удалить дублирующиеся строки. Результаты идентичны.


Задание 7a. Множественное вменение через mice

library(mice)
imp <- mice(nhanes, m=5, method="pmm", seed=123, printFlag=FALSE)
filled_data <- complete(imp, 1)
colSums(is.na(filled_data))
## age bmi hyp chl 
##   0   0   0   0
stripplot(imp, pch=20, cex=1.5, main="Реальные (синие) vs вмененные (красные) значения")

Вывод: Пропуски успешно вменены множественным методом. В таблице NA больше нет, а график показывает распределение реальных и вмененных данных.


Задание 7b. Мультиколлинеарность

library(car)
model_full <- lm(mpg ~ wt + hp + disp + cyl, data=mtcars)
vif_full <- vif(model_full)
cat("VIF исходной модели:\n")
## VIF исходной модели:
print(round(vif_full,2))
##    wt    hp  disp   cyl 
##  4.85  3.41 10.37  6.74
model_clean <- lm(mpg ~ wt + hp, data=mtcars)
vif_clean <- vif(model_clean)
cat("VIF после удаления коллинеарных переменных:\n")
## VIF после удаления коллинеарных переменных:
print(round(vif_clean,2))
##   wt   hp 
## 1.77 1.77
pairs(mtcars[,c("mpg","wt","hp","disp","cyl")], main="Матрица корреляций", col="steelblue", pch=19)

Вывод: Изначально VIF для disp и cyl >5, что указывает на мультиколлинеарность. После удаления проблемных переменных VIF снизился <5, проблема устранена. Матрица корреляций визуально подтверждает сильные связи между признаками.


Общий вывод

В лабораторной работе изучены методы очистки данных:

Работа показала, как использовать встроенные функции R для надежной предобработки данных перед анализом или построением моделей.