【问题标题】:using lead or lag from dplyr in combination with other variables将 dplyr 中的领先或滞后与其他变量结合使用
【发布时间】:2018-09-12 12:00:53
【问题描述】:

我有一个数据框:

                 Time   CardID    Data      Type
1  2018-01-01 10:44:35 10037479 PowerOn  STBEvent
2  2018-01-01 10:44:48 10037479    0401 UseRemote
3  2018-01-01 10:44:53 10037479    0301 UseRemote
4  2018-01-01 10:45:13 10037479    0401 UseRemote
5  2018-01-01 10:45:24 10037479    0301 UseRemote
6  2018-01-01 10:45:30 10037479    1415  LiveView
7  2018-01-01 10:45:37 10037479    0401 UseRemote
8  2018-01-01 11:08:01 10037479    1412  LiveView
9  2018-01-01 11:08:13 10037479    0401 UseRemote
10 2018-01-01 11:14:31 10037479    0301 UseRemote

structure(list(Time = structure(c(1514783675, 1514783688, 1514783693, 
1514783713, 1514783724, 1514783730, 1514783737, 1514785081, 1514785093, 
1514785471), class = c("POSIXct", "POSIXt")), CardID = c("10037479", 
"10037479", "10037479", "10037479", "10037479", "10037479", "10037479", 
"10037479", "10037479", "10037479"), Data = c("PowerOn", "0401", 
"0301", "0401", "0301", "1415", "0401", "1412", "0401", "0301"
), Type = c("STBEvent", "UseRemote", "UseRemote", "UseRemote", 
"UseRemote", "LiveView", "UseRemote", "LiveView", "UseRemote", 
"UseRemote")), .Names = c("Time", "CardID", "Data", "Type"), row.names = c(NA, 
10L), class = "data.frame")

我正在使用 dplyr 的超前和滞后函数来获取特定行之前和之后的数据点。例如我正在使用这个:

ae1 <- which(dplyr::lag(df$Data)=="1415")+1

这让我从上面的数据框中获得第 6 行,其中 Type 等于“LiveView”。我理解通过更改代码末尾的整数,我可以从数据框中获取相应的行。我的问题是:我可以使用相同/相似的功能,其中我可以获取下一个“LiveView”的数据 - 这是第 8 行。我可以很好地做到

ae1 <- which(dplyr::lag(df$Data)=="1415")+3

获取第 8 行。但是下一个 LiveView 类型可以出现在除 8 之外的任何行中。我在想类似于

ae1 <- which(dplyr::lag(df$Data)=="1415")+nrow(where Type == next "LiveView")

【问题讨论】:

  • 您的预期结果有点不清楚。假设您的数据框名为df,可能类似于group_by(df, Type) %&gt;% mutate(lag1 = lag(Data, 1))。还有lead函数,它朝相反的方向移动。
  • 我同意@jdobres。目前尚不清楚您要做什么以及您的预期输出应该是什么样子。您能否编辑您的问题以包含您提供的特定样本数据的预期输出?
  • 是的,这一点都不清楚。请用文字说明目标。是获取行号吗?行本身?第一个 LiveWire 行超过第一个 1415 行?
  • “这让我得到第 6 行”——不,8,当我运行代码时。

标签: r dplyr


【解决方案1】:

1) 如果目标是找到第一个 1415 行之后的第一个 LiveWire 行的行号,则使用显示的连词,后跟 whichfirst 得到行号和这些行号中的第一个。请注意,cummany 对于 1415 之后的第一个 Data 组件是正确的,并且通过滞后它,我们仅对它之后的那些组件才正确。如果我们知道只有一个这样的行,那么我们可以省略first。由于 dplyr 的延迟与基础中的 lag 冲突,我们使用 dplyr::lag 来确保我们使用的是所需的。

df %>% 
  { dplyr::lag(cumany(.$Data == 1415)) & .$Type == "LiveView" } %>%
  which %>%
  first
  ## [1] 8

2) 如果我们想要行本身而不是使用filterslice。如果我们知道只有一个这样的行,我们可以省略slice

df %>% 
  filter(dplyr::lag(cumany(Data == 1415)) & Type == "LiveView") %>%
  slice(1)
##                  Time   CardID Data     Type
## 1 2018-01-01 00:38:01 10037479 1412 LiveView

