Какой самый эффективный способ подсчитать, сколько строк в кадре данных было «активным» за каждую минуту дня? - PullRequest
1 голос
/ 05 октября 2019

У меня есть кадр данных в формате:

object_id  start_time  end_time
123        13:23       13:28
234        13:25       13:26

И я хочу преобразовать его в такой формат:

time    number_of_objects_active
13:22                          0
13:23                          1
13:24                          1
13:25                          2
13:26                          1
13:27                          1
13:28                          1
13:29                          0

Где в каждой строке есть минута дняи подсчет количества объектов, которые были активны в этой точке (где активное означает, что время больше или равно времени начала и меньше времени окончания).

Я попытался найти какой-то способ сделатьгрупповой, но с треском провалились. Не очень хорошее решение состоит в том, чтобы циклически проходить каждую минуту дня, а затем суммировать количество строк, которые были активны в эту минуту:

results_dictionary = {}
for minute in minutes:
    results_dictionary[minute] = df.loc[(df.start_time <= minute) & (df.end_time > minute)].shape[0]

, но я подозреваю, что есть более приятный способ для панд / питоновделает это.

1 Ответ

2 голосов
/ 05 октября 2019

Если вы работаете в pandas v0.25 или новее, используйте explode:

# Convert `start_time` and `end_time` to Timestamp, if they
# are not already. This also allows you to adjust cases where
# the times cross the day boundary, e.g.: 23:00 - 02:00
df['start_time'] = pd.to_datetime(df['start_time'])
df['end_time'] = pd.to_datetime(df['end_time'])

# Make a `time` column that holds a minutely range. We will
# later explode it into individual minutes
f = lambda row: pd.date_range(row['start_time'], row['end_time'], freq='T')
df['time'] = df.apply(f, axis=1)

# The reporting range, adjust as needed
t = pd.date_range('13:23', '13:30', freq='T')

result = df.explode('time') \
            .groupby('time').size() \
            .reindex(t).fillna(0) \
            .to_frame('active')
result.index = result.index.time

Результат:

          active
13:23:00     1.0
13:24:00     1.0
13:25:00     2.0
13:26:00     2.0
13:27:00     1.0
13:28:00     1.0
13:29:00     0.0
13:30:00     0.0
...