Вопрос или проблема
У меня есть следующий дата-фрейм:
Date.POSIXct Date WeekDay DayCategory Hour Holidays value
1 2018-05-01 00:00:00 2018-05-01 MA MA-MI-JU 0 0 30
2 2018-05-01 01:00:00 2018-05-01 MA MA-MI-JU 1 0 80
3 2018-05-01 02:00:00 2018-05-01 MA MA-MI-JU 2 0 42
4 2018-05-01 03:00:00 2018-05-01 MA MA-MI-JU 3 0 90
5 2018-05-01 04:00:00 2018-05-01 MA MA-MI-JU 4 0 95
6 2018-05-01 05:00:00 2018-05-01 MA MA-MI-JU 5 0 5
Категория дня группирует дни недели следующим образом: понедельники попадают в категорию LU
. Вторники, среды и четверги попадают в категорию MA-MI-JU
. Пятницы попадают в VI
, субботы в SA
и воскресенья в DO
соответственно.
Я хотел бы найти значение
для того же часа
в предыдущий день (Date
) с той же категорией дня
, при этом праздники
остаются в той же группе (например, если один экземпляр имеет праздник
0, но предыдущий день с той же категорией дня
имеет 1, нам нужно искать предыдущий и т.д.)
В качестве промежуточного шага, чтобы понять процесс, я хотел бы добавить столбец PreviousDaySameDayCategory
с Date
предыдущего дня, который имеет ту же категорию дня
, что и соответствующая строка. Иногда это будет просто та же дата
минус семь дней (“LU”,”VI”,”SA”,”DO”), но в другие дни это будет просто один день.
Воспроизводимые данные:
library(lubridate)
Date.POSIXct <- seq(as.POSIXct("2018-05-01"), as.POSIXct("2018-05-31"), "hour")
mydf <- as.data.frame(Date.POSIXct)
mydf$Date <- as.Date(substr(as.character(mydf$Date.POSIXct),1,10))
mydf$WeekDay <- substr(toupper((weekdays(mydf$Date))),1,2)
mydf$DayCategory <-as.factor(ifelse(mydf$WeekDay == "MA" | mydf$WeekDay == "MI" | mydf$WeekDay == "JU",
"MA-MI-JU", mydf$WeekDay))
mydf$Hour <- hour(mydf$Date.POSIXct)
mydf$Holidays <- c(rep(0, 24*7),rep(1, 24*7), rep(0, 24*16+1))
set.seed(123)
mydf$myvalue <- sample.int(101,size=nrow(mydf),replace=TRUE)
Я вручную начал первые дни и создал вектор, как должно выглядеть решение:
a <- rep(NA, 24)
b <- mydf$value[1:24]
c <- mydf$value[25:48]
d <- rep(NA, 24)
e <- rep(NA,24)
f <- rep(NA,24)
g <- rep(NA,24)
h <- rep(NA,24)
i <- mydf$value[169:192]
solution <- c(a,b,c,d,e,f,g,h,i)
solution
Я был бы признателен за любую подсказку в процессе мышления для решения подобных проблем, с которыми я сталкиваюсь относительно часто.
Я также опубликовал этот вопрос на Stack Over Flow, я думаю, что этот вид вопроса больше подходит для этого сообщества, чем для StackOverflow, верно? Я хотел бы удалить тот, который менее подходит для сообщества.
Если я вас правильно понимаю, вы хотите получить дату предыдущей той же категории дня, с тем же классом праздников, того же часа.
Если это так, возможно, вы можете попробовать:
1) Разделите строки по тому же часу, категории дня и группе праздников в одном кластере (или фильтре и т.д.)
2) Для каждого кластера, ранжируйте дату (первый день в группе – это 0, второй = 1 и т.д.) от наименьшего и т.д.
3) Для каждого ранга r, назначьте PreviousDaySameDayCategory, посмотрев на дату для строки r – 1, если r – 1 >= 0 в том же кластере
Это довольно просто реализовать с помощью dplyr. Пожалуйста, дайте мне знать, если следующее имеет смысл для вас.
(По некоторым причинам я не могу запустить ваше решение)
library(dplyr) rankedDf <- mydf %>% group_by(DayCategory, Hour, Holidays) %>% arrange(DayCategory, Hour, Holidays, Date) %>% mutate(rowRank = order(Date), previousRowRank = order(Date) - 1) %>% left_join(., ., by = c("previousRowRank" = "rowRank", "DayCategory", "Hour", "Holidays")) %>% select( Date.POSIXct = Date.POSIXct.x, Date = Date.x, WeekDay = WeekDay.x, DayCategory, Hour, Holidays, myvalue = myvalue.x, PreviousDaySameDayCategory = Date.y, PreviousValueSameDayCategory = myvalue.y ) print.data.frame(rankedDf, nrow = 500)
Примечание: Я также включаю DayCategory и т.д. в упорядочивание, чтобы было удобнее понять, как это работает; код работает отлично и только с Date в качестве параметра.
Ответ или решение
Поиск значения предыдущего дня в датафрейме R по категории
В этом руководстве мы разберем, как в R найти значение для одного и того же часа даты в предыдущем дне с определенной категорией, при этом соблюдая условия для выходных дней. Исходя из предоставленного датафрейма и условий, мы постараемся добавить новый столбец PreviousDaySameDayCategory
, который будет содержать дату предыдущего дня с той же категорией.
1. Подготовка данных
Сначала создадим датафрейм на основе предоставленного кода. Это позволит нам работать с аналогичным набором данных:
library(lubridate)
library(dplyr)
Date.POSIXct <- seq(as.POSIXct("2018-05-01"), as.POSIXct("2018-05-31"), "hour")
mydf <- as.data.frame(Date.POSIXct)
mydf$Date <- as.Date(substr(as.character(mydf$Date.POSIXct), 1, 10))
mydf$WeekDay <- substr(toupper((weekdays(mydf$Date))), 1, 2)
mydf$DayCategory <- as.factor(ifelse(mydf$WeekDay == "MA" | mydf$WeekDay == "MI" | mydf$WeekDay == "JU",
"MA-MI-JU", mydf$WeekDay))
mydf$Hour <- hour(mydf$Date.POSIXct)
mydf$Holidays <- c(rep(0, 24*7), rep(1, 24*7), rep(0, 24*16 + 1))
set.seed(123)
mydf$value <- sample.int(101, size = nrow(mydf), replace = TRUE)
2. Логика поиска предыдущего дня
Чтобы выполнить задачу, мы будем использовать следующий подход:
- Разделить строки по категориям
DayCategory
,Hour
иHolidays
. - Для каждой группы отсортируйте по дате.
- Получите дату предыдущего дня с той же
DayCategory
иHolidays
для каждого часа.
3. Реализация решения с использованием dplyr
Мы воспользуемся функцией dplyr
для группировки и манипуляции данными:
rankedDf <- mydf %>%
group_by(DayCategory, Hour, Holidays) %>%
arrange(Date) %>%
mutate(PreviousDaySameDayCategory = lag(Date, order_by = Date)) %>%
ungroup()
# Вывод результата
print(rankedDf)
Объяснение кода:
group_by(DayCategory, Hour, Holidays)
: Группируем наш датафрейм по категориям дня, часу и наличию выходного дня.arrange(Date)
: Сортируем группы по дате.mutate(PreviousDaySameDayCategory = lag(Date, order_by = Date))
: Создаем новый столбец для хранения даты предыдущего дня с помощью функцииlag()
, которая возвращает значение из предыдущей строки, основываясь на сортировке по дате.
4. Учет значений
Если необходимо, мы можем дополнительно вернуть значения value
для предыдущего дня, аналогично тому, как вы искали:
rankedDf <- mydf %>%
group_by(DayCategory, Hour, Holidays) %>%
arrange(Date) %>%
mutate(PreviousDaySameDayCategory = lag(Date, order_by = Date),
PreviousValueSameDayCategory = lag(value, order_by = Date)) %>%
ungroup()
# Вывод результата
print(rankedDf)
Заключение
Таким образом, метод, который мы применили, позволяет извлечь предыдущие значения по определенным категориям из датафрейма. Этот подход предоставляет гибкость для дальнейшего анализа данных и упрощает процесс обработки данных в R. Если у вас возникнут дополнительные вопросы или потребность в уточнениях, не стесняйтесь обращаться за помощью.