在python中识别事件数据中的序列的更有效的方法



我是python编程的新手,正在处理一些看起来效率不高的代码。我正在努力寻找特定的事件序列。事件是按行列出的,我已经使用IF语句和iloc/loc函数实现了这一点,通过查看后续事件来确定是否发现了感兴趣的序列,然后验证这是否在要考虑的时间阈值内。

适用于小型数据集,但我试图运行的实际数据集是超过10万行的数据,在这些数据中,这种方法陷入了停顿。有没有一种更有效的方法来缩短执行时间?我正在使用的代码如下。提前谢谢。

data = {'Mode':['1', '1', '1', '1','1','1','2'],'EventType':['A', 'A', 'B', 'A','B','B','A'], 'TimeStamp':['01/01/2018 06:20:00', '01/01/2018 06:33:00', '01/01/2018 06:34:01', '01/01/2018 06:35:59', '01/01/2018 06:36:11', '01/01/2018 06:38:59', '01/01/2018 06:42:12']} 
df = pd.DataFrame (data, columns = ['Mode','EventType','TimeStamp'])
df['TimeStamp'] = pd.to_datetime(df['TimeStamp'])
df['SEQ'] =""
column = df.columns.get_loc("EventType")
#iterate over rows and find sequences of interest
for i in range(0,len(df)-1):
r =0
if df.iloc[i,column] =="A":
if df.iloc[i+1,column] =="B":
if df.iloc[i+2,column]=="A":
df.loc[df.index[i],'SEQ'] = 'ABA'
r =i+2
else:
if df.iloc[i+3,column] =="A":
df.loc[df.index[i],'SEQ'] = 'ABBA'
r =i+3
else: 
df.loc[df.index[i],'SEQ'] = 'ABBB'
r =i+3
else: 
df.loc[df.index[i],'SEQ'] = 'AA'
r =i+1
else:
if df.iloc[i+1,column]=="B":
df.loc[df.index[i],'SEQ'] = 'BB'
r =i+1
else:
df.loc[df.index[i],'SEQ'] = 'B'
if r!=0:
Duration = (df.loc[df.index[r],'TimeStamp'] - df.loc[df.index[i],'TimeStamp']).total_seconds()
df.loc[df.index[i],'Duration (Seconds)'] = Duration
# Add relevant thresholds for identified sequences
thresholds = {'ABA': 180,
'ABBA': 240,
'BB': 180,
'AA': 180,
'ABBB': 240}
df['Threshold (Seconds)'] = [thresholds.get(x) for x in df['SEQ']]   
# Add column for Valid Sequences
df['Valid Duration']= df['Duration (Seconds)'] < df['Threshold (Seconds)']

为了加快脚本的速度,尤其是在处理大型数据集时,您应该尽量减少对dataFrame的访问。每个df.iloc[something]基本上都会发送程序来获取该位置包含的数据。此过程需要相对较长的时间!因此,您应该尽量避免这种情况,并将数据获取保持在最低限度。如果只检索数据集的单个值,请使用df.at[],而不是df.loc[]df.iloc[]。由于您正在处理序列,并且必须一次获取多行,因此我建议使用聚合。因此,与其一次获取每种事件类型,不如一次获取所有事件类型。我建议您首先构建序列,如下所示:

for i in range(0, len(df) - 1):
event = df.iloc[i : i + 4, column].str.cat(sep="")
if event == "ABBB":
pass
elif event == "ABBA":
pass
elif event.startswith("ABA"):
event = "ABA"
elif event.startswith("AA"):
event = "AA"
elif event.startswith("BB"):
event = "BB"
else:
event = ""
df.at[i, "SEQ"] = event

基本上每行有一个读操作df.iloc[i : i + 4, column]和一个写操作df.at[i, "SEQ"],而不是代码中的五个。计算TimeDiff时,请使用df.at[],因为您只获取/设置一个值。

# replace df.loc with df.at, takes half the time as it retrieves single values
if r != 0:
df.at[i, "Duration (Seconds)"] = (
df.at[r, "TimeStamp"] - df.at[i, "TimeStamp"]
).total_seconds()

这应该会大大加快代码的速度。如果你能记录性能,我很想看看这对你的数据集有什么影响。

最新更新