Лабораторная работа №4 (R)

Обработка пропусков на наборе данных Palmer Penguins

Author

ФИО студента: ____________________

Published

September 26, 2025

Цель: на практике отработать выявление и обработку пропусков в реальном датасете palmerpenguins: диагностика пропусков, удаление, заполнение (медиана/мода), групповое заполнение по видам/островам, оценка эффекта на распределения и визуализации.

0. Подготовка окружения

# Установка пакетов при необходимости:
# install.packages(c("palmerpenguins", "tidyverse", "skimr", "naniar"))

library(tidyverse)      # dplyr, ggplot2, tidyr, readr, etc.
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.2     ✔ tibble    3.2.1
✔ lubridate 1.9.4     ✔ tidyr     1.3.1
✔ purrr     1.0.4     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(palmerpenguins) # данные о пингвинах

Attaching package: 'palmerpenguins'

The following objects are masked from 'package:datasets':

    penguins, penguins_raw
library(skimr)          # удобный обзор данных
library(naniar)         # визуализация и работа с пропусками

Attaching package: 'naniar'

The following object is masked from 'package:skimr':

    n_complete

1. Данные Palmer Penguins (кратко)

Набор данных о пингвинах с островов Палмер (Антарктика). Содержит измерения трёх видов пингвинов: Adélie, Chinstrap, Gentoo.
Ключевые переменные (с пропусками в некоторых столбцах): - species — вид, - island — остров, - bill_length_mm, bill_depth_mm — длина и глубина клюва (мм), - flipper_length_mm — длина плавника (мм), - body_mass_g — масса тела (г), - sex — пол, - year — год наблюдения.

data(penguins)
penguins |> head()

2. Теория (шпаргалка по пропускам)

2.1. Почему возникают пропуски и почему их важно обрабатывать?

  • Ошибки/особенности сбора: недоступные измерения, потерянные записи.
  • Большинство алгоритмов и функций плохо работают с NA.
  • Стратегия зависит от природы данных: случайные пропуски (MCAR), зависящие от наблюдаемых переменных (MAR), или неслучайные (MNAR).

2.2. Диагностика пропусков

# Подсчёт пропусков по столбцам
colSums(is.na(penguins))
          species            island    bill_length_mm     bill_depth_mm 
                0                 0                 2                 2 
flipper_length_mm       body_mass_g               sex              year 
                2                 2                11                 0 
# Быстрый профиль
skimr::skim(penguins)
Data summary
Name penguins
Number of rows 344
Number of columns 8
_______________________
Column type frequency:
factor 3
numeric 5
________________________
Group variables None

Variable type: factor

skim_variable n_missing complete_rate ordered n_unique top_counts
species 0 1.00 FALSE 3 Ade: 152, Gen: 124, Chi: 68
island 0 1.00 FALSE 3 Bis: 168, Dre: 124, Tor: 52
sex 11 0.97 FALSE 2 mal: 168, fem: 165

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
bill_length_mm 2 0.99 43.92 5.46 32.1 39.23 44.45 48.5 59.6 ▃▇▇▆▁
bill_depth_mm 2 0.99 17.15 1.97 13.1 15.60 17.30 18.7 21.5 ▅▅▇▇▂
flipper_length_mm 2 0.99 200.92 14.06 172.0 190.00 197.00 213.0 231.0 ▂▇▃▅▂
body_mass_g 2 0.99 4201.75 801.95 2700.0 3550.00 4050.00 4750.0 6300.0 ▃▇▆▃▂
year 0 1.00 2008.03 0.82 2007.0 2007.00 2008.00 2009.0 2009.0 ▇▁▇▁▇
# Тепловая карта пропусков
naniar::gg_miss_var(penguins) + ggtitle("Доля пропусков по столбцам")

naniar::vis_miss(penguins) + ggtitle("Карта пропусков (NA)")

2.3. Базовые стратегии

  • Удаление строк/столбцов: drop_na() / select(-cols) — просто, но теряем данные и можем получить смещение.
  • Заполнение константой: replace_na(list(col = value)) — быстро, но может искажать распределения.
  • Заполнение статистиками: медиана/среднее для числовых, мода для категориальных.
  • Групповое заполнение: учитывает зависимость от групп (например, по species или island).

