查找并发 运行 个事务的总 "wait" 时间
Finding total "wait" time for concurrently running transactions
我需要评估制造执行系统的数百万行性能日志记录。我需要按日期、class 和名称对数据进行分组,并找到大量并发 运行 交易的总“等待时间”。数据看起来类似于此数据框中的内容:
import pandas as pd
d = {'START_DATE': ['2021-08-07 19:11:40', '2021-08-07 19:11:40', '2021-08-07 19:11:40',
'2021-08-07 19:20:40', '2021-08-07 19:20:40', '2021-08-07 19:20:40',
'2021-08-07 19:21:40', '2021-08-07 19:21:40', '2021-08-07 19:21:40',
'2021-08-10 19:20:40', '2021-08-10 19:20:40', '2021-08-10 19:20:40',
'2021-08-10 19:21:40', '2021-08-10 19:21:40', '2021-08-10 19:21:40'
],
'ELAPSED_TIME': ['00:00:00.465', '00:00:01.000', '00:00:00.165',
'00:00:00.100', '00:00:00.200', '00:03:00.000',
'00:05:00.000', '00:00:00.200', '00:00:03.000',
'00:00:00.100', '00:00:00.200', '00:03:00.000',
'00:05:00.000', '00:00:00.200', '00:00:03.000'
],
'TRANSACTION': ['a', 'b', 'c',
'a', 'd', 'c',
'e', 'a', 'b',
'a', 'd', 'c',
'e', 'a', 'b'
],
'USER': ['Bob', 'Bob', 'Bob',
'Biff', 'Biff', 'Biff',
'Biff', 'Biff', 'Biff',
'Bob', 'Bob', 'Bob',
'Bob', 'Bob', 'Bob'
],
'CLASS': ['AA', 'AA', 'AA',
'BB', 'BB', 'BB',
'BB', 'BB', 'BB',
'AA', 'AA', 'AA',
'AA', 'AA', 'AA'
]}
df = pd.DataFrame(data=d)
查看交易时间如何同时开始并且 运行 彼此并发,但将在不同时间“完成”。例如。 Bob 的第一组事务(第 0-2 行)都需要不同的时间量,但是当我按 DATE、CLASS 和 USER 分组时——我想显示总等待时间为 1000 毫秒(基于第二行的等待时间)。
08/07/2021,Biff有两组不同时间开始的交易,但它们仍然会重叠到一个等待时间--6000ms。
预期输出类似于:
DATE CLASS USER Wait
2021-08-07 AA Bob 1000
2021-08-07 BB Biff 360000
2021-08-10 AA Bob 360000
就像我提到的实际数据有数百万行交易——我正在寻求帮助以找到更好的东西(希望比我have/found更快):
def getSecs1(grp):
return pd.DatetimeIndex([]).union_many([ pd.date_range(
row.START_DATE, row.END_DATE, freq='25ms', closed='left')
for _, row in grp.iterrows() ]).size
我通过将毫秒添加到 START_DATE 来添加一个 END_DATE 列。我必须用 25 毫秒的块来完成它,否则它会花费太长时间。
任何 help/advice 将不胜感激。
###编辑
将重叠更改为分钟
此解决方案使用一个名为 staircase
的包,该包基于 pandas 和 numpy 构建,用于处理(数学)阶跃函数。您可以将间隔视为一个阶梯函数,它在间隔开始时从值 0 变为 1,在间隔结束时从值 1 变为 0。
附加设置
将 START_DATE
和 ELAPSED_TIME
转换为适当的 pandas
时间对象
df["START_DATE"] = pd.to_datetime(df["START_DATE"])
df["ELAPSED_TIME"] = pd.to_timedelta(df["ELAPSED_TIME"])
定义每日垃圾箱
dates = pd.period_range("2021-08-07", "2021-08-10")
解决方案
定义一个函数,它接受一个数据帧,从开始时间和结束时间(计算为开始 + 持续时间)生成一个阶梯函数,将非零值设置为 1,用 bin 对阶梯函数进行切片,然后积分。
import staircase as sc
def calc_dates_for_user(df_):
return (
sc.Stairs( # creating step function
start=df_["START_DATE"],
end=df_["START_DATE"] + df_["ELAPSED_TIME"],
)
.make_boolean() # where two intervals overlap the value of the step function will be 2. This sets all non-zero values to 1 (effectively creating a union of intervals).
.slice(dates) # analogous to groupby
.integral()/pd.Timedelta("1s") # for each slice integrate (which will equal the length of the interval) and divide by seconds
)
当我们按 USER
和 CLASS
分组并应用此函数时,我们得到一个数据帧,由这些变量索引,列索引对应于周期范围内的间隔
USER CLASS [2021-08-07, 2021-08-08) [2021-08-08, 2021-08-09) [2021-08-09, 2021-08-10) [2021-08-10, 2021-08-11)
Biff BB 360000.0 0.0 0.0 0.0
Bob AA 1000.0 0.0 0.0 360000.0
我们会像这样清理它
result = (
df.groupby(["USER", "CLASS"])
.apply(calc_dates_for_user)
.melt(ignore_index=False, var_name="DATE", value_name="WAIT") # melt column index into a single column of daily intervals
.query("WAIT != 0") # filter out days where no time recorded
.reset_index() # move USER and CLASS from index to columns
)
result
然后看起来像这样
USER CLASS DATE WAIT
0 Biff BB [2021-08-07, 2021-08-08) 360000.0
1 Bob AA [2021-08-07, 2021-08-08) 1000.0
2 Bob AA [2021-08-10, 2021-08-11) 360000.0
要获得预期结果,您可以将 DATE 列替换为与开始日期相关的时间戳
result["DATE"] = pd.IntervalIndex(result["DATE"]).left
我需要评估制造执行系统的数百万行性能日志记录。我需要按日期、class 和名称对数据进行分组,并找到大量并发 运行 交易的总“等待时间”。数据看起来类似于此数据框中的内容:
import pandas as pd
d = {'START_DATE': ['2021-08-07 19:11:40', '2021-08-07 19:11:40', '2021-08-07 19:11:40',
'2021-08-07 19:20:40', '2021-08-07 19:20:40', '2021-08-07 19:20:40',
'2021-08-07 19:21:40', '2021-08-07 19:21:40', '2021-08-07 19:21:40',
'2021-08-10 19:20:40', '2021-08-10 19:20:40', '2021-08-10 19:20:40',
'2021-08-10 19:21:40', '2021-08-10 19:21:40', '2021-08-10 19:21:40'
],
'ELAPSED_TIME': ['00:00:00.465', '00:00:01.000', '00:00:00.165',
'00:00:00.100', '00:00:00.200', '00:03:00.000',
'00:05:00.000', '00:00:00.200', '00:00:03.000',
'00:00:00.100', '00:00:00.200', '00:03:00.000',
'00:05:00.000', '00:00:00.200', '00:00:03.000'
],
'TRANSACTION': ['a', 'b', 'c',
'a', 'd', 'c',
'e', 'a', 'b',
'a', 'd', 'c',
'e', 'a', 'b'
],
'USER': ['Bob', 'Bob', 'Bob',
'Biff', 'Biff', 'Biff',
'Biff', 'Biff', 'Biff',
'Bob', 'Bob', 'Bob',
'Bob', 'Bob', 'Bob'
],
'CLASS': ['AA', 'AA', 'AA',
'BB', 'BB', 'BB',
'BB', 'BB', 'BB',
'AA', 'AA', 'AA',
'AA', 'AA', 'AA'
]}
df = pd.DataFrame(data=d)
查看交易时间如何同时开始并且 运行 彼此并发,但将在不同时间“完成”。例如。 Bob 的第一组事务(第 0-2 行)都需要不同的时间量,但是当我按 DATE、CLASS 和 USER 分组时——我想显示总等待时间为 1000 毫秒(基于第二行的等待时间)。
08/07/2021,Biff有两组不同时间开始的交易,但它们仍然会重叠到一个等待时间--6000ms。
预期输出类似于:
DATE CLASS USER Wait
2021-08-07 AA Bob 1000
2021-08-07 BB Biff 360000
2021-08-10 AA Bob 360000
就像我提到的实际数据有数百万行交易——我正在寻求帮助以找到更好的东西(希望比我have/found更快):
def getSecs1(grp):
return pd.DatetimeIndex([]).union_many([ pd.date_range(
row.START_DATE, row.END_DATE, freq='25ms', closed='left')
for _, row in grp.iterrows() ]).size
我通过将毫秒添加到 START_DATE 来添加一个 END_DATE 列。我必须用 25 毫秒的块来完成它,否则它会花费太长时间。
任何 help/advice 将不胜感激。
###编辑 将重叠更改为分钟
此解决方案使用一个名为 staircase
的包,该包基于 pandas 和 numpy 构建,用于处理(数学)阶跃函数。您可以将间隔视为一个阶梯函数,它在间隔开始时从值 0 变为 1,在间隔结束时从值 1 变为 0。
附加设置
将 START_DATE
和 ELAPSED_TIME
转换为适当的 pandas
时间对象
df["START_DATE"] = pd.to_datetime(df["START_DATE"])
df["ELAPSED_TIME"] = pd.to_timedelta(df["ELAPSED_TIME"])
定义每日垃圾箱
dates = pd.period_range("2021-08-07", "2021-08-10")
解决方案
定义一个函数,它接受一个数据帧,从开始时间和结束时间(计算为开始 + 持续时间)生成一个阶梯函数,将非零值设置为 1,用 bin 对阶梯函数进行切片,然后积分。
import staircase as sc
def calc_dates_for_user(df_):
return (
sc.Stairs( # creating step function
start=df_["START_DATE"],
end=df_["START_DATE"] + df_["ELAPSED_TIME"],
)
.make_boolean() # where two intervals overlap the value of the step function will be 2. This sets all non-zero values to 1 (effectively creating a union of intervals).
.slice(dates) # analogous to groupby
.integral()/pd.Timedelta("1s") # for each slice integrate (which will equal the length of the interval) and divide by seconds
)
当我们按 USER
和 CLASS
分组并应用此函数时,我们得到一个数据帧,由这些变量索引,列索引对应于周期范围内的间隔
USER CLASS [2021-08-07, 2021-08-08) [2021-08-08, 2021-08-09) [2021-08-09, 2021-08-10) [2021-08-10, 2021-08-11)
Biff BB 360000.0 0.0 0.0 0.0
Bob AA 1000.0 0.0 0.0 360000.0
我们会像这样清理它
result = (
df.groupby(["USER", "CLASS"])
.apply(calc_dates_for_user)
.melt(ignore_index=False, var_name="DATE", value_name="WAIT") # melt column index into a single column of daily intervals
.query("WAIT != 0") # filter out days where no time recorded
.reset_index() # move USER and CLASS from index to columns
)
result
然后看起来像这样
USER CLASS DATE WAIT
0 Biff BB [2021-08-07, 2021-08-08) 360000.0
1 Bob AA [2021-08-07, 2021-08-08) 1000.0
2 Bob AA [2021-08-10, 2021-08-11) 360000.0
要获得预期结果,您可以将 DATE 列替换为与开始日期相关的时间戳
result["DATE"] = pd.IntervalIndex(result["DATE"]).left