请注意,如果我们通过将第一行代码替换为以下代码,将行号添加到 df

df %>% mutate(n = 1:n()) %>%

那么除了其他列中的行本身之外,上述代码还将给出n 列中的行号。

2a) (2) 的替代方案是,我们可以首先按cumany(Data == 1415) 过滤,以给出从前 1415 行开始的所有行,然后删除第一行,因为我们只想要行 在它之后,然后在其中找到LiveView 行并取第一个。

df %>% 
  filter(cumany(Data == 1415)) %>%
  slice(-1) %>%
  filter(Type == "LiveView") %>%
  slice(1)
##                  Time   CardID Data     Type
## 1 2018-01-01 00:38:01 10037479 1412 LiveView

更新

修订。

【讨论】:

    【解决方案2】:

    我正在使用 dplyr 中的超前和滞后函数来获取特定行之前和之后的数据点。 [...] 我可以使用相同/相似的功能,其中我可以在下一个“LiveView”中获取数据[?]

    如果对于 Data == 1415 的每个实例,您想要找到 CardID 匹配、Type 匹配且 Time 更大的下一行,那么...

    library(data.table)
    setDT(df)
    
    mdf = df[Data == "1415", .(CardID, Type, Time)]
    w   = df[mdf, on=.(CardID, Type, Time > Time), mult="first", which=TRUE]
    df[w]
    
    #                   Time   CardID Data     Type
    # 1: 2018-01-01 00:38:01 10037479 1412 LiveView
    

    如果您有重复的时间,那么Time 将不能用作行号。您可以添加一个行号,例如 df[, rn := .I]df[, rn := rowid(CardID)] 并使用它来代替。

    on= 的行是非 equi 连接,目前在 dplyr 中不可用,这就是为什么我在这里使用不同的包发布。


    如果你想返回两行......

    w0 = df[Data == "1415", which=TRUE]
    w  = df[df[w0], on=.(CardID, Type, Time > Time), mult="first", which=TRUE]
    df[matrix(c(w0, w), 2, byrow=TRUE)]
    
    #                   Time   CardID Data     Type
    # 1: 2018-01-01 00:15:30 10037479 1415 LiveView
    # 2: 2018-01-01 00:38:01 10037479 1412 LiveView
    

    或者如果您还想要行前的数据点:

    wb = df[df[w0], on=.(CardID, Type, Time < Time), mult="first", which=TRUE]
    df[matrix(c(wb, w0, w), 3, byrow=TRUE)]
    
    #                   Time   CardID Data     Type
    # 1:                <NA>     <NA> <NA>     <NA>
    # 2: 2018-01-01 00:15:30 10037479 1415 LiveView
    # 3: 2018-01-01 00:38:01 10037479 1412 LiveView
    

    显示 NA,因为没有行符合这些条件。

    【讨论】:

      【解决方案3】:

      执行此操作的一种方法是dplyr::group_by 基于感兴趣的Typedplyr::filterType 的数据,然后将dplyr::slice 定位到您想要的位置,在这种情况下,位置@987654326 @:

      library(dplyr)
      
      df <- 
        structure(
          list(
            Time = 
              structure(c(1514783675, 1514783688, 1514783693, 
                          1514783713, 1514783724, 1514783730, 1514783737, 1514785081, 1514785093, 
                          1514785471), class = c("POSIXct", "POSIXt")), 
            CardID = c("10037479", "10037479", "10037479", "10037479", "10037479", "10037479", "10037479", 
                       "10037479", "10037479", "10037479"), 
            Data = c("PowerOn", "0401", "0301", "0401", "0301", "1415", "0401", "1412", "0401", "0301"), 
            Type = c("STBEvent", "UseRemote", "UseRemote", "UseRemote", 
                     "UseRemote", "LiveView", "UseRemote", "LiveView", "UseRemote", 
                     "UseRemote")), 
          .Names = c("Time", "CardID", "Data", "Type"), 
          row.names = c(NA, 10L), 
          class = "data.frame")
      
      
      df %>% 
      group_by(Type) %>% 
      filter(Type %in% 'LiveView') %>% 
      slice(2)
      

      【讨论】:

        猜你喜欢
        • 2023-04-04
        • 2020-10-19
        • 1970-01-01
        • 1970-01-01
        • 2020-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多