Files
2026-07-10 18:55:55 +08:00

448 lines
17 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import ast
from datetime import datetime, timedelta, timezone
import pandas as pd # 确保导入pandas用于类型检查
def process_incident_data(test_val):
"""
处理事故数据,去重、排序并提取指定字段。
Args:
test_val (dict): 包含 'status' 和 'data' 键的原始数据字典。
Returns:
dict: 格式化后的数据,包含 'events' 键。
"""
unique_data_dict = {}
for item in test_val:
name = item.get("incident_name")
if name and name not in unique_data_dict:
unique_data_dict[name] = item
# 获取去重后的数据列表
unique_data_list = list(unique_data_dict.values())
# 2. 根据 incident_time 升序排序
# incident_time 是 GMT 格式字符串,可以直接排序
sorted_data = sorted(unique_data_list, key=lambda x: x.get("incident_time", ""))
# 3. 提取指定字段并格式化时间
id = 0
processed_events_data = []
for item in sorted_data:
incident_time_str = item.get("incident_time")
if not incident_time_str:
# 如果 incident_time 为空或不存在,可以选择跳过或使用默认值
# 这里我们跳过
print(
f"Warning: Missing 'incident_time' for item: {item.get('incident_name')}, skipping."
)
continue
try:
# 🔥 仅修改这里:解析 GMT 格式时间 "Wed, 10 Apr 2024 16:00:00 GMT"
if isinstance(incident_time_str, datetime):
incident_datetime = incident_time_str
else:
# 解析 GMT 格式字符串 "Wed, 10 Apr 2024 16:00:00 GMT"
incident_datetime = datetime.strptime(incident_time_str, "%a, %d %b %Y %H:%M:%S %Z")
except ValueError as e:
# 如果时间格式不正确,可以选择跳过或使用默认值
# 这里我们跳过
print(
f"Warning: Invalid 'incident_time' format for item: {item.get('incident_name')}, value: {incident_time_str}, error: {e}. Skipping."
)
continue
# 格式化日期和时间(逻辑不变)
date_str = incident_datetime.strftime("%Y-%m-%d")
time_str = incident_datetime.strftime("%H:%M:%S")
# 创建新的字典,只包含需要的字段
id += 1
processed_item = {
"id": id,
"oneid": item.get("oneid", ""),
"date": date_str,
"time": time_str,
"incident_name": item.get("incident_name", ""),
"incident_description": item.get(
"incident_description", ""
),
}
processed_events_data.append(processed_item)
# 4. 构建最终返回的字典
total_count = len(processed_events_data)
result = {"data": processed_events_data, "total": total_count}
return result
def process_incident_data1(test_val):
"""
处理事故数据,按照incident_time和incident_name去重,然后按incident_time排序。
Args:
test_val (list): 原始数据列表
Returns:
dict: 格式化后的数据
"""
from datetime import datetime
# 1. 按照 incident_name 和 incident_time 组合去重
unique_data_dict = {}
for item in test_val:
name = item.get("incident_name")
time = item.get("incident_time")
if name and time:
# 使用组合键去重
key = f"{name}_{time}"
if key not in unique_data_dict:
unique_data_dict[key] = item
# 获取去重后的数据列表
unique_data_list = list(unique_data_dict.values())
# 2. 根据 incident_time 升序排序
def parse_time(time_str):
try:
# 处理 "Sat, 08 Mar 2025 09:00:00 GMT" 格式
return datetime.strptime(time_str, "%a, %d %b %Y %H:%M:%S %Z")
except:
# 处理 ISO 8601 格式作为备选
try:
return datetime.fromisoformat(time_str.replace("Z", "+00:00"))
except:
return datetime.min
sorted_data = sorted(unique_data_list, key=lambda x: parse_time(x.get("incident_time", "")))
# 3. 提取指定字段
id = 0
processed_events_data = []
for item in sorted_data:
incident_time_str = item.get("incident_time")
if not incident_time_str:
continue
try:
incident_datetime = parse_time(incident_time_str)
except:
continue
# 格式化日期和时间
date_str = incident_datetime.strftime("%Y-%m-%d")
time_str = incident_datetime.strftime("%H:%M:%S")
# 创建新的字典
id += 1
processed_item = {
"id": id,
"oneid": item.get("oneid", ""),
"date": date_str,
"time": time_str,
"incident_name": item.get("incident_name", ""),
"incident_description": item.get("incident_description", ""),
}
processed_events_data.append(processed_item)
# 4. 构建最终返回的字典
total_count = len(processed_events_data)
result = {"data": processed_events_data, "total": total_count}
return result
def aggregate_and_sort_incidents(raw_data):
"""
按(idc_tickcount_ms + Incident__Name)聚合,整合同一组内的信号数据,消除视觉冗余
1. 同一组只输出1条记录,包含公共信息+所有信号数据
2. 按idc_tickcount_ms从小到大排序
3. 保留所有关键数据(含mux_data解析)
"""
aggregate_dict = {}
for item in raw_data:
# 1. 处理聚合key(idc_tickcount_ms整数, Incident__Name)
try:
tickcount_int = int(item.get("idc_tickcount_ms", "0"))
except (ValueError, TypeError):
tickcount_int = 0
incident_name = item.get("incident_name", "unknown_incident")
aggregate_key = (tickcount_int, incident_name)
# 2. 提取当前记录的关键数据(用于后续整合)
# 处理数值:优先取int_value,无则取float_value,都无则为None
# value = item.get("int_value") or item.get("float_value")
int_value=item.get("int_value")
float_value=item.get('float_value')
if int_value is not None:
value = int_value
elif float_value is not None:
value = float_value
else:
value = None
# 处理mux_data:若为JSON字符串,解析为字典(方便后续使用)
mux_data = item.get("mux_data")
if mux_data and mux_data != "null":
try:
mux_data = ast.literal_eval(mux_data)
except (ValueError, SyntaxError):
pass # 解析失败则保留原始字符串
# 3. 整合到聚合字典
if aggregate_key not in aggregate_dict:
# 首次遇到该key:初始化聚合结构(提取公共基础信息)
aggregate_dict[aggregate_key] = {
"base_info": { # 同一组的公共信息(只取第一条记录的)
"oneid": item.get("oneid"),
"ihd_version": item.get("ihd_version"),
"incident_time": item.get("incident_time"),
"speed": item.get("speed"),
"gps_heading": item.get("gps_heading"),
"incident_name": incident_name,
"incident_description": item.get("incident_description"),
"Trigger__condition": item.get("Trigger__condition"),
"idc_tickcount_ms": item.get("idc_tickcount_ms"),
"idc_tickcount_ms_int": tickcount_int,
"gps_dr_position": item.get("gps_dr_position"),
"incident_id": item.get("incident_id"),
"longitude": item.get("longitude"),
"latitude": item.get("latitude")
},
"signal_data": {} # 整合同一组的所有信号(key: 信号名,value: 信号数据)
}
# print('item.get("signal_name")',item.get('signal_name'))
# 4. 将当前记录的信号数据添加到signal_data中
# signal_key = item.get("key", "unknown_key")
signal_key=item.get('signal_name')
aggregate_dict[aggregate_key]["signal_data"][signal_key] = {
"value": value,
"mux_data": mux_data,
"signal_ihd_id": item.get("signal_ihd_id"),
"Decoding__value": item.get("Decoding__value"),
"Meaning": item.get("meaning")
}
sorted_data=sort_incidents_by_heading(list(aggregate_dict.values())) # 跨周期的
sorted_result = sorted(
sorted_data,
key=lambda x: x.get("idc_tickcount_ms_tmp", x["base_info"]["idc_tickcount_ms_int"])
)
return sorted_result
def parse_coordinate(coord_str):
"""
解析坐标字符串为浮点数
"""
if coord_str is None:
return None
if isinstance(coord_str, (int, float)):
return float(coord_str)
if isinstance(coord_str, str):
try:
return float(coord_str)
except ValueError:
# 如果是 "[longitude, latitude]" 格式,提取第一个数字
if coord_str.startswith('[') and coord_str.endswith(']'):
try:
coord_str_clean = coord_str.strip('[]')
coords = coord_str_clean.split(',')
if len(coords) >= 1:
return float(coords[0].strip())
except (ValueError, IndexError):
pass
return None
return None
def sort_incidents_by_heading(raw_data):
"""
按__head方法的逻辑进行排序:根据GPS航向角排序并处理时间戳回绕
"""
import pandas as pd
# 将原始数据转换为DataFrame,并处理经纬度
processed_data = []
for item in raw_data:
# 获取base_info
base_info = item.get('base_info', {})
processed_item = item.copy() # 保持原始结构
# 解析经纬度和航向角,从base_info中获取
longitude = parse_coordinate(base_info.get('longitude'))
latitude = parse_coordinate(base_info.get('latitude'))
gps_heading = parse_coordinate(base_info.get('gps_heading'))
# 添加到processed_item,用于排序
processed_item['longitude'] = longitude if longitude is not None else 0.0
processed_item['latitude'] = latitude if latitude is not None else 0.0
processed_item['gps_heading'] = gps_heading if gps_heading is not None else 0.0
processed_item['incident_time'] = base_info.get('incident_time', '')
# 确保时间戳是数值类型,从base_info中获取
try:
tickcount_ms = int(base_info.get('idc_tickcount_ms', 0))
except (ValueError, TypeError):
tickcount_ms = 0
processed_item['idc_tickcount_ms'] = tickcount_ms
processed_data.append(processed_item)
df = pd.DataFrame(processed_data)
# 确保所有相关列都是数值类型
df['idc_tickcount_ms'] = pd.to_numeric(df['idc_tickcount_ms'], errors='coerce').fillna(0).astype(int)
df['longitude'] = pd.to_numeric(df['longitude'], errors='coerce').fillna(0.0)
df['latitude'] = pd.to_numeric(df['latitude'], errors='coerce').fillna(0.0)
df['gps_heading'] = pd.to_numeric(df['gps_heading'], errors='coerce').fillna(0.0)
# 计算平均GPS航向角
gps_heading = df["gps_heading"].mean()
# print('gps_heading',gps_heading)
# 根据GPS航向角进行排序
if (gps_heading >= 315):
df.sort_values(by=['incident_time','latitude', 'longitude','idc_tickcount_ms'],
ascending=[True, True, False, True], inplace=True)
elif (gps_heading < 45):
df.sort_values(by=['incident_time','latitude', 'longitude','idc_tickcount_ms'],
ascending=[True, True, True, True], inplace=True)
elif (gps_heading >= 45) and (gps_heading < 90):
df.sort_values(by=['incident_time','longitude', 'latitude','idc_tickcount_ms'],
ascending=[True, True, True, True], inplace=True)
elif (gps_heading >= 90) and (gps_heading < 135):
df.sort_values(by=['incident_time','longitude', 'latitude','idc_tickcount_ms'],
ascending=[True, True, False, True], inplace=True)
elif (gps_heading >= 135) and (gps_heading < 180):
df.sort_values(by=['incident_time','latitude', 'longitude','idc_tickcount_ms'],
ascending=[True, False, True, True], inplace=True)
elif (gps_heading >= 180) and (gps_heading < 225):
df.sort_values(by=['incident_time','latitude', 'longitude','idc_tickcount_ms'],
ascending=[True, False, False, True], inplace=True)
elif (gps_heading >= 225) and (gps_heading < 270):
df.sort_values(by=['incident_time','longitude', 'latitude','idc_tickcount_ms'],
ascending=[True, False, False, True], inplace=True)
elif (gps_heading >= 270) and (gps_heading < 315):
df.sort_values(by=['incident_time','longitude', 'latitude','idc_tickcount_ms'],
ascending=[True, False, True, True], inplace=True)
# 处理时间戳回绕
df['idc_tickcount_ms_tmp'] = df['idc_tickcount_ms'].copy()
df.reset_index(inplace=True, drop=True)
# 确保数据类型一致
df['idc_tickcount_ms'] = df['idc_tickcount_ms'].astype(int)
max_tickcount = df['idc_tickcount_ms'].max()
loopcount = 65535 if max_tickcount < 65536 else 2097151
period = 0
# 确保所有值都是整数
df['idc_tickcount_ms'] = df['idc_tickcount_ms'].astype(int)
for i in range(1, len(df)):
current_tick = int(df.loc[i, 'idc_tickcount_ms'])
prev_tick = int(df.loc[i-1, 'idc_tickcount_ms'])
if current_tick < prev_tick:
period += 1
df.loc[i, 'idc_tickcount_ms_tmp'] = current_tick + period * loopcount
# 按调整后的时间戳排序
df.sort_values(by=["idc_tickcount_ms_tmp"], inplace=True)
# 转换回列表格式,移除临时添加的排序字段
result = []
for record in df.to_dict('records'):
# 移除临时添加的排序字段
cleaned_record = {k: v for k, v in record.items() if k not in ['longitude', 'latitude', 'gps_heading', 'incident_time']}
result.append(cleaned_record)
# print(result)
return result
def aggregate_line_list(map_result):
# 初始化聚合字典,key为idc_tickcount_ms_intvalue为聚合后的数据
aggregated_data = {}
# 遍历所有事件
for item in map_result:
base_info = item['base_info']
# 提取需要的字段
tickcount = item['idc_tickcount_ms_tmp']
speed = base_info['speed']
oneid = base_info['oneid']
latitude = base_info['latitude']
longitude = base_info['longitude']
incident_name = base_info['incident_name']
# 聚合处理
if tickcount not in aggregated_data:
# 新的tickcount,初始化记录
aggregated_data[tickcount] = {
'idc_tickcount_ms_int': tickcount,
'speed': speed,
'oneid': oneid,
'latitude': latitude,
'longitude': longitude,
'incident_names': [incident_name] # 用列表收集多个事件名称
}
else:
# 已存在的tickcount,追加事件名称
aggregated_data[tickcount]['incident_names'].append(incident_name)
# 转换为列表形式(按tickcount排序)
result = sorted(aggregated_data.values(), key=lambda x: x['idc_tickcount_ms_int'])
return result
def get_logging_list(map_list):
result=[]
id=0
for item in map_list:
# print(item)
id+=1
row_data={}
row_data['id']=id
base_info = item['base_info']
# print("base_info['incident_time']",base_info['incident_time'])
# dt = datetime.strptime(base_info['incident_time'], "%Y-%m-%d %H:%M:%S%z")
dt = base_info['incident_time']
if not isinstance(dt, datetime):
# 只有是字符串时,才解析
dt = datetime.strptime(dt, "%Y-%m-%d %H:%M:%S%z")
row_data['time']=dt.strftime("%H:%M:%S")
# row_data['coordinates']=base_info['longitude'][:12]+'.'+'\n'+base_info['latitude'][:12]
row_data['coordinates'] = str(base_info['longitude'])[:12] + '\n' + str(base_info['latitude'])[:12]
row_data['idc_tickcount_ms']=base_info['idc_tickcount_ms_int']
row_data['speed']=base_info['speed']
row_data['incident']={
"name":base_info['incident_name'],
"description":base_info['incident_description'],
}
row_data['signals']=[]
for key,value in item["signal_data"].items():
signals_name_value={}
signals_name_value["name"]=key
signals_name_value["value"]=value['value']
signals_name_value["meaning"]=value['Meaning']
row_data['signals'].append(signals_name_value)
result.append(row_data)
return result