【问题标题】:Annual mean using common months over the year for different plots使用一年中不同地块的常见月份的年平均值
【发布时间】:2021-05-16 10:44:09
【问题描述】:

data

data 你好, 我有一个像这样的大型数据集。我想通过 dplyr 计算我可以做到的年平均值:

    annual_mean<-
              df %>%
              group_by(year) %>% 
              summarise(across(Plot1:Plot3, ~ mean(.x, na.rm = TRUE)))

但我需要使用多年来通常出现的月份来计算年平均值,不包括 NA。例如,在 Plot1 中可能是 2、4、5 和 7 个月,这些年来很常见。因此,我必须仅使用这些月份来计算年平均值。然后是 Plot2、Plot3 的不同常见月份。

新成员! 非常感谢任何帮助!

可重现的样本数据

> dput(head(df, 100))
structure(list(Plot1 = c(0.77, 0.75, 0.75, 0.77, 0.79, 0.8, 0.8, 
0.83, 0.81, 0.85, 0.85, NA, NA, 0.69, 0.66, 0.74, 0.63, 0.65, 
0.65, 0.7, 0.7, 0.7, 0.79, 0.8, 0.75, 0.82, 0.8, 0.83, 0.8, 0.82, 
NA, 0.86, 0.8, 0.81, 0.78, 0.78, 0.73, 0.79, 0.74, 0.72, 0.76, 
0.71, 0.71, 0.72, 0.73, 0.71, 0.73, 0.74, 0.79, 0.78, 0.78, 0.83, 
0.8, 0.85, 0.86, 0.78, 0.76, 0.73, 0.72, 0.69, 0.73, 0.65, 0.63, 
0.63, 0.65, 0.69, 0.76, 0.7, 0.7, 0.71, 0.72, 0.77, 0.71, 0.76, 
0.77, 0.78, 0.8, 0.76, 0.76, 0.51, 0.74, 0.71, 0.73, 0.64, 0.65, 
0.63, 0.61, 0.64, 0.71, 0.68, 0.74, 0.7, 0.76, 0.74, 0.71, 0.74, 
0.8, 0.78, 0.79, 0.69), Plot2 = c(NA, 0.38, 0.45, 0.48, 0.76, 
0.88, 0.91, 0.9, 0.89, 0.89, 0.89, 0.84, 0.82, 0.83, 0.67, 0.62, 
0.58, 0.6, 0.57, NA, NA, NA, NA, 0.42, 0.48, 0.53, 0.49, 0.51, 
0.66, 0.89, NA, 0.87, 0.88, 0.85, 0.85, 0.85, 0.81, 0.69, 0.67, 
0.57, 0.54, NA, NA, NA, NA, NA, 0.44, 0.51, 0.48, 0.38, 0.51, 
0.83, 0.91, 0.91, 0.87, 0.89, 0.84, 0.87, 0.58, 0.75, 0.61, 0.55, 
0.55, 0.55, NA, 0.61, 0.6, NA, NA, NA, NA, NA, NA, 0.78, 0.87, 
0.91, 0.92, 0.9, 0.9, 0.9, 0.89, 0.88, 0.88, 0.82, 0.56, 0.54, 
0.54, 0.57, NA, NA, NA, NA, NA, NA, NA, 0.28, NA, 0.69, 0.8, 
0.91), Plot3 = c(NA, 0.77, 0.65, 0.7, 0.61, 0.63, 0.6, 0.59, 
0.55, 0.53, 0.49, 0.44, 0.45, 0.35, 0.48, 0.51, 0.7, 0.63, 0.7, 
0.7, NA, NA, NA, NA, 0.38, NA, 0.67, 0.59, 0.59, 0.61, 0.56, 
0.53, 0.54, 0.51, 0.32, 0.37, 0.43, 0.4, 0.67, 0.6, 0.65, 0.67, 
0.72, NA, 0.72, NA, 0.75, 0.7, 0.69, 0.66, 0.62, 0.6, 0.57, 0.54, 
0.54, 0.53, 0.49, 0.33, 0.31, 0.41, 0.46, 0.47, 0.52, 0.69, 0.74, 
0.7, NA, NA, 0.79, NA, 0.72, 0.72, 0.64, 0.6, 0.6, 0.58, 0.58, 
0.54, 0.53, 0.51, 0.51, 0.49, 0.37, 0.51, 0.48, 0.5, 0.64, 0.77, 
NA, NA, 0.78, 0.77, 0.72, NA, 0.68, 0.61, 0.59, 0.62, 0.59, 0.59
), Day = c(18, 5, 21, 6, 22, 8, 24, 9, 25, 11, 27, 12, 28, 13, 
29, 15, 31, 16, 2, 18, 1, 17, 2, 18, 6, 22, 7, 23, 9, 25, 10, 
26, 12, 28, 13, 29, 14, 30, 16, 1, 17, 3, 19, 1, 17, 2, 18, 6, 
22, 7, 23, 9, 25, 10, 26, 12, 28, 13, 29, 14, 30, 16, 1, 17, 
3, 19, 1, 17, 2, 18, 6, 22, 7, 23, 9, 25, 10, 26, 12, 28, 13, 
29, 14, 30, 16, 1, 17, 3, 19, 1, 17, 2, 18, 5, 21, 6, 22, 8, 
24, 9), year = c(2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 
2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 
2000, 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001, 
2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001, 
2001, 2001, 2002, 2002, 2002, 2002, 2002, 2002, 2002, 2002, 2002, 
2002, 2002, 2002, 2002, 2002, 2002, 2002, 2002, 2002, 2002, 2002, 
2002, 2002, 2002, 2003, 2003, 2003, 2003, 2003, 2003, 2003, 2003, 
2003, 2003, 2003, 2003, 2003, 2003, 2003, 2003, 2003, 2003, 2003, 
2003, 2003, 2003, 2003, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 
2004, 2004, 2004, 2004), months = c(2, 3, 3, 4, 4, 5, 5, 6, 6, 
7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 12, 1, 1, 2, 2, 3, 3, 4, 4, 
5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, 12, 12, 1, 1, 2, 2, 
3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, 12, 12, 
1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 
11, 12, 12, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6)), row.names = c(NA, 
-100L), class = c("tbl_df", "tbl", "data.frame"))

【问题讨论】:

  • 欢迎来到 SO!如果您可以提供完整的可重现示例,包括不是屏幕截图形式的数据片段,您更有可能获得有用的解决方案!请阅读guidance 了解更多信息。您可以考虑使用dput(df) 获取数据以改进您的问题。祝你好运!
  • 谢谢。我分享了数据。请检查第二个数据链接。是的,第一个数据链接只是截图,不便之处敬请见谅。
  • 请检查我的更新。

标签: r dplyr


【解决方案1】:

更新 我已经根据您在 cmets 中的要求修改了我的解决方案。这次我首先找到每个Plot 的共同月份,然后继续计算每年的平均值。

library(dplyr)
library(purrr)

# I created a character vector of Plot names in order to ease iteration
Plots <- paste("Plot", c(1:3), sep = "")

# Then we iterate over each name selecting only the corresponding column 
# from the original data set and find the common months for each iteration.
Plots %>%
  map(~ df %>% 
        select(.x, months, year) %>%
        drop_na() %>%
        group_split(year) %>%
        map(~ .x %>% 
              select(months) %>%
              distinct()) %>% 
        reduce(~ intersect(.x, .y))) %>%
  set_names(nm = Plots) -> commons

然后我们使用公地月份对整个数据集应用过滤器:

# This time we iterate over both commons and plot names at the same time

map2(Plots, commons, ~ 
       df %>% 
       select(.x, months, year) %>%
       filter(months %in% .y[["months"]]) %>%
       group_by(year) %>%
       summarise(across(starts_with("Plot"), ~ mean(.x, na.rm = TRUE)))) %>%
  exec(cbind, !!!.) %>%
  select(-c(3, 5))


    year Plot1 Plot2 Plot3
   <dbl> <dbl> <dbl> <dbl>
 1  2000 0.749 0.771 0.566
 2  2001 0.78  0.724 0.512
 3  2002 0.741 0.707 0.528
 4  2003 0.703 0.806 0.559
 5  2004 0.734 0.757 0.549
 6  2005 0.725 0.758 0.547
 7  2006 0.732 0.796 0.542
 8  2007 0.725 0.763 0.585
 9  2008 0.761 0.736 0.569
10  2009 0.766 0.776 0.575
11  2010 0.768 0.78  0.622
12  2011 0.781 0.787 0.549
13  2012 0.776 0.784 0.553
14  2013 0.774 0.787 0.598
15  2014 0.748 0.809 0.577
16  2015 0.731 0.797 0.587
17  2016 0.758 0.67  0.653
18  2017 0.799 0.76  0.599
19  2018 0.794 0.81  0.575

【讨论】:

  • 你的意思是你想分开地块并只考虑每个地块中常见的月份?所以每个情节都有自己的共同月份?
  • 我所做的是首先删除所有 3 个 Plots 的 NAs,然后找到所有这些 Plots 的共同月份。是的,它可以完成,但我将不得不慢慢来。
  • 那里没有什么特别的事情发生只要记住用实际的Plots变量的数量修改Plots向量,在这种情况下我们只有3个。尝试运行map2部分没有最后两行,让我知道。我花了相当多的时间在这上面,虽然很感激,但我不想让它未完成。
  • 是的,我更改了实际的绘图变量。你是对的,问题来自 cbind。没有最后两行,我得到所有图的结果
  • 你做得很好。非常感谢您的时间和善意的帮助,尽管更新 rlang 对我来说无法以某种方式解决 exec 函数问题。这其实是我的问题,我R不太好。你太高手了,看你的代码我也能感觉到!!!
【解决方案2】:

您有三个Plot 列,并且您希望对每个列执行相同的操作。在这种情况下,您可以通过将数据“转换”为“长”(即“整洁”)格式来让您的生活更轻松。这是使用tidyrdplyr 的方法:

library(dplyr)
library(tidyr)

tidied_df <- df %>%
  
  # First pivot into 'long' or 'tidy' format
  pivot_longer(Plot1:Plot3, names_to = "Plot", 
               values_to = "Value", names_prefix = "Plot") %>% 
  
  # First remove all missing values of 'Value'
  filter(!is.na(Value)) %>% 
  
  # Now turn 'implicit' missing months to explicit
  complete(Plot, year, months) %>% 
  
  # Can now add a column indicating whether the whole month is 'missing'
  # for a given year
  group_by(Plot, year, months) %>% 
  mutate(month_missing = all(is.na(Value))) %>% 
  
  # Now use the helper column to remove a month from all years if any
  # one year has only missing values for that month
  group_by(Plot, months) %>% 
  filter(!any(month_missing)) %>% 
  ungroup()
  
# We can take a look to see which months are present across all years
# for each plot like so:
tidied_df %>% 
  group_by(Plot) %>% 
  summarise(
    months = paste(sort(unique(months)), collapse = ", "), 
    .groups = "drop"
  )
#> # A tibble: 3 x 2
#>   Plot  months                         
#>   <chr> <chr>                          
#> 1 1     2, 3, 4, 5, 6, 7, 9, 10, 11, 12
#> 2 2     4, 5, 6, 7, 8, 9, 10, 11       
#> 3 3     3, 4, 5, 6, 7, 8, 9, 10
  

# Finally, we can compute the mean across each plot:
tidied_df %>% 
  group_by(Plot, year) %>% 
  summarise(Value = mean(Value, na.rn = TRUE), .groups = "drop")
#> # A tibble: 57 x 3
#>    Plot   year Value
#>    <chr> <dbl> <dbl>
#>  1 1      2000 0.749
#>  2 1      2001 0.78 
#>  3 1      2002 0.741
#>  4 1      2003 0.703
#>  5 1      2004 0.734
#>  6 1      2005 0.725
#>  7 1      2006 0.732
#>  8 1      2007 0.725
#>  9 1      2008 0.761
#> 10 1      2009 0.766
#> # … with 47 more rows

编辑

根据要求,这是一种过滤 Plot 值的方法,其中所有年份至少有 4 个月的共同点:

tidied_df %>% 
  group_by(Plot) %>% 
  filter(n_distinct(months) > 4) %>% 
  ungroup()

【讨论】:

  • 这正是我正在寻找的解决方案。完美解决!!!非常感激。还有一件事……我们能否添加一个条件,仅在一年中至少有 4 个月常见时才计算年平均值?
  • 是的,我会进行编辑。如果您的问题的主要部分得到解答,请考虑接受此解决方案!谢谢。
  • 您的回答完美解决了问题。所以,我必须考虑你的解决方案。你能告诉我我应该把这个新条件准确地放在哪里吗?
  • 您可以简单地将它放在第一个管道链的末端 - 玩一玩并尝试了解发生了什么,您会发现它并不太复杂。
猜你喜欢
  • 2015-08-29
  • 2020-06-19
  • 1970-01-01
  • 1970-01-01
  • 2023-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-03
相关资源
最近更新 更多