与 Python 中间隔重叠的时间间隔相关的总和值

问题描述 投票:0回答:2

假设我有一个 pandas 数据框,其中开始时间和结束时间之间有时间间隔,然后是与每个间隔关联的值。

import random
import time
import numpy as np

def random_date(input_dt = None):
    if input_dt is None:
        start = 921032233
    else:
        start = dt.datetime.timestamp(pd.to_datetime(input_dt))
    d = random.randint(start, int(time.time()))
    return dt.datetime.fromtimestamp(d).strftime('%Y-%m-%d %H:%M:%S')

date_ranges = []
for _ in range(200):
    date_range = []
    for i in range(2):
        if i == 0:
            date_range.append(random_date())
        else:
            date_range.append(random_date(date_range[0]))
    date_ranges.append(date_range)

date_ranges_df = pd.DataFrame(date_ranges, columns=['start_dt', 'end_dt'])
date_ranges_df['value'] = np.random.random((date_ranges_df.shape[0], 1))

我可以通过两种方式来解决这个问题,我会接受其中一个答案。

  1. 获取每个不同重叠区间的总和。这意味着应该有一个与变化的(不重叠且顺序完整的)时间间隔相关的总和。即,如果重叠时间间隔在一段时间内保持不变,则总和将保持不变并具有单个值 - 那么当重叠间隔以任何方式发生变化(删除或添加时间间隔)时,将计算新的总和。这可能涉及一些桌面上的自合并。

  2. 另一种(也许更简单)的方法是定义一个标准时间间隔,例如 1 小时,并询问该小时段内所有重叠间隔的总和是多少?

生成的数据帧应具有类似的结构,其中开始时间和结束时间后跟表示该间隔中所有值之和的值列。

python datetime intervals
2个回答
1
投票
  1. 每个不同重叠区间的总和: 这比较复杂,因为我们需要检测重叠周期,然后需要对重叠周期的值求和。

  2. 定义的小时段内所有重叠间隔的总和: 这需要将我们的数据重新采样为定期的每小时频率(将不规则间隔转换为定期的每小时频率并聚合这些每小时间隔内的“

    value
    ”数据的过程),然后计算总和。

每个不同重叠区间的总和

import pandas as pd

# Convert to datetime objects
date_ranges_df['start_dt'] = pd.to_datetime(date_ranges_df['start_dt'])
date_ranges_df['end_dt'] = pd.to_datetime(date_ranges_df['end_dt'])

# Sort by start_dt
date_ranges_df = date_ranges_df.sort_values(by='start_dt')

# Create list of tuples: [(start1, end1, value1), (start2, end2, value2),...]
intervals = list(date_ranges_df.itertuples(index=False, name=None))

# Split intervals into start and end points and sort them
points = sorted([(start, value, 1) for start, _, value in intervals] + [(end, value, -1) for _, end, value in intervals])

result = []
current_value = 0
current_start = points[0][0]

for i, (point, value, change) in enumerate(points):
    if i > 0 and point != points[i-1][0]:
        result.append((current_start, points, current_value))
        current_start = point
    current_value += change * value

# Create a dataframe from result
result_df = pd.DataFrame(result, columns=['start_dt', 'end_dt', 'value'])

这可以通过将间隔转换为单独的点来实现,每个点都标记有一个值和一个标志,指示它是起点 (

1
) 还是终点 (
-1
)。

然后对点进行排序。当我们迭代这些点时,当我们到达一个不等于前一个点的点(表示一个新的间隔段)时,我们记录前一个段以及到该点的累积值。然后,我们更新当前的起点,并在遇到起点和终点时继续添加或减去值。

生成的 DataFrame

result_df
包含不重叠的段,以及每个段期间活动的间隔值的总和。

定义的小时段内所有重叠间隔的总和

# Convert to datetime objects
date_ranges_df['start_dt'] = pd.to_datetime(date_ranges_df['start_dt'])
date_ranges_df['end_dt'] = pd.to_datetime(date_ranges_df['end_dt'])

# Resample to 1-hour intervals
hourly_intervals = pd.date_range(date_ranges_df['start_dt'].min(), date_ranges_df['end_dt'].max(), freq='H')

