如何在 R 中使用日期查找连续天数的平均数?

问题描述 投票:0回答:1

我正在处理的气候数据已添加日期并进行子集化,仅包含温度连续 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 不是用于此操作的正确函数,哈哈。您建议使用哪些代码/函数来解决这个问题?

r date lapply mean
1个回答
0
投票

我认为您使用

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()
  • “堆叠”data.frames,一个在另一个之上,并创建一个名为
    id
    的附加变量来跟踪输出中的每一行来自哪个 data.frame
  • as_tibble()
  • 将 data.frame 转换为 tibble,以便更好地打印
  • Date
  • Y
    M
    组件构建
    D
    变量
  • filter()
  • 删除构建日期为
    NA
    (即每年 2 月)的记录
  • relocate()
  • Date
    变量移动到小标题的第一列
  • arrange()
  • 首先按源表对 tibble 进行排序 (
    id
    ),然后按
    Date
    为使用按组游程长度编码做准备
    第二个 
  • mutate()
  • 通过
    id
    列值 (
    .by = id
    ) 处理数据,以构造 (1) 一个逻辑标志,用于标识
    Temp
     第 90 个百分位数以上的记录和 (2) RLE 标识符(使用 
    data.table::rleidv()
     函数)为每个记录分配一个整数(从 1 开始),当遇到不同的值时增加 1,有效地对连续日期进行分组
    filter(keepflag == TRUE)
  • 删除
  • Temp
     
    高于第 90 个百分位数的所有记录
    count()
  • 计算每个源 data.frames 中每组 RLE ID 中的日期数量,并将该值(默认情况下)存储在名为
  • 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


© www.soinside.com 2019 - 2024. All rights reserved.