2.4. Практические рецепты в R

library(dplyr)
library(tidyr)
library(forcats)

# Удаление строк с NA хотя бы в одном из выбранных столбцов
penguins_drop <- penguins |> drop_na(bill_length_mm, bill_depth_mm)

# Заполнение константами
penguins_const <- penguins |>
  mutate(sex = fct_explicit_na(sex, na_level = "unknown"))
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `sex = fct_explicit_na(sex, na_level = "unknown")`.
Caused by warning:
! `fct_explicit_na()` was deprecated in forcats 1.0.0.
ℹ Please use `fct_na_value_to_level()` instead.
# Заполнение «модой» (часто встречающееся значение) для фактора/характера
mode_val <- function(x) { 
  ux <- na.omit(x); if (length(ux) == 0) return(NA)
  names(sort(table(ux), decreasing = TRUE))[1]
}

penguins_mode <- penguins |> 
  mutate(
    sex = if_else(is.na(sex), mode_val(sex), sex)
  )

# Заполнение медианой по всему столбцу
medians <- penguins |> summarise(across(where(is.numeric), ~median(.x, na.rm = TRUE)))
penguins_med <- penguins |> mutate(across(where(is.numeric), ~replace_na(.x, medians[[cur_column()]])))

# Групповая медиана по виду (species)
penguins_group_med <- penguins |>
  group_by(species) |>
  mutate(across(where(is.numeric), ~if_else(is.na(.x), median(.x, na.rm = TRUE), .x))) |>
  ungroup()

2.5. Как оценивать эффект заполнения?

  • Сравнивайте распределения до/после: summary(), skim(), гистограммы, boxplot.
  • Смотрите средние/медианы/дисперсии по группам: они не должны резко «ломаться».
  • Фиксируйте выбранную стратегию и аргументы, чтобы обеспечить воспроизводимость.
# Пример: сравнение медиан по виду до/после
penguins |> group_by(species) |> summarise(med_bill_len = median(bill_length_mm, na.rm = TRUE))
penguins_group_med |> group_by(species) |> summarise(med_bill_len = median(bill_length_mm, na.rm = TRUE))

3. Задания

Часть A. Диагностика

  1. Выведите таблицу количества пропусков по всем столбцам (в убывающем порядке).
  2. Постройте gg_miss_var и vis_miss для наглядности. Кратко опишите, где пропусков больше всего.

Часть B. Базовые подходы

  1. Сформируйте датасет без пропусков в числовых столбцах bill_length_mm, bill_depth_mm, flipper_length_mm, body_mass_g (используйте drop_na). Сравните размерность с исходной.
  2. Заполните sex модой по всему набору. Сравните распределение sex до/после (bar chart).

Часть C. Заполнение статистиками

  1. Заполните все числовые столбцы медианами (по всему столбцу). Постройте гистограмму bill_length_mm до/после заполнения в одном окне (фасеты или цвет).
  2. Выполните групповое заполнение медианой по species для числовых столбцов. Сравните медианы body_mass_g по species до/после (таблица из 2–3 строк на вид).

Часть D. Сравнение стратегий

  1. Сравните три версии датасета:
    1. исходный с пропусками,
    2. глобальная медиана,
    3. групповая медиана по species.
      Для каждого варианта посчитайте среднее и медиану bill_depth_mm по species, выведите аккуратную таблицу (pivot_wider).

Часть E. Визуализация (мини-отчёт)

  1. Постройте boxplot body_mass_g по species и sex для набора после группового заполнения. Добавьте подписи, легенду, тему.
  2. Сохраните 2–3 ключевых графика (ggsave()) и укажите их в выводах.

Контрольные вопросы

  1. Чем отличаются стратегии drop_na() и заполнение медианой? Когда что предпочтительнее?
  2. Почему групповое заполнение может быть лучше глобального? Приведите пример из набора пингвинов.
  3. Какие риски несёт замена пропусков модой для категориальных признаков?
  4. Что такое MCAR/MAR/MNAR? Как это влияет на выбор стратегии?
  5. Какие графики вы используете для оценки эффектов заполнения и почему?