使用R,如何根据多个条件对对象进行计数?

时间:2020-04-15 05:40:49

标签: r dplyr data.table

我正在尝试根据某些条件对911呼叫的数据帧中的对象进行计数,但是逻辑上遇到了麻烦。我的实际数据有超过300万行,因此我尝试通过考虑以下小子集来简化问题:

dat <- structure(list(call = c("14-1234", "14-4523", "14-7711", "14-8199", "14-3124"), 
                      badge = c("8456", "1098", "3432", "4750", "5122"),
                      off.sex = c("Male", "Male", "Female", "Male", "Male"),
                      shift = c("1", "1", "1", "1", "2"),
                      assignedmin = c(1902, 1870, 1950, 1899, 1907),
                      clearedmin = c(1980, 1910, 1990, 1912, 1956)),
                 class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -5L))

变量“ call”标识911呼叫,“徽章”标识人员,“轮班”基本上标识特定区域中的时间段。呼叫进入的特定分钟数由“ assignedmin”给出,而呼叫在“ clearedmin”给出的时间视为已清除。

我想计算在给定的班次中能够响应特定呼叫的人员数量。例如,对于呼叫14-1234,在时间1902分配了警务人员8456。将有多少其他警务人员能够响应该电话?官员1098忙于从1870分钟到1910分钟之间的另一个呼叫,因此将无法响应发生在1902分钟的呼叫。但是,基于此简单的数据集,官员3432在那时不会很忙因此将被视为可用。当时没有人员5122,但轮值有所不同,因此将不被视为可用。

所需的输出:

  call    badge off.sex shift assignedmin clearedmin n_shift n_avail n_unavail n_shift_male n_male_avail
1 14-1234 8456  Male    1            1902       1980       4       2         2            3            1
2 14-4523 1098  Male    1            1870       1910       4       4         0            3            3
3 14-7711 3432  Female  1            1950       1990       4       3         1            3            2
4 14-8199 4750  Male    1            1899       1912       4       3         1            3            2
5 14-3124 5122  Male    2            1907       1956       1       1         1            1            1

我希望这不会太令人费解。基本上,在assignmin给出的时间,如果某个人员在同一班次并且没有被其他呼叫占用,则该人员将可用。我可以很容易地使用dplyr和data.table来计算班次中的警员人数,如下所示:

dat <- dat %>% group_by(shift) %>% mutate(n_shift = uniqueN(badge),
                                          n_shift_male = uniqueN(badge[off.sex == 'Male']) %>% ungroup()

2 个答案:

答案 0 :(得分:1)

使用data.table来计算每班人员人数的选项,然后执行非等价自加入来找出n_unavail,最后是n_avail = n_shift - n_unavail

library(data.table)
setDT(dat)[, c("n_shift", "n_shift_male") := .(.N, sum(off.sex=="Male")), shift]

dat[, c("n_unavail", "n_male_not_avail") :=
        dat[dat, on=.(shift, assignedmin<=assignedmin, clearedmin>=assignedmin),
            by=.EACHI, .(.N - 1L, sum(x.off.sex[x.call != i.call]=="Male"))][,
                (1L:3L) := NULL]
    ]

dat[, c("n_avail", "n_male_avail") := .(n_shift - n_unavail, n_shift_male - n_male_not_avail)]

输出:

      call badge off.sex shift assignedmin clearedmin n_shift n_shift_male n_unavail n_male_not_avail n_avail n_male_avail
1: 14-1234  8456    Male     1        1902       1980       4            3         2                2       2            1
2: 14-4523  1098    Male     1        1870       1910       4            3         0                0       4            3
3: 14-7711  3432  Female     1        1950       1990       4            3         1                1       3            2
4: 14-8199  4750    Male     1        1899       1912       4            3         1                1       3            2
5: 14-3124  5122    Male     2        1907       1956       1            1         0                0       1            1

答案 1 :(得分:0)

n_unavail列可以如下填充。首先,我自己在shift上加入表,以便同一班次的每个人员组合都有一行(如果您的数据集很大,这是不可行的)。然后,我计算通话时_other人员是否不可用,并对它们进行计数。

dat %>% 
  left_join(dat, by = "shift", suffix = c("", "_other")) %>% 
  mutate(unavail = (assignedmin_other < assignedmin & clearedmin_other > assignedmin)) %>% 
  group_by(call) %>% 
  summarise(n_avail = sum(!unavail),
            n_unavail = sum(unavail))

#   call    n_avail n_unavail
#   <chr>     <int>     <int>
# 1 14-1234       2         2
# 2 14-3124       1         0
# 3 14-4523       4         0
# 4 14-7711       3         1
# 5 14-8199       3         1

可以将其连接到您的桌子上以获得所需的结果。