我正在处理的气候数据已添加日期并进行子集化,仅包含温度连续 3 天或以上超过 90% 的数据。
set.seed(12368)
A <- data.frame("Y" = rep(1990:2009, each = 360), "M" = rep(1:12, each = 30, times = 20), "D" = rep(1:30, 240), "Temp" = c(sample(0:35, size = 7200, replace = TRUE)))
B <- data.frame("Y" = rep(1990:2009, each = 360), "M" = rep(1:12, each = 30, times = 20), "D" = rep(1:30, 240), "Temp" = c(sample(-10:22, size = 7200, replace = TRUE)))
C <- data.frame("Y" = rep(1990:2009, each = 360), "M" = rep(1:12, each = 30, times = 20), "D" = rep(1:30, 240), "Temp" = c(sample(3:42, size = 7200, replace = TRUE)))
climate <- list("Alist" = A, "Blist" = B, "Clist" = C)
#climate
library(dplyr)
library(magrittr)
datedclimate <- lapply(lapply(climate,
function(x)
x %<>%
mutate("Date" = as.Date(with(x, paste(Y,M,D, sep="-")),"%Y-%m-%d"))
),
function(y)
y %>% relocate("Date")
)
datedclimate
tm <- lapply(datedclimate, \(x) {
y <- as.data.frame(subset(x,
Temp > quantile(Temp, probs = 0.90, na.rm = TRUE))
)
y[unique(
sort(
unlist(
lapply( # this iterates through all of my data sets
which(
c(diff(y[,'Date'])==1, FALSE) & c(diff(y[,'Date'], diff=2)==0, FALSE, FALSE)),
\(x) x + 0:2)
))),]
}
)
tm
我想做的下一步是找到每个连续天数的平均天数。例如,子集 C 列表具有 5 个连续 3 天的区间和 1 个连续 4 天的区间。因此,平均连续天数为 (3+3+3+3+3+4)/6 的 3.17 天。
我尝试修改此问题中的代码,但它没有返回正确的数字。如果可能的话,我也更愿意修改/使用上面的子集数据 tm。
ConsecMean <- function(x) {
x <- ifelse(x > quantile(x, probs = 0.90, na.rm = TRUE), 0, 1)
cs <- cumsum(x)
cs <- cs[x == 0]
mean <- mean(table(cs))
return(mean)
}
tri <- lapply(lapply(datedclimate, "[[", 5), ConsecMean)
tri
> tri
$Alist
[1] 1.105735
$Blist
[1] 1.104746
$Clist
[1] 1.099693
因此,我正在寻找一个可以应用于数据帧(气候)列表的函数,该函数将返回列表中每个数据帧的平均数。我想我应该使用 lapply,但我不知道从那里去哪里。我也尝试过使用 rle,但它与日期格式不兼容,而且我也认为 rle 不是用于此操作的正确函数,哈哈。您建议使用哪些代码/函数来解决这个问题?
我认为您使用
rle()
的方法是正确的,但需要使用它的不同版本。如果您愿意考虑使用按组处理的基于 tibble
的方法,那么我相信下面的代码将满足您的需求。然而,我对此并不确定,因为当我在我的机器上运行它时,您提供的数据生成代码与您对 Alist
中应该包含的内容的描述不匹配(R 4.4.1,Win 10).您说:
子集 A 列表有 4 个连续 3 天的区间和 1 个连续 6 天的区间。因此,平均连续天数为 (3+3+3+3+6)/5 的 3.6 天。
但是,当我运行你的代码时,我连续三天运行了六次;请参阅来自
tm$Alist
的以下(带注释的)数据:
> tm$Alist
Date Y M D Temp
2012 1995-08-02 1995 8 2 33 # start 1
2013 1995-08-03 1995 8 3 34
2014 1995-08-04 1995 8 4 33 # end 1
3641 2000-02-11 2000 2 11 34 # start 2
3642 2000-02-12 2000 2 12 33
3643 2000-02-13 2000 2 13 33 # end 2
3650 2000-02-20 2000 2 20 34 # start 3
3651 2000-02-21 2000 2 21 33
3652 2000-02-22 2000 2 22 35 # end 3
4066 2001-04-16 2001 4 16 34 # start 4
4067 2001-04-17 2001 4 17 33
4068 2001-04-18 2001 4 18 33 # end 4
4582 2002-09-22 2002 9 22 35 # start 5
4583 2002-09-23 2002 9 23 35
4584 2002-09-24 2002 9 24 33 # end 5
6024 2006-09-24 2006 9 24 34 # start 6
6025 2006-09-25 2006 9 25 35
6026 2006-09-26 2006 9 26 35 # end 6
鉴于我看到的输出,正确的平均连续天数对于
Alist
来说正好是 3。除非您想按年和月进行分组,否则上面的运行 #2 和 3 将合并为六天的单次运行?
无论如何,这是我想出的代码。请注意,它使用rleidv()
包中的
data.table
函数,但我相当确定在安装 data.table
包时安装了 tidyverse
。换句话说,我假设您已经安装了它。set.seed(12368)
A <- data.frame("Y" = rep(1990:2009, each = 360), "M" = rep(1:12, each = 30, times = 20), "D" = rep(1:30, 240), "Temp" = c(sample(0:35, size = 7200, replace = TRUE)))
B <- data.frame("Y" = rep(1990:2009, each = 360), "M" = rep(1:12, each = 30, times = 20), "D" = rep(1:30, 240), "Temp" = c(sample(-10:22, size = 7200, replace = TRUE)))
C <- data.frame("Y" = rep(1990:2009, each = 360), "M" = rep(1:12, each = 30, times = 20), "D" = rep(1:30, 240), "Temp" = c(sample(3:42, size = 7200, replace = TRUE)))
library(data.table)
library(dplyr)
bind_rows(A, B, C, .id = "id") |>
as_tibble() |>
mutate("Date" = as.Date(paste(Y, M, D, sep = "-"), "%Y-%m-%d")) |>
filter(is.na(Date) == FALSE) |>
relocate(Date) |>
arrange(id, Date) |>
mutate(
keepflag = Temp > quantile(Temp, probs = 0.90, na.rm = TRUE),
runs = data.table::rleidv(keepflag),
.by = id
) |>
filter(keepflag == TRUE) |>
count(id, runs) |>
filter(n >= 3) |>
summarize(ConsecMean = mean(n), .by = id)
在上面的代码中:
bind_rows()
id
的附加变量来跟踪输出中的每一行来自哪个 data.frameas_tibble()
Date
Y
和 M
组件构建 D
变量filter()
NA
(即每年 2 月)的记录relocate()
Date
变量移动到小标题的第一列arrange()
id
),然后按 Date
为使用按组游程长度编码做准备第二个 mutate()
id
列值 (.by = id
) 处理数据,以构造 (1) 一个逻辑标志,用于标识 Temp
第 90 个百分位数以上的记录和 (2) RLE 标识符(使用
data.table::rleidv()
函数)为每个记录分配一个整数(从 1 开始),当遇到不同的值时增加 1,有效地对连续日期进行分组
filter(keepflag == TRUE)
Temp
不
高于第 90 个百分位数的所有记录
count()
n
的新变量中
filter(n >= 3)
summarize()
ConsecMean
列值
创建
id
变量
我使用此代码获取您的数据的结果是# A tibble: 3 × 2
id ConsecMean
<chr> <dbl>
1 1 3
2 2 3
3 3 3.17