使用dplyr根据条件分组计算行数

使用dplyr根据条件分组计算行数,r,dplyr,R,Dplyr,我有一个数据框,如下所示: position_time telematic_trip_no lat_dec lon_dec 1 2016-06-05 00:00:01 526132109 -26.6641 27.8733 2 2016-06-05 00:00:01 526028387 -26.6402 27.8059 3 2016-06-05 00:00:01 526081476 -26.5545 28.3263 4 2016-0

我有一个数据框,如下所示:

        position_time telematic_trip_no  lat_dec lon_dec
1 2016-06-05 00:00:01         526132109 -26.6641 27.8733
2 2016-06-05 00:00:01         526028387 -26.6402 27.8059
3 2016-06-05 00:00:01         526081476 -26.5545 28.3263
4 2016-06-05 00:00:04         526140512 -26.5310 27.8704
5 2016-06-05 00:00:05         526140518 -26.5310 27.8704
6 2016-06-05 00:00:19         526006880 -26.5010 27.8490 
  is_stolen hour_of_day time_of_day day_of_week  lat_min
1         0           0           0      Sunday -26.6651
2         0           0           0      Sunday -26.6412
3         0           0           0      Sunday -26.5555
4         0           0           0      Sunday -26.5320
5         0           0           0      Sunday -26.5320
6         0           0           0      Sunday -26.5020
   lat_max lon_max lon_min 
1 -26.6631 27.8743 27.8723     
2 -26.6392 27.8069 27.8049    
3 -26.5535 28.3273 28.3253    
4 -26.5300 27.8714 27.8694      
5 -26.5300 27.8714 27.8694      
6 -26.5000 27.8500 27.8480     
现在我要做的是计算每一行的行数,其中is_sleet=1,数据帧中满足以下条件的行数:

  • lat_dec和lon_dec位于lat_max、lat_min、lon_max和lon_min之间(即,安装在GPS点周围的“框”内)
  • 日的时间和周的日期与兴趣行的时间相同
  • 行的远程信息处理路径号需要与感兴趣行的不同
  • 最后,匹配行的is_被盗标记需要等于0
我已经编写了一个脚本,使用for循环来实现这一点,但它运行得非常慢,这让我想到是否有一种有效的方法可以使用dplyr或data.table之类的东西在多种条件下进行复杂的行计数


ps如果你好奇的话,我真的想计算一辆被盗汽车在一次典型的旅行中经过多少辆车:)

根据你对问题的描述,下面应该可以

library(dplyr)
library(stats)
# df is the data.frame (see below)
df <- cbind(ID=seq_len(nrow(df)),df)
r.stolen <- which(df$is_stolen == 1)
r.not <- which(df$is_stolen != 1)
print(df[rep(r.not, times=length(r.stolen)),] %>%
  setNames(.,paste0(names(.),"_not")) %>%
    bind_cols(df[rep(r.stolen, each=length(r.not)),], .) %>% 
      mutate(in_range = as.numeric(telematic_trip_no != telematic_trip_no_not & time_of_day == time_of_day_not & day_of_week == day_of_week_not & lat_dec >= lat_min_not & lat_dec <= lat_max_not & lon_dec >= lon_min_not & lon_dec <= lon_max_not)) %>%
        group_by(ID) %>%
          summarise(count = sum(in_range)) %>% 
            arrange(desc(count)))
而是在管道里

我已经使用以下数据片段对此进行了测试

df <- structure(list(position_time = structure(c(1L, 1L, 1L, 2L, 3L, 
                4L, 4L, 5L, 6L, 7L, 8L, 9L, 10L), .Label = c("2016-06-05 00:00:01", 
                "2016-06-05 00:00:04", "2016-06-05 00:00:05", "2016-06-05 00:00:19", 
                "2016-06-05 00:00:20", "2016-06-05 00:00:22", "2016-06-05 00:00:23", 
                "2016-06-05 00:00:35", "2016-06-05 00:09:34", "2016-06-06 01:00:06"
                ), class = "factor"), telematic_trip_no = c(526132109L, 526028387L, 
                526081476L, 526140512L, 526140518L, 526006880L, 526017880L, 526027880L, 
                526006880L, 526006890L, 526106880L, 526005880L, 526007880L), 
                lat_dec = c(-26.6641, -26.6402, -26.5545, -26.531, -26.531, 
                -26.501, -26.5315, -26.5325, -26.501, -26.5315, -26.5007, 
                -26.5315, -26.5315), lon_dec = c(27.8733, 27.8059, 28.3263, 
                27.8704, 27.8704, 27.849, 27.88, 27.87, 27.849, 27.87, 27.8493, 
                27.87, 27.87), is_stolen = c(0L, 0L, 0L, 0L, 0L, 0L, 1L, 
                1L, 1L, 1L, 1L, 1L, 1L), hour_of_day = c(0L, 0L, 0L, 0L, 
                0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), time_of_day = c(0L, 
                0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 9L, 0L), day_of_week = structure(c(2L, 
                2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 1L), .Label = c("Monday", 
                "Sunday"), class = "factor"), lat_min = c(-26.6651, -26.6412, 
                -26.5555, -26.532, -26.532, -26.502, -26.532, -26.532, -26.502, 
                -26.532, -26.502, -26.532, -26.532), lat_max = c(-26.6631, 
                -26.6392, -26.5535, -26.53, -26.53, -26.5, -26.53, -26.53, 
                -26.5, -26.53, -26.5, -26.53, -26.53), lon_max = c(27.8743, 
                27.8069, 28.3273, 27.8714, 27.8714, 27.85, 27.8714, 27.8714, 
                27.85, 27.8714, 27.85, 27.8714, 27.8714), lon_min = c(27.8723, 
                27.8049, 28.3253, 27.8694, 27.8694, 27.848, 27.8694, 27.8694, 
                27.848, 27.8694, 27.848, 27.8694, 27.8694)), .Names = c("position_time", 
                "telematic_trip_no", "lat_dec", "lon_dec", "is_stolen", "hour_of_day", 
                "time_of_day", "day_of_week", "lat_min", "lat_max", "lon_max", 
                "lon_min"), class = "data.frame", row.names = c(NA, -13L))
正如预期的那样,带有
的附加行从带有
ID=7的
7行开始

如果一个人改为按
远程信息处理\u trip\u no
分组,我们得到的结果是:

# A tibble: 7 x 2
  telematic_trip_no count
              <int> <dbl>
1         526006890     2
2         526106880     1
3         526005880     0
4         526006880     0
5         526007880     0
6         526017880     0
7         526027880     0
#一个tible:7 x 2
远程信息处理\u跳闸\u不计算
1         526006890     2
2         526106880     1
3         526005880     0
4         526006880     0
5         526007880     0
6         526017880     0
7         526027880     0
作为警告,上述方法确实会消耗内存。最坏情况下,行数增长到
N^2/4
,其中
N
是原始数据帧中的行数,用于评估条件的数据帧的列数加倍。与大多数阵列处理技术一样,速度和内存之间存在权衡

希望这能有所帮助。

有一个新特性非等联接,它使条件联接非常简单。使用@aichao的数据:

require(data.table) # v1.9.7+
setDT(df)[, ID := .I] # add row numbers
not_stolen = df[is_stolen == 0L]
is_stolen  = df[is_stolen == 1L]

not_stolen[is_stolen, 
    .(ID = i.ID, N = .N - sum(telematic_trip_no == i.telematic_trip_no)), 
    on = .(time_of_day, day_of_week, lat_min <= lat_dec, 
          lat_max >= lat_dec, lon_min <= lon_dec, lon_max >= lon_dec), 
    by=.EACHI][, .(ID, N)]
#    ID  N
# 1:  7 NA
# 2:  8 NA
# 3:  9  0
# 4: 10  2
# 5: 11  1
# 6: 12 NA
# 7: 13 NA
require(data.table)#v1.9.7+
setDT(df)[,ID:=.I]#添加行号
未被盗=df[被盗==0L]
被偷=df[被偷=1L]
不是被偷的,
(ID=i.ID,N=.N-sum(远程通信跳闸号==i.远程通信跳闸号)),
on=(一天中的时间,一周中的日期,纬度=纬度,纬度=纬度,
by=.EACHI][,(ID,N)]
#身份证号码
#1:7 NA
#2:8 NA
# 3:  9  0
# 4: 10  2
# 5: 11  1
#6:12 NA
#7:13 NA
部分
未被窃取[被窃取,
执行类似于联接操作的子集。。即,对于
中的每一行,提取匹配的行索引(基于提供给
on=
参数的条件)

by=.EACHI
确保,对于
i
(第一)参数中的每一行,这里的
在相应的匹配行索引上被窃取
,在
j
中提供的表达式,第二个参数,
(ID=i.ID,N=.N-sum(远程通信\u trip\u no==i.telematic\u trip\u no)),
进行计算。这将返回上面显示的结果


HTH.

dput()
足够的数据,包括必要的条件,将有助于其他人帮助您。您是否也可以包括不起作用的“for-loop”代码?“感兴趣的行”指的是什么?您是否选择一行,然后将其与所有其他行进行比较?尝试使用
which()
语句来创建满足所有条件的行的子集。这样,它只需在提取相应数据时对数据集进行一次迭代。您可能需要两到四条语句的序列来保持人类可读性和紧凑性,但通常比复杂循环更快、更不容易出错。下面是C运行说明。我正在寻找这样的连接函数。很高兴知道。谢谢。
# A tibble: 7 x 2
  telematic_trip_no count
              <int> <dbl>
1         526006890     2
2         526106880     1
3         526005880     0
4         526006880     0
5         526007880     0
6         526017880     0
7         526027880     0
require(data.table) # v1.9.7+
setDT(df)[, ID := .I] # add row numbers
not_stolen = df[is_stolen == 0L]
is_stolen  = df[is_stolen == 1L]

not_stolen[is_stolen, 
    .(ID = i.ID, N = .N - sum(telematic_trip_no == i.telematic_trip_no)), 
    on = .(time_of_day, day_of_week, lat_min <= lat_dec, 
          lat_max >= lat_dec, lon_min <= lon_dec, lon_max >= lon_dec), 
    by=.EACHI][, .(ID, N)]
#    ID  N
# 1:  7 NA
# 2:  8 NA
# 3:  9  0
# 4: 10  2
# 5: 11  1
# 6: 12 NA
# 7: 13 NA