В данной работе рассматриваются методы очистки и предобработки данных в R:
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. Сводка показывает минимум, максимум, медиану и количество пропусков.
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() позволяет отфильтровать отсутствующие значения.
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 строки). Метод удобен для быстрого фильтра.
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 позволяет автоматизировать медианное заполнение.
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 до и после очистки наглядно показывает уменьшение экстремальных значений.
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 строк
Вывод: Оба метода позволяют удалить дублирующиеся строки. Результаты идентичны.
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 больше нет, а график показывает распределение реальных и вмененных данных.
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 для надежной предобработки данных перед анализом или построением моделей.