Appropriate method for testing event data with no "natural" time bins I frequently get data that takes the form of a list of events with timestamps. For example, it might show different salespeople and each time they make a sale. What is the right method for testing whether two groups have a different rate of events?
This isn't a survival / time-to-event analysis because each group can have many events. I can do it by binning the timestamps into periods and doing a Poisson regression treating each time period as an independent sample with a certain number of events (or perhaps using a logistic regression if events are relatively sparse and many periods have zero events). But this feels odd because the time periods are arbitrary. For example, in the data below I could chunk the events by minute, hour, or day, and I'd get similar results.
Questions:

*

*Is there a more natural way to test differences in rates of events?

*Is there a recommended R package that can do this simply?

For the purposes of this question, please assume that each time period can be treated independently (ie, there are no correlated errors between adjacent time periods) and we aren't trying to model linear or periodic effects of time.

Here's an example dataset in R showing two sales teams and each time one of them makes a sale:
library(dplyr)
library(lubridate)

set.seed(413)
startdate=ISOdate(2009,4,13,4,13,00)
num_sales_eb <- 100000
num_sales_tg <- 120000
num_days <- 10

sales <- data.frame(
  team=c(rep("EB", num_sales_eb), rep("TG", num_sales_tg)),
# generate the specified number of sales events across the specified span of days for each salesperson
  saletime=c(
    startdate + runif(num_sales_eb, min=0, max=86400*num_days),
    startdate + runif(num_sales_tg, min=0, max=86400*num_days)
  )
) %>% arrange(saletime)

Here's an example of running a Poisson regression with different time bins and the same results.
# bin timestamps
sales <- sales %>% mutate(
  day=ceiling(difftime(saletime, startdate, units="days")),
  hour=ceiling(difftime(saletime, startdate, units="hours")),
  minute=ceiling(difftime(saletime, startdate, units="mins"))
)

sales_perday <- sales %>% group_by(team, day) %>% summarise(sales=n())
sales_perhour <- sales %>% group_by(team, hour) %>% summarise(sales=n())
sales_perminute <- sales %>% group_by(team, minute) %>% summarise(sales=n())

# note that if there are many periods where one or both teams had no sales, 
# we need to generate zero-sale records for those periods

preg_day <- glm(sales ~ team, family="poisson", data=sales_perday)
preg_hour <- glm(sales ~ team, family="poisson", data=sales_perhour)
preg_minute <- glm(sales ~ team, family="poisson", data=sales_perminute)

summary(preg_day)
summary(preg_hour)
summary(preg_minute)
```



This isn't a survival / time-to-event analysis because each group can have many events.

That's not correct. Survival analysis is readily extended to time-to-event analysis with multiple events per individual or group. See Section 2.2 of the R survival vignette for how to handle repeated events of the same type.
You just define separate time periods for each event for each group. You specify the startTime as the time of the previous event (or your choice of time = 0 for the first event), the stopTime (at which the event happened or follow-up ceased for that group), and an indicator of whether stopTime represents an event or censoring for that time period. Those values nicely come from your consecutive time stamps for each group. That's called the "counting process" data format.
Standard methods based on survival analysis can then accomplish what you want. You get estimates of "cumulative hazards" instead of survival curves, but those can still be used to compare groups. You can extend this to regression models if you wish. If you have individual employee data you could use ID values for employees and used group membership as a covariate. You won't be restricted to the strict assumptions that would underlie a Poisson model (however you tried to implement it).
