У меня есть список фреймов данных, в каждом из которых есть столбцы года, месяца, дня и температуры, а также некоторые другие данные. Я уже выяснил (с помощью помощи по переполнению стека, спасибо, ребята), как подмножество фреймов данных, чтобы они содержали только те данные, температура которых превышает определенный порог. Однако теперь мне нужно взять эти подмножества и найти другое подмножество последовательных дней (по сути, найти все строки, в которых температура была выше порогового значения в течение 3+ дней).
пример данных:
set.seed(1234)
A <- data.frame("D" = c(sample(1:5, size = 1000, replace = TRUE)), "Temp" = c(sample(0:35, size = 1000, replace = TRUE)))
B <- data.frame("D" = c(sample(1:5, size = 1000, replace = TRUE)), "Temp" = c(sample(-10:22, size = 1000, replace = TRUE)))
C <- data.frame("D" = c(sample(1:5, size = 1000, replace = TRUE)), "Temp" = c(sample(3:42, size = 1000, replace = TRUE)))
climate <- list("Alist" = A, "Blist" = B, "Clist" = C)
# courtesy of ThomasIsCoding
tm <- lapply(
climate,
function(x) {
subset(
x,
Temp > quantile(Temp, probs = 0.90)
)
}
)
tm
До сих пор я пытался использовать lapply, diff и rle, чтобы найти случаи, когда дни были последовательными. Я взял свой список фреймов данных, использовал lapply, чтобы выбрать столбец дней, затем снова использовал lapply, чтобы найти разницу между каждым элементом в столбце дней, а затем снова использовал lapply, чтобы выполнить rle.
result <- lapply(lapply(lapply(
tm, '[[',1), # this selects the days column in all the dataframes in the list tmax95
diff), # this finds the difference between each element in the days column to help determine if they are consecutive
rle) # i don't really understand rle fully but to my understanding this takes all the differences and counts how many there are in order or something like that
result
Затем я использую еще один пример, чтобы найти случаи, когда имеется более двух различий в 1 день (последовательных).
fin <- lapply(result, function(x) x$lengths>=2 & x$values==1)
fin
Однако это не совсем то, что я хочу в качестве конечного результата, поскольку он возвращает список списков значений True и Falses, тогда как мне нужны строки данных, связанные с возвращаемыми значениями True. Как я смогу получить данные за последовательные дни, а не за истинные значения?
@Edward В этом случае просто возможности ссылаться на фреймы данных A, B и C со столбцом D должно быть достаточно, чтобы я мог разобраться с исходными данными. Я не использовал исходные данные в качестве образца, поскольку они содержат 20 фреймов данных, каждый из которых содержит около 10 000 строк и 15 столбцов. Было бы более полезно, если бы я поместил сюда исходные данные?
Проверьте, сработает ли это у вас, используя dplyr
. Немного неясно, что означает «последовательный» в контексте случайно распределенных дней, но я пока беру данные такими, какие они есть.
library(dplyr)
threshTemp = 20
threshDay = 3
lapply(tm, \(x)
x %>%
mutate(cond = Temp > threshTemp, consid = consecutive_id(cond)) %>%
filter(n() >= threshDay & cond, .by = c(D, consid)) %>%
select(-cond, -consid))
Случайно распределенные дни предназначены только для создания образца набора данных. В моих исходных данных они основаны на реальных наблюдениях, а затем я выбираю дни, которые превышают определенный температурный порог, в результате чего некоторые дни идут подряд, а большинство нет, если это имеет смысл.
Все должно быть в порядке, мы также могли бы отсортировать, но поскольку мы группируем, это не имеет большого значения, за исключением, возможно, соображений печати и отображения.
Вы можете попробовать следующий код, который сначала применяет порог температуры к каждому климату, используя subset
(как вы), а затем подмножества их, используя diff
, чтобы найти строки, в которых есть 3 дня подряд.
result <- lapply(climate, \(x) {
y <- subset(x,
Temp > quantile(Temp, probs = 0.90)
)
y[unique(
sort(
unlist(
lapply(
which(
c(diff(y[,'D'])==1, FALSE) & c(diff(y[,'D'], diff=2)==0, FALSE, FALSE)),
\(x) x + 0:2)
))),]
}
)
lapply(result, head)
$Alist
D Temp
317 2 35
326 3 33
341 4 34
579 3 34
582 4 33
584 5 35
$Blist
D Temp
357 2 21
358 3 22
361 4 20
$Clist
D Temp
257 2 40
258 3 40
269 4 41
350 1 41
351 2 42
364 3 41
Объяснение:
diff()
принимает различия каждого элемента. Если установить значение == 1, будут найдены последовательные дни. diff(..., diff=2)==0
находит последовательные равные различия. Вместе эти два условия определяют первый из трех последовательных дней. Добавление FALSE
гарантирует, что вектор имеет правильную длину, поскольку дифференцирование каждый раз уменьшает длину на 1.
which
находит индексы первых 3 дней подряд. +0:2
дает индексы за 3 дня подряд.
lapply
выполняет цикл для каждого дня, и нам нужно unlist
это, чтобы получить вектор, отсортировать его, а затем удалить дубликаты с помощью unique
.
Данные (climate
), указанные в вопросе с set.seed(1234)
.
Спасибо! Это сработало с небольшими изменениями, но мне было интересно, сможете ли вы объяснить различные функции, которые вы использовали, и что они делают в этом контексте? Даже прочитав документацию R Help, я все еще немного в замешательстве.
Да - см. мое редактирование для объяснения.
Вам придется вернуться к исходным данным, содержащим даты. Предоставленные вами данные не содержат дат.