【问题标题】:Mutate data frame with data from another data frame使用来自另一个数据帧的数据改变数据帧
【发布时间】:2022-02-15 06:21:32
【问题描述】:

可重现的数据:

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 area date1 date2 average_temp
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)

【问题讨论】:

    标签: r dataframe date merge mean


    【解决方案1】:

    这是一个非 equi 或基于范围的连接。不幸的是,dplyr 本身无法做到这一点,所以我们需要另一个包的帮助。以下选项:

    模糊连接

    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
    

    数据表

    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

    # 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
    

    【讨论】:

    • 感谢您的解决方案。我将使用模糊版本。处理所有数据时我的速度很慢,但可以完成这项工作。
    猜你喜欢
    • 1970-01-01
    • 2021-12-25
    • 2020-07-24
    • 2015-12-31
    • 2018-12-25
    • 1970-01-01
    • 2020-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多