使用另一个数据框的数据来改变数据框中的数据

3

可重复数据:

df1 <- tibble(id = c("GR1","GR2"),
              area = c("A1","A2"),
              date1 = as.Date(c("2022-01-01","2022-01-02")),
              date2 = as.Date(c("2022-01-06","2022-01-08")))

set.seed(543)
df2 <- tibble(date3 = seq(as.Date("2022-01-01"), as.Date("2022-01-09"), "days"),
              temperature =runif(9, min = 28, max = 33),
              area = c("A1","A2","A1","A2","A1","A2","A1","A2","A1"))

你好,我希望在df1中创建一列,其中包含在df2筛选后得出的平均温度。(实际数据框中,df1有1036行,df2有26192行。)

我尝试了这种方法,但它并没有像我想象的那样起作用。

df3 <- df1 %>%
  group_by(area) %>%
  mutate(average_temp = mean(filter(.data = df2, date3 >= df1$date1 & date3 <= df1$date2 & area == df1$area)$temperature))

我收到了这个错误

警告信息:

1: 在计算 average_temp = mean(...) 时出现问题。

i 长对象长度不是短对象长度的倍数


期望的结果是

id 地区 日期1 日期2 平均气温
GR1 A1 2022-01-01 2022-02-12 31.58708
GR2 A2 2022-01-02 2022-02-11 30.50867

这段代码本身可以得出期望的结果。因此,问题必须是我在使用 mutate 和 dplyr 语法迭代行的逻辑中没有注意到的东西。

mean(filter(.data = df2, date3 >= df1$date1[2] & date3 <= df1$date2[2] & area == df1$area[2])$temperature)
1个回答

3

这是一种非等值或基于范围的连接方式。不幸的是,dplyr本身不能完成这项任务,因此我们需要另一个包的帮助。以下提供了几个选项:

fuzzyjoin

fuzzyjoin::fuzzy_left_join(
  df1, df2,
  by = c("area", date1="date3", date2="date3"),
  match_fun=list(`==`, `<=`, `>=`)
) %>%
  group_by(id, date1, date2) %>%
  summarize(
    area = area.x[1],
    avg = mean(temperature)
  ) %>%
  ungroup()
# `summarise()` has grouped output by 'id', 'date1'. You can override using the `.groups` argument.
# # A tibble: 2 x 5
#   id    date1      date2      area    avg
#   <chr> <date>     <date>     <chr> <dbl>
# 1 GR1   2022-01-01 2022-01-06 A1     31.6
# 2 GR2   2022-01-02 2022-01-08 A2     30.5

data.table

library(data.table)
DT1 <- as.data.table(df1)
DT2 <- as.data.table(df2)
DT1[DT2, avg := ave(i.temperature, id, FUN = mean),
    on = .(area, date1 <= date3, date2 >= date3) ]
#        id   area      date1      date2      avg
#    <char> <char>     <Date>     <Date>    <num>
# 1:    GR1     A1 2022-01-01 2022-01-06 31.58708
# 2:    GR2     A2 2022-01-02 2022-01-08 30.50867

我知道有一种更规范的方法可以在没有 ave 的情况下完成,但是我时间不够……

sqldf

sqldf

是一个R软件包,它允许使用SQL语言来操作数据框。
# library(sqldf) # not required to load, per se
sqldf::sqldf(
  "select df1.id, df1.area, df1.date1, df1.date2,
     avg(df2.temperature) as avg
   from df1
     left join df2 on df1.area=df2.area
       and df2.date3 between df1.date1 and df1.date2
   group by df1.id, df1.area, df1.date1, df1.date2")
#    id area      date1      date2      avg
# 1 GR1   A1 2022-01-01 2022-01-06 31.58708
# 2 GR2   A2 2022-01-02 2022-01-08 30.50867

感谢您的解决方案。我将使用模糊版本。处理所有数据时速度较慢,但可以完成任务。 - Andres Hidalgo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接