hourly_df = pd.DataFrame()
for start in hourly_intervals:
    end = start + timedelta(hours=1)
    # Get intervals that overlap with current hour
    mask = ((date_ranges_df['start_dt'] < end) & (date_ranges_df['end_dt'] > start))
    overlap = date_ranges_df.loc[mask]
    if not overlap.empty:
        # Sum values of overlapping intervals
        total_value = overlap['value'].sum()
        hourly_df = hourly_df.append({'start_dt': start, 'end_dt': end, 'value': total_value}, ignore_index=True)

# Convert column types
hourly_df['start_dt'] = pd.to_datetime(hourly_df['start_dt'])
hourly_df['end_dt'] = pd.to_datetime(hourly_df['end_dt'])

注意:代码假定

start_dt
end_dt
列格式正确,并且
value
列包含数值。
此外,由于嵌套循环,它可能不是大型数据集的最优化解决方案。可能需要根据数据的大小优化代码。

这应该为这两个代码提供具有相同结构的结果

DataFrame
,包括“
start_dt
”、“
end_dt
”和“值”列。
start_dt
”和“
end_dt
”是每个区间的边界,“值”是这些边界内所有重叠区间的总和。

对于第一种方法,它将每个不同重叠间隔的值相加,它看起来像:

  start_dt                  end_dt                     value
0 2023-07-04 08:06:02+00:00 2023-07-04 14:12:22+00:00  1.2789
1 2023-07-04 17:02:02+00:00 2023-07-04 23:17:54+00:00  0.8672
2 2021-06-30 00:45:11+00:00 2021-06-30 05:32:20+00:00  1.4563
...

对于第二种方法,每小时求和值:

  start_dt                  end_dt                     value
0 2023-07-04 08:00:00+00:00 2023-07-04 09:00:00+00:00  0.7489
1 2023-07-04 09:00:00+00:00 2023-07-04 10:00:00+00:00  0.5321
2 2023-07-04 10:00:00+00:00 2023-07-04 11:00:00+00:00  0.4563
...

注意:

value
列包含每行在“
start_dt
”到“
end_dt
”范围内的所有重叠间隔值的总和。


1
投票

第二种方式: 由于我是新用户,我只能创建答案。因此,这个答案很大程度上建立在@VonC的答案上。

据我测试,目前对他们没有价值的间隔会在过程中丢失,并且重叠间隔不会被累加。为了解决第一个问题,我添加了 else 条件,如果时间间隔内不存在任何值,则该条件会添加零。为了解决第二个问题,我添加了 .sum(),它还将total_value 转换为浮点数。此外,还避免了 .append 的使用。

# Convert to datetime objects
date_ranges_df['start_dt'] = pd.to_datetime(date_ranges_df['start_dt'])
date_ranges_df['end_dt'] = pd.to_datetime(date_ranges_df['end_dt'])

# Resample to 1-hour intervals
hourly_intervals = pd.date_range(date_ranges_df['start_dt'].min(), 
date_ranges_df['end_dt'].max(), freq='H')

hourly_df = pd.DataFrame()
for start in hourly_intervals:
    end = start + timedelta(hours=1)
    # Get intervals that overlap with current hour
    mask = ((date_ranges_df['start_dt'] < end) & (date_ranges_df['end_dt'] > start))
    overlap = date_ranges_df.loc[mask]
    if not overlap.empty:
        # Sum values of overlapping intervals
        total_value = overlap['value'].sum()
        new_entry = pd.Series({'start': start, 'end': end, 'value': total_value})
        hourly_df = pd.concat([hourly_df, new_entry.to_frame().T], ignore_index=True)
    else:
        new_entry = pd.Series({'start': start, 'end': end, 'value': 0})
        hourly_df = pd.concat([hourly_df, new_entry.to_frame().T], ignore_index=True)

# Convert column types
hourly_df['start_dt'] = pd.to_datetime(hourly_df['start_dt'])
hourly_df['end_dt'] = pd.to_datetime(hourly_df['end_dt'])
© www.soinside.com 2019 - 2024. All rights reserved.