根据您对问题的描述,以下应该可行
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)))
第一行只是将一个名为ID 的列添加到df,它通过行号来标识行,我们稍后可以dplyr::group_by 进行计数。
接下来的两行将行划分为被盗和未被盗的汽车。关键是:
- 复制每一行被盗汽车
N 次,其中N 是未被盗汽车的行数,
- 复制未被盗汽车的行(作为一个块)
M 次,其中M 是被盗汽车的行数,并且
- 将 (2) 的结果作为新列附加到 (1) 并更改这些新列的名称,以便我们可以在条件中引用它们
(3) 的结果中的行枚举了原始数据帧中所有被盗行和未被盗行的行,因此您的条件可以以数组方式应用。 dplyr 管道 R 工作流是代码的第四行(包装在 print() 中)这样做:
- 第一个命令使用
times复制未被盗的汽车行
- 第二个命令在我们绑定列时将
_not附加到列名中,以将它们与被盗的汽车列区分开来。感谢 this SO answer 的宝石。
- 第三条命令使用
each复制被盗汽车行,并使用dplyr::bind_cols将先前的结果作为新列追加
- 第四条命令使用
dplyr::mutate 创建一个名为in_range 的新列,这是应用条件的结果。布尔结果转换为{0,1} 以便于累积
- 管道中的其余命令对由
ID 分组的in_range 进行计数,并将结果按计数的递减顺序排列。请注意,现在ID 是标识原始数据帧中is_stolen = 1 的行的列,而ID_not 是is_stolen = 0 的行的列
这假设您想要原始数据框中is_stolen = 1 的每一行的计数,这就是您在问题中所说的。相反,如果您真的想要每个被盗的telematic_trip_no 的计数,那么您可以使用
group_by(telematic_trip_no) %>%
改为在管道中。
我已经使用以下数据 sn-p 对此进行了测试
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))
在这里,我将带有 is_stolen = 1 的 7 新行附加到您原来的 6 行,这些行都是 is_stolen = 0:
- 第一个添加的带有
telematic_trip_no = 526005880 的行违反了所有未被盗行的经度条件,因此其计数应为0
- 添加的第二行带有
telematic_trip_no = 526006880 违反了所有未被盗行的纬度条件,因此其计数应为0
- 添加的第三行带有
telematic_trip_no = 526007880 违反了所有未被盗行的telematic_trip_no 条件,因此其计数应为0
- 添加的第四行
telematic_trip_no = 526006890满足4和5未被盗行的条件,因此其计数应为2
- 添加
telematic_trip_no = 526106880 的第五行满足6 行未被窃取的条件,因此其计数应为1
- 添加的第六行带有
telematic_trip_no = 526017880 违反了所有未被盗行的time_of_day 条件,因此其计数应为0
- 添加的第七行带有
telematic_trip_no = 526027880 违反了所有未被盗行的day_of_week 条件,因此其计数应为0
在这个数据上运行代码给出:
# A tibble: 7 x 2
ID count
<int> <dbl>
1 10 2
2 11 1
3 7 0
4 8 0
5 9 0
6 12 0
7 13 0
正如预期的那样,回想带有is_stolen = 1 的附加行从带有ID = 7 的行7 开始。
如果要按telematic_trip_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
需要注意的是,上述方法确实会消耗内存。在最坏的情况下,行数增长到N^2/4,其中N 是原始数据框中的行数,而用于评估条件的数据框的列数加倍。与大多数阵列处理技术一样,速度和内存之间存在折衷。
希望这会有所帮助。