【问题标题】:R: Trouble coding loop function for feature extraction?R:用于特征提取的编码循环功能有问题?
【发布时间】:2018-12-16 16:06:37
【问题描述】:

我有两个向量:

 EventDate <- c("2018-10-31", "2018-11-16", "2018-12-02")
 ThirtyDaysPriorEvent <- c("2018-10-01", "2018-10-17", "2018-11-02")

我需要帮助为以下工作流程编写循环函数:

  1. 遍历向量以识别相同索引位置的日期, 并将它们存储在变量中。例如,第一对日期 将是 EventDate[1] 和 ThirtyDaysPriorEvent[1]。对于示例数据,值为“2018-10-31”和“2018-10-01”。
  2. 在 dplyr 的过滤器中使用变量作为日期参数 功能。查询 db 以获取每个事件日期前 30 天发生的所有活动。将结果存储在名为 Activities30dys 的数据框中。
  3. 计算Activities30dys 数据框中列的总和。
  4. 使用第 3 步中的计算值在事件数据框中创建一个新列。

这是我想要达到的结果:

事件数据框中名为“d”的新列源自活动数据框中“x”列中的聚合值。

      date  a    b     c     d
2018-10-31 42 60.5 152.4 16.63
2018-11-16 54 54.1 151.6 16.63
2018-12-02 63 74.2 153.5 19.95

然而,这是我所得到的:

 library(dplyr)

 # identifies dates in the same index position for each vector & stores results in variables
 e <- EventDate[1]
 e30 <- ThirtyDaysPriorEvent[1]

 # uses variables to filter Activities dataframe
 Activities30Dys <- Activities %>%
   filter(date > e30 & date < e) 

 # computes sum of x activity done 30 days prior to event date
 sum(Activities30Dys$x, na.rm = TRUE)

 # adds new column (d) to Events dataframe
 Events %>%
   mutate()

这是我的可复制数据:

     Events <- structure(list(date = c("2018-10-31", "2018-11-16", "2018-12-02"
), a = c(42L, 54L, 63L), b = c(60.5, 54.1, 74.2), c = c(152.4, 
151.6, 153.5)), .Names = c("date", "a", "b", "c"), row.names = 
c(NA, 3L), class = "data.frame")

     Activities <- structure(list(date = c("2018-09-18", "2018-09-19", "2018-10-21", 
"2018-10-21", "2018-10-24", "2018-10-26", "2018-10-27", "2018-11-18", 
"2018-11-19", "2018-11-21", "2018-11-24", "2018-11-26", "2018-11-27", 
"2018-12-05"), x = c(3.43, 3.16, 3.2, 3.27, 3.74, 3.2, 3.22, 
3.43, 3.16, 3.2, 3.74, 3.2, 3.22, 3.02), y = c(132L, 122L, 120L, 
130L, 127L, 128L, 127L, 132L, 122L, 120L, 127L, 128L, 127L, 121L
)), .Names = c("date", "x", "y"), row.names = c(NA, 14L), class = "data.frame")

如何使用 R 最好地实现我的目标?

【问题讨论】:

    标签: r for-loop dplyr feature-extraction


    【解决方案1】:

    我会采用几种方法来处理它,这取决于它如何适合您的工作流程。 purrr::map 系列函数使映射这些向量而不是循环变得容易。在这种情况下,map2 将同时映射到一对向量上。

    我要注意的第一件事是,由于您正在处理日期,因此最好将它们视为此类并转换为 Date 类。

    另一件事是不清楚您是否希望您的端点在过滤时是inclusiveexclusive。我使用dplyr::between 作为速记,但这将包括端点。我会让你根据需要调整。

    一种方法是用map2_dfr 映射两个日期向量以返回数据框,过滤Activities,按开始日期分组,然后汇总。这将为您提供一个数据框,然后您可以将其与Events 连接,前提是您已将其日期转换为真实的Dates。

    library(dplyr)
    library(purrr)
    
    sums_df <- map2_dfr(as.Date(EventDate), as.Date(ThirtyDaysPriorEvent), function(e, e30) {
      activities30dys <- Activities %>%
        mutate(date = as.Date(date)) %>%
        filter(between(date, e30, e)) %>%
        group_by(date = e) %>%
        summarise(d = sum(x, na.rm = T))
    
      activities30dys
    })
    
    Events %>%
      mutate(date = as.Date(date)) %>%
      left_join(sums_df, by = "date")
    #>         date  a    b     c     d
    #> 1 2018-10-31 42 60.5 152.4 16.63
    #> 2 2018-11-16 54 54.1 151.6 16.63
    #> 3 2018-12-02 63 74.2 153.5 19.95
    

    另一种选择是执行类似的map2,但使用map2_dbl 返回单个数字向量。然后您可以mutate 将此作为列添加到Events

    sums_dbl <- map2_dbl(as.Date(EventDate), as.Date(ThirtyDaysPriorEvent), function(e, e30) {
      activities30dys <- Activities %>%
        mutate(date = as.Date(date)) %>%
        filter(between(date, e30, e))
    
      sum(activities30dys$x, na.rm = T)
    })
    
    Events %>%
      mutate(d = sums_dbl)
    #>         date  a    b     c     d
    #> 1 2018-10-31 42 60.5 152.4 16.63
    #> 2 2018-11-16 54 54.1 151.6 16.63
    #> 3 2018-12-02 63 74.2 153.5 19.95
    

    最后要注意的是,您无需同时存储活动日期和 30 天前日期的向量,而是可以随时计算之前的日期。如果您已转换为 Date,则 e - 30 会为您提供 30 天前的日期,您可以像这样构建您的工作流程:

    map(as.Date(EventDate), function(e) {
      e30 <- e - 30
      # ...
    })
    

    【讨论】:

    • 感谢您分享一些很棒的想法以及解决问题的选项!
    【解决方案2】:

    这是一种方法。在众多之中。

    extend_df <- function(events, priors, data) {
    
    require(dplyr)
    
    monthly <- list()
    for (i in seq_along(events)) {
    
      to <- events[i]
      from <- priors[i]
    
      monthly[[i]] <- data %>%
        filter(date > from & date < to) %>% 
        summarise(n = sum(x)) %>% 
        pull(n)
    
    
      }
    return(monthly)
    }
    
    Events %>% mutate(d = extend_df(EventDate, ThirtyDaysPriorEvent, Activities))
    
            date  a    b     c     d
    1 2018-10-31 42 60.5 152.4 16.63
    2 2018-11-16 54 54.1 151.6 16.63
    3 2018-12-02 63 74.2 153.5 19.95
    

    【讨论】:

    • 在函数定义中调用library 意味着每次调用该函数时都在加载库
    • 很高兴它为@codeinspired 工作。感谢@camille 的谨慎,将library() 更改为require()
    【解决方案3】:

    我确信我们可能会为此提供完整的 dplyr 解决方案,但不能不显着重塑数据。

    所以我提供了一个简单的 for 循环解决方案,主要是重复使用您编写的代码。小的修改是为了代码的易读性:

    #-- Initialize d
    Events$d <- NA
    
    #-- Run loop
    for (i in 1:nrow(Events)) {
      e <- Events$date[i]
      e30 <- e - 30
      Events$d[i] <- Activities %>%
        filter(between(date, e30, e)) %>%
        summarize(x = sum(x, na.rm = TRUE)) %>%
        pull()
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-25
      • 1970-01-01
      • 2020-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-28
      相关资源
      最近更新 更多