【问题标题】:Using the result of summarise (dplyr) to mutate the original dataframe使用 summarise (dplyr) 的结果来改变原始数据帧
【发布时间】:2014-10-05 15:33:21
【问题描述】:

我有一个相当大的数据框,其中有一列 POSIXct 日期时间(约 10 年的每小时数据)。我会标记当天属于夏令时的所有行。例如,如果夏令时从 '2000-04-02 03:00:00' (DOY=93) 开始,我希望可以标记 DOY=93 的前两个小时。 虽然我是 dplyr 的新手,但我会尽可能地使用这个包并尽可能地避免 for-loops

例如:

library(lubridate)
sd = ymd('2000-01-01',tz="America/Denver")
ed = ymd('2005-12-31',tz="America/Denver")
span = data.frame(date=seq(from=sd,to=ed, by="hour"))
span$YEAR = year(span$date)
span$DOY = yday(span$date)
span$DLS = dst(span$date)

要查找应用夏令时的一年中的不同日子,我使用 dplyr

library(dplyr)
limits = span %.% group_by(YEAR) %.% summarise(minDOY=min(DOY[DLS]),maxDOY=max(DOY[DLS]))

这给了

      YEAR minDOY maxDOY
    1 2000     93    303
    2 2001     91    301
    3 2002     97    300
    4 2003     96    299
    5 2004     95    305
    6 2005     93    303

现在我将在 span 数据帧中“管道”上述结果,而不使用效率低下的 for-loop

解决方案 1

在@aosmith 的帮助下,只需两个命令即可解决问题(并避免使用“解决方案 2”中的 inner_join):

 limits = span %>% group_by(YEAR) %>% mutate(minDOY=min(DOY[DLS]),maxDOY=max(DOY[DLS]),CHECK=FALSE)

 limits$CHECK[(limits2$DOY >= limits$minDOY) & (limits$DOY <= limits$maxDOY) ] = TRUE      

解决方案 2

在@beetroot 和@matthew-plourde 的帮助下,问题已经解决了: 缺少一个内部连接:

limits = span %>% group_by(YEAR) %>% summarise(minDOY=min(DOY[DLS]),maxDOY=max(DOY[DLS])) %>% inner_join(span, by='YEAR')

然后我添加了一个新列 (CHECK) 来填充夏令时的正确值

limits$CHECK = FALSE
limits$CHECK[(limits$DOY >= limits$minDOY) & (limits$DOY <= limits$maxDOY) ] = TRUE

【问题讨论】:

  • 所以你想在 span 中有两个新列,minDOY 和 maxDOY 并且它们的值在每一行和各自的年份重复?这可能可以用 left_join 完成,但如果没有示例数据就无法测试。
  • 感谢@beetroot 的提示。我现在就试试!对于示例数据...上面的代码对您不起作用?
  • 啊,我只是没有安装 lubridate,现在我懒得这样做了;)
  • 没问题,甜菜根!在您的帮助和 matthew-plourde 的帮助下,一切都已解决。多亏了 oropendola,现在我有了一个新工具。见上面的代码。
  • 向现有数据集添加新列似乎是 mutate 的工作,而不是 summarise 加入的工作。

标签: r dplyr posixct lubridate


【解决方案1】:

按照@aosmith 的建议,完成工作的最佳解决方案是。

limits = span %>% group_by(YEAR) %>% mutate(minDOY=min(DOY[DLS]),maxDOY=max(DOY[DLS]),CHECK=FALSE)

limits$CHECK[(limits2$DOY >= limits$minDOY) & (limits$DOY <= limits$maxDOY) ] = TRUE

使用 ave 函数是一个不错的选择,但我个人更喜欢坚持使用 'dplyr' 包。

【讨论】:

    【解决方案2】:

    dplyr 是一个很棒的工具,但在这种情况下,我不确定它是否最适合这项工作。这样就完成了你的任务:

    span$CHECK <- ave(dst(span$date), as.Date(span$date, tz = tz(span$date)), FUN = any)
    

    我认为ave 是这个函数的一个糟糕的名称,但如果你记得它存在,当你想将摘要加入到它来自的 data.frame 时,它​​通常非常有用。

    【讨论】:

    • 嗯...像往常一样,在 R 中总是有学习新功能和新技巧的空间。我以前从未使用过 ave 功能。我马上试试!
    • 这与 OP 中的CHECK 给出的结果不同。您需要同时按YEARDOY 进行分组。我喜欢你对any 的使用,这使得CHECK 的创建如此简单。我认为 dplyr 等价物是 span %&gt;% group_by(YEAR, DOY) %&gt;% mutate(CHECK = any(DLS))
    • 感谢@aosmith,这是一个错误。我解决了这个问题并使它可以仅使用span$date 在一行中计算CHECK
    【解决方案3】:

    正如@beetroot 在 cmets 中指出的那样,您可以通过连接来完成此操作:

    limits = span %>% 
       group_by(YEAR) %>% 
       summarise(minDOY=min(DOY[DLS]),maxDOY=max(DOY[DLS])) %>%
       inner_join(span, by='YEAR')
    #    YEAR minDOY maxDOY                date DOY   DLS
    # 1  2000     93    303 2000-01-01 00:00:00   1 FALSE
    # 2  2000     93    303 2000-01-01 01:00:00   1 FALSE
    # 3  2000     93    303 2000-01-01 02:00:00   1 FALSE
    # 4  2000     93    303 2000-01-01 03:00:00   1 FALSE
    # 5  2000     93    303 2000-01-01 04:00:00   1 FALSE
    # 6  2000     93    303 2000-01-01 05:00:00   1 FALSE
    # 7  2000     93    303 2000-01-01 06:00:00   1 FALSE
    # 8  2000     93    303 2000-01-01 07:00:00   1 FALSE
    # 9  2000     93    303 2000-01-01 08:00:00   1 FALSE
    # 10 2000     93    303 2000-01-01 09:00:00   1 FALSE
    

    【讨论】:

    • 加入是完成我的任务的中间步骤。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-07
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 2015-08-03
    • 2015-04-23
    • 2018-08-03
    相关资源
    最近更新 更多