Цель работы — изучить методы обработки пропусков, удаления выбросов, устранения дубликатов и выявления мультиколлинеарности в языке R.
Создадим числовой вектор, содержащий пропущенные значения.
data_vec <- c(5, 12, NA, 18, 21, NA, 30, 42)
data_vec
## [1] 5 12 NA 18 21 NA 30 42
Пояснение:
Функция c() объединяет значения в один вектор. Значения
NA обозначают пропуски.
Определим позиции пропусков и удалим их.
is.na(data_vec)
## [1] FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE
clean_vec <- data_vec[!is.na(data_vec)]
clean_vec
## [1] 5 12 18 21 30 42
Пояснение:
is.na() возвращает TRUE для пропусков.
Используя логическое отрицание !, мы оставляем только
реальные значения.
Сформируем таблицу, содержащую пропуски.
df_mixed <- data.frame(
id = c(1, 2, 3, 4, 5, 6),
score = c(80, NA, 95, 88, NA, 77),
name = c("Anna", "Bob", "Chris", NA, "Diana", "Eva")
)
df_mixed
## id score name
## 1 1 80 Anna
## 2 2 NA Bob
## 3 3 95 Chris
## 4 4 88 <NA>
## 5 5 NA Diana
## 6 6 77 Eva
Удалим строки с пропусками:
complete.cases(df_mixed)
## [1] TRUE FALSE TRUE FALSE FALSE TRUE
df_mixed_clean <- df_mixed[complete.cases(df_mixed), ]
df_mixed_clean
## id score name
## 1 1 80 Anna
## 3 3 95 Chris
## 6 6 77 Eva
Пояснение:
complete.cases() возвращает TRUE только для строк без
NA.
Таким образом остаются полностью заполненные строки.
Загрузим данные и посмотрим количество пропусков.
library(caret)
data(airquality)
summary(airquality)
## Ozone Solar.R 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
## Month Day
## Min. :5.000 Min. : 1.0
## 1st Qu.:6.000 1st Qu.: 8.0
## Median :7.000 Median :16.0
## Mean :6.993 Mean :15.8
## 3rd Qu.:8.000 3rd Qu.:23.0
## Max. :9.000 Max. :31.0
##
colSums(is.na(airquality))
## Ozone Solar.R Wind Temp Month Day
## 37 7 0 0 0 0
air_mean <- airquality
num_cols <- sapply(air_mean, is.numeric)
for (col in names(air_mean)[num_cols]) {
air_mean[[col]][is.na(air_mean[[col]])] <- mean(air_mean[[col]], na.rm = TRUE)
}
colSums(is.na(air_mean))
## Ozone Solar.R Wind Temp Month Day
## 0 0 0 0 0 0
air_median <- airquality
for (col in names(air_median)[num_cols]) {
air_median[[col]][is.na(air_median[[col]])] <- median(air_median[[col]], na.rm = TRUE)
}
colSums(is.na(air_median))
## Ozone Solar.R Wind Temp Month Day
## 0 0 0 0 0 0
Пояснение:
Среднее чувствительно к выбросам.
Медиана более устойчива и часто используется при наличии экстремальных
значений.
Создадим два набора данных и добавим искусственные выбросы.
set.seed(100)
a <- c(rnorm(40, mean=10, sd=2), 35, 40)
b <- c(rnorm(40, mean=100, sd=8), 180, 220)
Построим boxplot:
boxplot(a, main="Набор A с выбросами")
boxplot(b, main="Набор B с выбросами")
Пояснение графика:
Точки за пределами “усов” boxplot являются выбросами.
Определим выбросы:
out_a <- boxplot.stats(a)$out
out_b <- boxplot.stats(b)$out
out_a
## [1] 35 40
out_b
## [1] 180 220
Удалим выбросы:
a_clean <- a[!(a %in% out_a)]
b_clean <- b[!(b %in% out_b)]
boxplot(a_clean, main="Набор A без выбросов")
boxplot(b_clean, main="Набор B без выбросов")
Вывод:
После удаления экстремальных значений распределение становится более
компактным и симметричным.
Создадим таблицу с повторяющимися строками.
dup_table <- data.frame(
id = c(1,2,2,3,4,4,5),
name = c("A","B","B","C","D","D","E")
)
dup_table
## id name
## 1 1 A
## 2 2 B
## 3 2 B
## 4 3 C
## 5 4 D
## 6 4 D
## 7 5 E
Удаление через unique():
unique_rows <- unique(dup_table)
unique_rows
## id name
## 1 1 A
## 2 2 B
## 4 3 C
## 5 4 D
## 7 5 E
Удаление через duplicated():
no_dups <- dup_table[!duplicated(dup_table), ]
no_dups
## id name
## 1 1 A
## 2 2 B
## 4 3 C
## 5 4 D
## 7 5 E
Сравнение:
identical(unique_rows, no_dups)
## [1] TRUE
Вывод:
Обе функции дают одинаковый результат — остаются только уникальные
строки.
library(mice)
df_na <- data.frame(
x1 = c(10, 15, NA, 20, 25),
x2 = c(NA, 5, 7, 9, 11)
)
df_na
## x1 x2
## 1 10 NA
## 2 15 5
## 3 NA 7
## 4 20 9
## 5 25 11
Импутация методом pmm:
imp <- mice(df_na, m=3, method="pmm", seed=100)
##
## iter imp variable
## 1 1 x1 x2
## 1 2 x1 x2
## 1 3 x1 x2
## 2 1 x1 x2
## 2 2 x1 x2
## 2 3 x1 x2
## 3 1 x1 x2
## 3 2 x1 x2
## 3 3 x1 x2
## 4 1 x1 x2
## 4 2 x1 x2
## 4 3 x1 x2
## 5 1 x1 x2
## 5 2 x1 x2
## 5 3 x1 x2
completed <- complete(imp, 1)
completed
## x1 x2
## 1 10 9
## 2 15 5
## 3 15 7
## 4 20 9
## 5 25 11
Пояснение:
mice использует множественную импутацию, восстанавливая
пропуски на основе других переменных.
Создадим переменные с высокой корреляцией.
set.seed(123)
n <- 100
x1 <- rnorm(n)
x2 <- x1 * 0.9 + rnorm(n, sd=0.1)
x3 <- rnorm(n)
y <- 2*x1 + rnorm(n)
mc_df <- data.frame(y, x1, x2, x3)
cor(mc_df[,2:4])
## 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(y ~ x1 + x2 + x3, data=mc_df)
summary(model)
##
## Call:
## lm(formula = y ~ x1 + x2 + x3, data = mc_df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.49138 -0.65392 0.05664 0.67033 2.53210
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.01933 0.10734 -0.180 0.858
## x1 1.52859 0.98666 1.549 0.125
## x2 0.46218 1.09456 0.422 0.674
## x3 -0.05739 0.11223 -0.511 0.610
##
## Residual standard error: 1.052 on 96 degrees of freedom
## Multiple R-squared: 0.7474, Adjusted R-squared: 0.7395
## F-statistic: 94.69 on 3 and 96 DF, p-value: < 2.2e-16
Проверим VIF:
if (!requireNamespace("car", quietly = TRUE)) install.packages("car")
library(car)
vif(model)
## x1 x2 x3
## 72.628674 72.558466 1.017576
Пояснение:
Если VIF > 5 (или 10), это указывает на мультиколлинеарность.
В нашем случае x1 и x2 сильно коррелируют, что подтверждается высоким
VIF.
В ходе работы были изучены методы: - очистки пропусков, - удаления выбросов, - устранения дубликатов, - импутации с помощью mice, - выявления мультиколлинеарности.
Полученные результаты демонстрируют важность предварительной обработки данных перед построением моделей.