按城市统计事件21与2先后发生次数及代码无限循环排查
按城市统计事件先后发生次数的代码问题排查与解决
需求
按城市统计两类事件的先后发生次数:
- 事件编号21发生在事件编号2之前的次数
- 事件编号2发生在事件编号21之前的次数
数据集
import pandas as pd data = { 'city': ['Amsterdam', 'Vienna', 'Paris', 'Paris', 'Istanbul', 'Istanbul','Delhi', 'London', 'London', 'Barcelona', 'Barcelona'], 'date': [ '2022-09-01T11:34:53', '2022-09-01T13:37:37', '2022-09-01 10:44:22.000', '2022-09-01T10:39:33', '2022-09-01 16:18:24.000', '2022-09-01T16:15:14', '2022-09-01T13:28:33', '2022-09-01 15:50:54.000', '2022-09-01T15:51:07', '2022-09-01 12:24:26.000','2022-09-01T12:24:07' ], 'year': [ '2022']*11, 'month': [9]*11, 'hour': [ 11,13,11,10,17,16,13,16,16,13,12 ], 'eventcode': [ 'J']*11, 'eventnumber': [ '21', '21', '2', '21', '2', '21', '21', '2', '21', '2','21' ] } df = pd.DataFrame(data, columns= ['city', 'date', 'year', 'month', 'hour', 'eventcode','eventnumber' ])
原代码问题
一段代码可正常统计事件21在事件2之前的次数,但调换事件编号后会陷入无限循环:
可正常运行的代码
import numpy as np bc=np.array(df['city']) un_bc,bc_index,bc_count=np.unique(bc,return_counts=True,return_index=True) new_df=pd.DataFrame() count=0 for i,j in zip(bc_index,bc_count): j=j+i-1 while i+1 <= j: if df.iat[i,7]==21 and df.iat[i+1,7]==2: count +=1 new_df=new_df.append(df[i:i+2]) i +=1 print(count)
陷入无限循环的代码
import numpy as np bc=np.array(df['city']) un_bc,bc_index,bc_count=np.unique(bc,return_counts=True,return_index=True) new_df=pd.DataFrame() count=0 for i,j in zip(bc_index,bc_count): j=j+i-1 while i+1 <= j: if df.iat[i,7]==2 and df.iat[i+1,7]==21: count +=1 new_df=new_df.append(df[i:i+2]) i +=1 print(count)
问题排查
- 列索引错误:
eventnumber是DataFrame的第7列(从1计数),但iat使用0-based索引,正确索引应为6而非7。原代码中df.iat[i,7]访问不存在的列,实际会抛出IndexError,推测是笔误。 - 数据类型不匹配:数据集里
eventnumber是字符串类型(如'2'),但代码中用整数2做比较,导致条件永远不成立。 - 循环变量滥用:在
for循环中修改迭代变量i,会破坏for循环的迭代逻辑,处理完一个城市后i的值已被修改,后续循环可能进入异常逻辑,最终导致无限循环。
解决方法
改用Pandas分组功能,按城市分组后先按时间排序,再检查事件先后顺序,代码简洁且无逻辑漏洞:
# 将date列转为datetime类型,确保时间排序准确 df['date'] = pd.to_datetime(df['date']) # 按城市分组,统计每个城市内事件的先后情况 result = df.groupby('city').apply(lambda x: { '2_before_21': ((x.sort_values('date')['eventnumber'].shift() == '2') & (x.sort_values('date')['eventnumber'] == '21')).sum(), '21_before_2': ((x.sort_values('date')['eventnumber'].shift() == '21') & (x.sort_values('date')['eventnumber'] == '2')).sum() }).apply(pd.Series) # 计算总次数 total_2_before_21 = result['2_before_21'].sum() total_21_before_2 = result['21_before_2'].sum() print(f"事件2在事件21之前发生的总次数:{total_2_before_21}") print(f"事件21在事件2之前发生的总次数:{total_21_before_2}")
代码说明
- 先将
date转为datetime类型,保证时间排序的准确性。 - 按城市分组后,对每个城市的事件按时间排序,用
shift()获取前一行的事件编号,比较当前行与前一行的事件组合,统计符合条件的次数。 - 最后汇总所有城市的统计结果,得到总次数。
运行结果符合预期:事件2在事件21之前发生1次,事件21在事件2之前发生3次。
内容的提问来源于stack exchange,提问作者Sar
相关产品推荐
相关产品推荐

