选择其他df中不存在的行

时间:2019-02-14 15:06:04

标签: r sqldf not-exists

我有一个包含旅行ID,停车ID,时间戳和速度的DF。

   trip_id stop_id speed timestamp
 1       1       1     5         1
 2       1       1     0         2
 3       1       1     0         3
 4       1       1     5         4
 5       1       2     2       101
 6       1       2     2       102
 7       1       2     2       103
 8       1       2     2       104
 9       1       3     4       201
10       1       3     0       202

对于trip_id和stop_id相同的组,我已经保存了速度为零的第一行和最后一行。

df_departure_z <- sqldf("SELECT trip_id, stop_id, MAX(timestamp) FROM df WHERE speed = 0 GROUP BY trip_id,stop_id")
df_arrival_z <- sqldf("SELECT trip_id, stop_id, MIN(timestamp) FROM df WHERE speed = 0 GROUP BY trip_id,stop_id")

哪个给出了结果:

df_departure_z:

trip_id stop_id MAX(timestamp)
1       1       1              3
2       1       3            203

df_arrival_z:

trip_id stop_id MIN(timestamp)
1       1       1              2
2       1       3            202

我的问题:存在一个速度永远不为零的停靠点(停靠点2),因此我想找到一种方法来为速度永远不为零的停靠点保存一个时间戳。我已经尝试过了:

df_arr_dep <- sqldf("SELECT trip_id, stop_id, MIN(timestamp) FROM df GROUP BY trip_id, stop_id EXCEPT SELECT trip_id, stop_id FROM df_arrival_z ")

但是这给了我一个错误,因为我试图基于另一个df中两列中的值保存三列。基本上,我想再次搜索我的df并找到那些不在df_departure_z或df_arrival_z中的trip_id和stop_id的组合。如果我尝试使用SELECT *,则会得到所有未保存的行,这也是错误的。

2 个答案:

答案 0 :(得分:0)

除了sqldf之外,您还可以使用其他库吗?我认为以下功能可以满足您使用dplyr的需求:

library(dplyr)

dat %>%
  group_by(trip_id, stop_id) %>%
  filter(speed == 0 | sum(speed == 0) == 0) %>%
  summarize(min_time = min(timestamp),
            max_time = if_else(sum(speed == 0) == 0,
                               NA_real_,
                               max(timestamp)))

# A tibble: 3 x 4
# Groups:   trip_id [?]
  trip_id stop_id min_time max_time
    <int>   <int>    <dbl>    <dbl>
1       1       1        2        3
2       1       2      101       NA
3       1       3      202      202

数据

dat <- structure(list(trip_id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L),
                      stop_id = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L), 
                      speed = c(5L, 0L, 0L, 5L, 2L, 2L, 2L, 2L, 4L, 0L),
                      timestamp = c(1L, 2L, 3L, 4L, 101L, 102L, 103L, 104L, 201L, 202L)),
                 .Names = c("trip_id", "stop_id", "speed", "timestamp"), 
                 row.names = c(NA, -10L),
                 class = "data.frame")

答案 1 :(得分:0)

如果我对每次旅行和停车的理解正确,那么您希望该行的速度为零的最大时间戳行,或者如果没有这样的行,则该组中非零速度的行的最大时间戳行。进一步向下,我们做出另一种假设,即在组中没有0个速度行的情况下,仅使用NA。之后,我们讨论问题中的EXCEPT查询。

在上述第一种情况下,按行程,停止和速度== 0进行分组。如果速度为0和非0,则每次行程将产生2行并停止,如果存在0和非0速度,则将给出1行行程并停止只是非零速度。在每个组中,我们以速度== 0的行为最大。由于TRUE> FALSE,所以如果有两行,它将采用速度为0的行,否则将采用单个非零速度的行。

sqldf("SELECT trip_id, stop_id, timestamp, MAX(speed0) speed0
  FROM 
    (SELECT trip_id, stop_id, MAX(timestamp) timestamp, speed == 0 speed0
    FROM df 
    GROUP BY 1, 2, 4)
  GROUP BY 1, 2")

给予:

  trip_id stop_id timestamp speed0
1       1       1         3      1
2       1       2       104      0
3       1       3       202      1

speed0第1行中的1表示为该组找到了速度== 0行,因此该组仅使用了速度== 0行的最大时间戳。同样,在第2行中,speed0的0表示该组中没有找到speed == 0的行,因此它使用了该组中非0行的最大时间戳。

如果您不希望第4列,只需在末尾添加[-4]即可。

替代解释

如果您想要的是那些行中不适用的NA,则没有速度== 0,则只需替换上面sql中的第一行,如下所示:

sqldf("SELECT trip_id, stop_id, NULLIF(MAX(speed0) * timestamp, 0) timestamp
  FROM 
    (SELECT trip_id, stop_id, MAX(timestamp) timestamp, speed == 0 speed0
    FROM df 
    GROUP BY 1, 2, 4)
  GROUP BY 1, 2")

给予:

  trip_id stop_id timestamp
1       1       1         3
2       1       2        NA
3       1       3       202

另一种方法是使用左联接给出相同的结果:

sqldf("WITH a(trip_id, stop_id) AS (
         SELECT distinct trip_id, stop_id
         FROM df),
      b(trip_id, stop_id, timestamp) AS (
         SELECT trip_id, stop_id, MAX(timestamp) timestamp
         FROM df
         WHERE speed == 0
         GROUP BY 1, 2)
      SELECT *
      FROM a LEFT JOIN b
      USING (trip_id, stop_id)")

例外与不存在

关于涉及EXCEPT的问题的最后一行代码,将使用以下涉及NOT EXISTS的相关子查询来完成:

sqldf("SELECT a.trip_id, a.stop_id, MIN(a.timestamp) timestamp
  FROM df a
  WHERE NOT EXISTS  (
    SELECT *
    FROM df b
    WHERE speed == 0 AND a.trip_id = b.trip_id AND a.stop_id = b.stop_id)
  GROUP by 1, 2")

给予:

  trip_id stop_id timestamp
1       1       2       101

注意

我们假定此输入以可重复的形式显示:

Lines <- "
   trip_id stop_id speed timestamp
 1       1       1     5         1
 2       1       1     0         2
 3       1       1     0         3
 4       1       1     5         4
 5       1       2     2       101
 6       1       2     2       102
 7       1       2     2       103
 8       1       2     2       104
 9       1       3     4       201
10       1       3     0       202"
df <- read.table(text = Lines)