Пресса

Как говорится, не читайте советских западных газет перед обедом… Почему? Потому как после прочтения вам совершенно точно будет страшно и можно заработать несварение. Вот лишь некоторые заголовки на тему атак дронов на НПЗ:

  • Bloomberg: Russian diesel exports continue to drop amid Ukrainian drone strikes on oil refineries - The Kyiv Independent

Экспорт дизеля продолжает падать на фоне ударов дронов по НПЗ

  • The New York Times: Ukraine Strikes More Russian Oil Facilities in a Bid to Disrupt Military Logistics

Еще больше НПЗ подверглись украинским ударам в попытке разрушения военной логистики

  • France24: Ukraine’s drone attacks on Russian oil refineries cause domestic petrol prices to surge - bne IntelliNews

Украинские атаки дронов вызвали скачок внутренних цен на топливо

В общем под впечатлением прочитанного я отправился на ближайшую заправку и залил полный бак 95-го бензина по цене ниже 50 рублей в Питере. В этом конкретном случае была какая-то скидка, но по 55 я бы точно заправился и без скидок. Осознав некоторое несоответствие прочитанного с реальным физическим миром, я решил разобраться и посмотреть объективные данные.

Нефтепродукты

К счастью, в Росстате можно найти данные по реальному производству бензина и дизелного топлива. Учет ведется в недельном разрезе. Как заведено в нашем статистическом ведомстве за несколько лет они умудрились несколько раз изменить схему индикации временного периода. Не удивительно, что в интернете сложно найти толковый график, который хоть как-то бы мог прояснить ситуацию.

К сожалению, даже после приведения в порядок временных меток остались некоторые косяки (за двоения) и наоборот пропуски, которые удалось аккуратно починить. Людям, которые много работают с данными известно, что данные не бывают идеальными, но многим, кто далек от этой области хочется обслуживать свои собственные заблуждения и внутренние установки. Последние могут считать, что Росстат фсе врет и это их личное дело.

Не вижу смысла показывать промежуточные итоги и сразу перейду к финальной версии графика:

Выводы

  • Ничего аномального в производстве бензина и дизельного топлива не выявлено: февраль чуть выше среднего за 5 лет, март где-то в области среднего
  • Вероятно, какие-то последствия имеются, но ощутить их будет трудно
  • Продолжаю читать западную прессу и искать вдохновений для новых заметок

Исходный код заметки
# Необходимые библиотеки
library(dplyr)
library(stringi)
library(lubridate)
library(ggplot2)

# Загрузка данных с использованием пакета fedstatAPIr
# fedstatAPIr::fedstat_data_load_with_filters("57843") |> 
# fst::write_fst("data/prod.fst")
# Загрузка предварительно сохраненных данных 
oil_prod <- fst::read_fst("data/prod.fst")
attacks <- readxl::read_excel("data/oil_refine_attacks.xlsx")

# Месяцы в родительном падеже 
months_genitive <- c("января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря")
# Присвоение порядкового номера к месяцу для дальнейшей обработке
mnth_rcd <- 1:12 |> `names<-`(months_genitive)

# Магия с регулярными выражениями для получения приемлемого формата дат
oil_prod1 <- oil_prod |> 
  mutate(month0 = stri_extract_all(PERIOD, regex = paste0(months_genitive, collapse = "|"))) |> 
  mutate(month_start = sapply(month0, \(x)x[1]) |> dplyr::recode(!!!mnth_rcd), 
      month_finish = sapply(month0, \(x)x[2]) |> dplyr::recode(!!!mnth_rcd)) |>
  mutate(month_finish = ifelse(is.na(month_finish), month_start,month_finish)) |> 
  mutate(week_expr = stri_extract(PERIOD, regex = "\\d{1,2} неделя"),
      month_day_start =  stri_extract(PERIOD, regex = "(с|С|со|c) \\d{1,2}") |> stri_replace(regex = "(с|С|со|c) ", "") |> as.numeric(),
      month_day_finish =  stri_extract(PERIOD, regex = "по \\d{1,2}") |> stri_replace(fixed = "по ", "") |> as.numeric())  |> 
  mutate(week_n = stri_replace(week_expr, fixed = " неделя", "") |> as.numeric()) |> 
  mutate(year_day_start = week_n*7-7, 
      year_day_finish = week_n*7-1) |> 
  mutate(start1 = ymd(paste0(Time, "-01-01")) + year_day_start, 
      finish1 = ymd(paste0(Time, "-01-01")) + year_day_finish) |> 
  mutate(start0 = ymd(paste0(Time, "-", month_start, "-", month_day_start)),
      finish0 = ymd(paste0(Time, "-", month_finish, "-", month_day_finish))) |> 
  mutate(start = if_else(is.na(start1), start0, start1),
      finish = if_else(is.na(finish1), finish0, finish1)) |> 
  mutate(finish = if_else(finish>start, finish, finish + 365)) |>
  mutate(duration = finish-start) |> 
  mutate(duration = if_else(duration<0, duration+365, duration)) |> 
  select(type = s_OKPD2, value = ObsValue, start, finish, duration)

# Распределение значений до дневного уровня гранулярности
oil_prod2 <- purrr::pmap_dfr(oil_prod1, ~{data.frame(type = ..1, 
                                    date = ..3 + seq_len(..5+1),
                                    value = ..2/(..5+1))}) 

# Агрегирование до уровня месяца 
oil_prod3 <- oil_prod2 |> 
  distinct(type, date, .keep_all = TRUE) |> # исключение некоторых дубликатов в статистике РОССТАТА
  mutate(year = year(date), day = yday(date), month = month(date)) |>
  group_by(type, year, month) |> 
  summarise(value = mean(value, na.rm = T), .groups = "drop") 

# Расчет среднего/максимального/минимального за последние 5 лет
oil_prod_avg <- filter(oil_prod3, year %in% 2019:2023) |>
  group_by(type, month) |> 
  summarise(max = max(value), min = min(value), value = mean(value), .groups = "drop") |> 
  mutate(year = 2024)

# Агрегирование количества атак по месяцам
attacks1 <- filter(attacks, attack== 1) |> 
  mutate(month = month(date)) |> 
  group_by(month) |> 
  summarise(attack = sum(attack)) |> 
  mutate(year = 2024)

# График
oil_prod3 |> 
  filter(year %in% 2021:2024) |> 
  ggplot(aes(x = month, y = value)) + 
  geom_col(aes(fill = type), alpha = .5, position = "dodge") + 
  geom_line(data = oil_prod_avg, aes(col = type)) +
  geom_ribbon(data = oil_prod_avg, aes(ymin = min, ymax=max, fill = type), alpha = .5, show.legend = F) +
  geom_point(data = attacks1, aes(y = 0, size = attack), alpha = .5) +
  facet_grid(year~type) +
  scale_x_continuous(labels = month.abb, breaks = 1:12) + 
  labs(col = "Среднее за 5 лет", fill = "Объем прозводства", size = "Атаки дронов", x = "Месяц", y = "Тысяча тонн", 
       title = "Объем производства бензина и дизильного топлива") + 
  guides(fill = guide_legend(nrow = 2, direction = "vertical"), col = guide_legend(nrow = 2, direction = "vertical"),
         size = guide_legend(nrow = 2, direction = "vertical"))+
  theme(legend.position = "top")

Простой способ узнать о новых публикациях – подписаться на Telegram-канал: