【问题标题】:Conditional removal of rows for grouped data in R有条件地删除 R 中分组数据的行
【发布时间】:2016-12-02 23:28:44
【问题描述】:

我正在尝试提取 1950 年至 2015 年间几个测量站每年的年平均降雨量。降雨数据集由每日测量值组成。

在计算每个站点的年平均值之前,我需要过滤数据,这样每个月必须有 >15 天的数据。

如何在 R 中做到这一点?

让这成为一个工作示例:

id<-rep(c("Station_1","Station_2","Station_3"),length(1),each=1080)
year<-rep(c(1950:1952),length(1:3),each=360)
month <- rep(c(1:12),length(1:9),each=30)
day <- rep(c(1:30),length(1:108))
value<-runif(3240, min=0, max=10)

df<-data.frame(cbind(id,year,month,day,value))

我尝试了类似的方法:

result<-df %>%
   group_by(id,year,month) %>%
   summarise(No._of_days=n(),mean_month=mean(value))
result<-result[!(result$No._of_days<15),]
result<-result %>%
   group_by(id,year) %>%
   summarise(No._of_months=n(),mean_year=mean(mean_month))

但是,这会导致错误的解决方案,因为我正在“从平均值中取平均值”。

感谢您的建议。

【问题讨论】:

  • 请停止使用data.frame(cbind(...))data.frame() 就足够了。看看?data.frame
  • 感谢 Sathish、aichao、sebolus 和 NJBurgo 快速而正确的回复 - 非常感谢您的帮助!所有解决方案都有效,但我会坚持使用 aichao,因为我最喜欢使用 dplyr。很抱歉错误地制定了数据框 - 我现在将“按原样”保留,因为这里的每个人都对如何正确构建它添加了很好的评论。

标签: r nested row mean


【解决方案1】:

原始数据:在创建数据框时删除变量的默认分解。

df<-data.frame(id = id,year = year, month = month, day = day, value = value, stringsAsFactors = FALSE)

id, year, month 对数据进行分组,并使用.N 内部变量获取子集的天数。接下来,链接结果(类似于 dplyr 中的 %>%)。现在分组id, year,然后是条件N &gt; 15,最后计算该子集的mean降雨并将其存储在avg_rainfall中。

setDT通过引用将dataframe转换为datatable

library("data.table")
setDT(df)[, .(value, .N), by = .(id, year, month)][N > 15, .(avg_rainfall = mean(value)), by = .(id, year)]

#           id year avg_rainfall
# 1: Station_1 1950     4.852840
# 2: Station_1 1951     5.138069
# 3: Station_1 1952     4.934006
# 4: Station_2 1950     4.870335
# 5: Station_2 1951     5.179425
# 6: Station_2 1952     5.055026
# 7: Station_3 1950     4.959524
# 8: Station_3 1951     5.049996
# 9: Station_3 1952     4.927548

【讨论】:

  • 非常感谢您提供快速而清晰的解决方案 - 我真的很感激!对错误地制定数据框表示歉意 - 下次会记住。
  • 还有一个问题,而不是过滤超过 15 天的行,如果 15 个连续的单元格是 NA,我可以改为过滤吗?例如.... df[ ,!apply(is.na(df), 2, function(x) {v stackoverflow.com/questions/15186697/…
  • 如果您的意图是在计算平均值之前删除 NA,您可以在 mean 函数中传递 na.rm = TRUE。例如:avg_rainfall = mean(value, na.rm = TRUE)
【解决方案2】:

有一些东西,例如 data.frame,由于您创建它的方式,将所有内容都编码为一个因素。改用这个:

df<-data.frame(id = id,
               year = year,
               month = month,
               day = day,
               value = value)

那么(很抱歉,我不是magrittr 的粉丝)以下将起作用:

# Filter into a new data.frame
df2 <- semi_join(df, 
          filter(summarise(group_by(df, year, month), N = n()), N > 15),
          by = c(year = "year", 
                 month = "month"))

# Summarise
summarise(group_by(df2, id), 
          value = mean(value, na.rm = TRUE))

【讨论】:

  • 感谢@NJBurgo,提供出色的解决方案和对问题的快速回复!干杯,C
【解决方案3】:

只关注代码,它对我有用,但有一些修改。例如。你写你想要> 15天的数据,但选择> 14,还要确保值是数字,而不是你的df。

`df<-data.frame(cbind(id,year,month,day,value))
 df$value<- as.numeric(as.character(df$value))
   result<-df %>%
   group_by(id,year,month) %>%
   summarise(No._of_days=n(),mean_month=mean(value))
result<-result[!(result$No._of_days<=15),]
result<-result %>%
  group_by(id,year) %>%
  summarise(No._of_months=n(),mean_year=mean(mean_month))`

抛开代码:从数学的角度来看,我并不清楚这种方法。为什么要排除年度聚合中少于 16 次测量的所有内容?如果您的测量结果确实是随机的,请考虑使用您在任何月份的值并估算数据集中所有缺失的天数(例如,对每个站点、年份(连续)、日历周、前后降雨量使用回归天)。

【讨论】:

  • 感谢 @sebolus 的解决方案 - 我非常感谢快速周转。回覆。数学上,我的子集方法已经完成,因为如果某些月份在制定年平均值时表现不佳,则可能会丢失全年降雨的季节性差异。尽管您的估算解决方案是可行的,但现有文献中关于降雨/风/温度数据等的常用方法是简单地排除这些月份(必要时再排除几年)以避免此问题。目前,我将坚持使用子集化方法。谢谢,蔡
【解决方案4】:

使用dplyrmagrittr 的方法略有不同:

library(dplyr)
set.seed(42) # this is only so we get consistent results to compare

# then generate id, year month, day, and value using your code 
# but use what @NJBurgo used to generate df

df<-data.frame(id = id,
       year = year,
       month = month,
       day = day,
       value = value)

result <- df %>%
  group_by(id,year,month) %>%
  mutate(No._of_days=n()) %>%
  filter(No._of_days > 15) %>%  ## keep only rows with number of days greater than 15
  ungroup() %>%
  group_by(id,year) %>%
  summarize(mean_year=mean(value))

# using set.seed(42), you should get
print(result)
##         id  year mean_year
##     <fctr> <int>     <dbl>
##1 Station_1  1950  4.954538
##2 Station_1  1951  4.878709
##3 Station_1  1952  4.737996
##4 Station_2  1950  4.942614
##5 Station_2  1951  4.876992
##6 Station_2  1952  5.193242
##7 Station_3  1950  5.235278
##8 Station_3  1951  4.955401
##9 Station_3  1952  4.905078

关键是filtergroup_by 行(按idyearmonth 分组)。我还使用mutate 而不是summarise 创建No._of_days。然后ungroup() 再由idyear 重新组合以计算均值。

顺便说一句,您的测试用例不足以对此进行测试,因为所有月份都有 30 天。

希望这会有所帮助。

【讨论】:

  • 谢谢@aichao - 我喜欢这个解决方案,特别是因为我最喜欢使用 dplyr。关于数据框的观点 - 我认为包含一个可以参考的例子很重要,即使它很糟糕!我以前没有制作过虚拟数据集,也不想花太长时间来寻找如何创建更真实的真实数据复制,因为知道按天数过滤的概念仍然适用。非常感谢
猜你喜欢
  • 2021-11-25
  • 2015-08-31
  • 2021-06-09
  • 2021-03-08
  • 2014-05-04
  • 2020-08-11
  • 2022-08-12
  • 2012-06-05
  • 1970-01-01
相关资源
最近更新 更多