1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107 |
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- ##################################################################
- #
- # Copyright (c) 2023 CICV, Inc. All Rights Reserved
- #
- ##################################################################
- """
- @Authors: yangzihao(yangzihao@china-icv.cn)
- @Data: 2023/11/28
- @Last Modified: 2023/11/28
- @Summary: Evaluate multiple cases.
- """
- import os
- import sys
- import pandas as pd
- import numpy as np
- import requests
- import json
- import pathlib
- import time
- import traceback
- import log
- from common import json2dict, score_grade, mileage_format, duration_format, string_concatenate, replace_key_with_value
- from score import cal_score_from_80
- def calculate_ratios(grade_count_list):
- """
- This function helps to calculate the ratios of the grade in grade_count_list.
- Arguments:
- grade_count_list: A list of the number of grades.
- Returns:
- ratios: A list of the ratios of the grade in grade_count_list.
- """
- arr = np.array(grade_count_list)
- total = arr.sum()
- ratios = np.round(arr / total * 100).astype(int).tolist()
- # 确保四个比例的和为100
- if sum(ratios) != 100:
- ratios[0] += 100 - sum(ratios)
- return ratios
- def grade_statistic(grade_list):
- """
- This function statistic the number of grades in grade_list.
- Arguments:
- grade_list: A list of grades.
- Returns:
- grade_distribution: A dict of the distribution of 4 grades.
- """
- a_grade_count = len([x for x in grade_list if x == "优秀"])
- b_grade_count = len([x for x in grade_list if x == "良好"])
- c_grade_count = len([x for x in grade_list if x == "一般"])
- d_grade_count = len([x for x in grade_list if x == "较差"])
- grade_count_list = [a_grade_count, b_grade_count, c_grade_count, d_grade_count]
- ratios = calculate_ratios(grade_count_list)
- grade_distribution = {
- "优秀": ratios[0],
- "良好": ratios[1],
- "一般": ratios[2],
- "较差": ratios[3]
- }
- return grade_distribution
- def custom_metric_param_list_parser(param_list):
- """
- param_dict = {
- "paramA" [
- {
- "kind": "-1",
- "optimal": "1",
- "multiple": ["0.5","5"],
- "spare1": null,
- "spare2": null
- }
- ]
- }
- """
- kind_list = []
- optimal_list = []
- multiple_list = []
- spare_list = []
- # spare1_list = []
- # spare2_list = []
- for i in range(len(param_list)):
- kind_list.append(int(param_list[i]['kind']))
- optimal_list.append(float(param_list[i]['optimal']))
- multiple_list.append([float(x) for x in param_list[i]['multiple']])
- spare_list.append([item["param"] for item in param_list[i]["spare"]])
- # spare1_list.append(param_list[i]['spare1'])
- # spare2_list.append(param_list[i]['spare2'])
- result = {
- "kind": kind_list,
- "optimal": optimal_list,
- "multiple": multiple_list,
- "spare": spare_list,
- # "spare1": spare1_list,
- # "spare2": spare2_list
- }
- return result
- def custom_metric_param_parser(customMetricParam):
- result = {}
- for key, param_list in customMetricParam.items():
- result[key] = custom_metric_param_list_parser(param_list)
- return result
- def custom_multi_case_statistic(custom_cases_dict, config, dimension):
- """
- Args:
- custom_cases_dict:
- config:
- dimension:
- Returns:
- """
- df_custom_cases = pd.DataFrame(custom_cases_dict).T.dropna(how='all')
- # common data
- bulitin_metric_list = config.builtinMetricList
- # config infos
- dimension_config = config.config[dimension]
- metric_list = dimension_config['metric']
- type_list = dimension_config['type']
- type_name_dict = dimension_config['typeName']
- name_dict = dimension_config['name']
- unit_dict = dimension_config['unit']
- metric_dict = dimension_config['typeMetricDict']
- dimension_name_dict = config.dimension_name
- # # custom metric data
- customMetricParam = dimension_config['customMetricParam']
- # custom_data = custom_data
- custom_param_dict = custom_metric_param_parser(customMetricParam)
- weight_custom = float(dimension_config['weightDimension'])
- # optimal_dict = dimension_config['optimal']
- # kind_dict = dimension_config['kind']
- # multiple_dict = dimension_config['multiple']
- report_dict = {
- "name": f"{dimension_name_dict[dimension]}",
- "weight": f"{weight_custom * 100}%",
- }
- # calculate score_custom and grade_custom
- score_custom_list = df_custom_cases['score'].values.tolist()
- score_custom = cal_score_from_80(score_custom_list)
- grade_custom = score_grade(score_custom)
- report_dict["score"] = score_custom
- report_dict["level"] = grade_custom
- report_dict["scoreList"] = score_custom_list
- # calculate grade_distribution
- grade_custom_list = df_custom_cases['level'].values.tolist()
- grade_custom_distribution = grade_statistic(grade_custom_list)
- report_dict["levelDistribution"] = grade_custom_distribution
- score_type_dict = {}
- value_list_dict = {}
- bad_count_dict = {}
- good_rate_dict = {}
- bad_rate_dict = {}
- type_details_dict = {}
- for type in type_list:
- type_dict = {
- "name": type_name_dict[type],
- }
- builtin_graph_dict = {}
- custom_graph_dict = {}
- df_custom_cases[type] = df_custom_cases["details"].apply(lambda x: x[type] if type in x.keys() else None)
- df_custom_cases1 = df_custom_cases.dropna(subset=[type])
- type_cases_dict = df_custom_cases1[type].to_dict()
- df_type_cases = pd.DataFrame(type_cases_dict).T.dropna(how='all')
- # calculate score_type and grade_type
- score_type_list = df_type_cases['score'].values.tolist()
- score_type = round(np.mean(score_type_list), 2)
- grade_type = score_grade(score_type)
- type_dict["score"] = score_type
- type_dict["level"] = grade_type
- score_type_dict[type] = score_type
- # calculate grade_distribution
- grade_type_list = df_type_cases['level'].values.tolist()
- grade_type_distribution = grade_statistic(grade_type_list)
- type_dict["gradeDistribution"] = grade_type_distribution
- dfs = df_type_cases['indexes'].apply(lambda x: pd.DataFrame(x).T)
- df_type_indexes = pd.concat(dfs.tolist(), ignore_index=True)
- # functionACC description
- type_metric1_list = [] # good
- type_metric2_list = [] # not good
- type_metric3_list = [] # bad
- # indexes
- type_dict_indexes = {}
- for metric in metric_dict[type]:
- df_metric_indexes = df_type_indexes[df_type_indexes['name'] == f"{name_dict[metric]}"]
- kind_metric = custom_param_dict[metric]['kind'][0]
- optimal_metric = custom_param_dict[metric]['optimal'][0]
- multiple_metric0 = custom_param_dict[metric]['multiple'][0][0]
- multiple_metric1 = custom_param_dict[metric]['multiple'][0][1]
- if kind_metric == 1: # 越大越好
- metric_value_list = df_metric_indexes['min'].astype(str).values.tolist()
- metric_value_list = [float(x) for x in metric_value_list if '-' not in x]
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = max(metric_value_list) if metric_value_list else "-"
- if not optimal_metric:
- metric_bad_count = 0
- else:
- metric_bad_count = len([x for x in metric_value_list if x < float(optimal_metric)])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- type_metric1_list.append(metric) if metric_bad_rate == 0 else type_metric2_list.append(
- metric) if avg_metric_value > float(optimal_metric) else type_metric3_list.append(metric)
- elif kind_metric == -1: # 越小越好
- metric_value_list = df_metric_indexes['max'].astype(str).values.tolist()
- metric_value_list = [float(x) for x in metric_value_list if '-' not in x]
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = max(metric_value_list) if metric_value_list else "-"
- if not optimal_metric:
- metric_bad_count = 0
- else:
- metric_bad_count = len([x for x in metric_value_list if x > float(optimal_metric)])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- type_metric1_list.append(metric) if metric_bad_rate == 0 else type_metric2_list.append(
- metric) if avg_metric_value < float(optimal_metric) else type_metric3_list.append(metric)
- elif kind_metric == 0:
- metric_value_list = df_metric_indexes['avg'].astype(str).values.tolist()
- metric_value_list = [float(x) for x in metric_value_list if '-' not in x]
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = max(metric_value_list) if metric_value_list else "-"
- if not optimal_metric:
- metric_bad_count = 0
- else:
- metric_bad_count = len([x for x in metric_value_list if (
- x > float(optimal_metric) * multiple_metric1 or x < float(
- optimal_metric) * multiple_metric0)])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- if not optimal_metric:
- type_metric1_list.append(metric)
- else:
- type_metric1_list.append(metric) if metric_bad_rate == 0 else type_metric2_list.append(metric) if (
- float(optimal_metric) * multiple_metric1 > avg_metric_value > float(
- optimal_metric) * multiple_metric0) else type_metric3_list.append(
- metric)
- type_dict_indexes[metric] = {
- "name": f"{name_dict[metric]}",
- "average": avg_metric_value,
- "max": max_metric_value,
- "min": min_metric_value,
- }
- if not optimal_metric:
- type_dict_indexes[metric]["range"] = f"-"
- else:
- if kind_metric == -1:
- type_dict_indexes[metric]["range"] = f"[0, {optimal_metric}]"
- elif kind_metric == 1:
- type_dict_indexes[metric]["range"] = f"[{optimal_metric}, inf)"
- elif kind_metric == 0:
- type_dict_indexes[metric][
- "range"] = f"[{float(optimal_metric) * multiple_metric0}, {float(optimal_metric) * multiple_metric1}]"
- value_list_dict[metric] = metric_value_list
- bad_count_dict[metric] = metric_bad_count
- good_rate_dict[metric] = metric_good_rate
- bad_rate_dict[metric] = metric_bad_rate
- type_dict["indexes"] = type_dict_indexes
- for metric in metric_dict[type]:
- metric_data = {
- "name": f"{name_dict[metric]}",
- "data": value_list_dict[metric],
- "markLine": [custom_param_dict[metric]['optimal'][0]]
- }
- custom_graph_dict[metric] = metric_data
- type_dict["builtin"] = builtin_graph_dict
- type_dict["custom"] = custom_graph_dict
- # description
- str_type_metric1 = ''
- str_type_metric2 = ''
- str_type_metric3 = ''
- if len(type_metric1_list) == len(metric_list):
- str_metric = string_concatenate(metric_list)
- type_description1 = f"{str_metric}指标均表现良好,平均值在合理范围内且不存在不合格用例。"
- elif len(type_metric3_list) == len(metric_list):
- str_metric = string_concatenate(metric_list)
- type_description1 = f"{str_metric}指标平均值在合理范围外,算法在大部分用例下均表现不佳,需重点优化。"
- else:
- if type_metric1_list:
- str_type1 = string_concatenate(type_metric1_list)
- str_type_metric1 += f"{str_type1}指标表现良好,平均值在合理范围内且不存在不合格用例;"
- for metric in type_metric2_list:
- str_type_metric2 += f"{name_dict[metric]}指标表现不佳,存在{bad_count_dict[metric]}个不合格用例,需要改进算法在这些用例中的表现;"
- if type_metric3_list:
- str_type3 = string_concatenate(type_metric3_list)
- str_type_metric3 += f"{str_type3}指标平均值在合理范围外,算法在大部分用例下均表现不佳,需重点优化。"
- type_description1 = ''
- type_description1 += (str_type_metric1 + '\n') if str_type_metric1 else ''
- type_description1 += (str_type_metric2 + '\n') if str_type_metric2 else ''
- type_description1 += str_type_metric3
- type_description1 = type_description1[:-1] + "。"
- # type_description2 = "经计算可知,"
- # for metric in metric_dict[type]:
- # type_description2 += f"{metric}指标位于合理区间的占比为{good_rate_dict[metric]}%,"
- # type_description2 = type_description2[:-1] + "。"
- type_dict["description1"] = replace_key_with_value(type_description1, name_dict)
- # type_dict["description2"] = replace_key_with_value(type_description2, name_dict)
- type_details_dict[type] = type_dict
- report_dict["details"] = type_details_dict
- # custom description1
- good_type_list = []
- bad_type_list = []
- for type in type_list:
- bad_type_list.append(type) if score_type_dict[type] < 80 else good_type_list.append(type)
- # generate custom_description1
- good_type_list_count = len(score_custom_list)
- over_80_count = len([num for num in score_custom_list if num >= 80])
- over_80_proportion = over_80_count / good_type_list_count
- below_80_count = good_type_list_count - over_80_count
- below_80_proportion = below_80_count / good_type_list_count
- below_60_count = len([num for num in score_custom_list if num < 60])
- below_60_proportion = below_60_count / good_type_list_count
- if grade_custom == '优秀':
- custom_description1 = f'算法在本轮测试中的表现优秀;'
- elif grade_custom == '良好':
- custom_description1 = f'算法在本轮测试中的表现满足设计指标要求。其中有{over_80_count}个用例得分超过80分,占比为{over_80_proportion * 100:.2f}%;'
- elif grade_custom == '一般':
- str_bad_type = string_concatenate(bad_type_list)
- custom_description1 = f'未满足设计指标要求。其中有{below_80_count}个用例得分低于80分,占比为{below_80_proportion * 100:.2f}%,需优化算法在{str_bad_type}上的表现;'
- elif grade_custom == '较差':
- str_bad_type = string_concatenate(bad_type_list)
- custom_description1 = f'未满足设计指标要求。其中有{below_60_count}个用例得分低于60分,占比为{below_60_proportion * 100:.2f}%,需优化算法在{str_bad_type}上的表现;'
- # customcient description2
- if not bad_type_list:
- custom_description2 = f"算法在{dimension_name_dict[dimension]}维度上的表现满足设计指标要求。"
- else:
- custom_description2 = f"算法在{str_bad_type}的指标需要重点优化。"
- report_dict["description1"] = replace_key_with_value(custom_description1, type_name_dict)
- report_dict["description2"] = replace_key_with_value(custom_description2, type_name_dict)
- return report_dict
- def safe_multi_case_statistic(safe_cases_dict, config):
- """
- Args:
- safe_cases_dict:
- config:
- Returns:
- """
- # report_dict = {
- # "name": "安全性",
- # "weight": f"{weight_safe * 100}%",
- # "score": score_safe,
- # "level": grade_safe,
- # "scoreList": score_safe_list,
- # "levelDistribution": grade_safe_distribution,
- #
- # "description1": safe_description1,
- # "description2": safe_description2,
- # "noObjectCar": False,
- #
- # "safeTime": time_dict,
- # "safeDistance": distance_dict,
- # "safeAcceleration": acceleration_dict,
- # "safeProbability": probability_dict
- # }
- df_safe_cases = pd.DataFrame(safe_cases_dict).T.dropna(how='all')
- # common data
- bulitin_metric_list = config.builtinMetricList
- # config infos
- dimension_config = config.config["safe"]
- metric_list = dimension_config['metric']
- type_list = dimension_config['type']
- type_name_dict = dimension_config['typeName']
- name_dict = dimension_config['name']
- unit_dict = dimension_config['unit']
- metric_dict = dimension_config['typeMetricDict']
- # # custom metric data
- customMetricParam = dimension_config['customMetricParam']
- # custom_data = custom_data
- custom_param_dict = custom_metric_param_parser(customMetricParam)
- weight_safe = float(dimension_config['weightDimension'])
- optimal_dict = dimension_config['optimal'][0]
- kind_dict = dimension_config['kind'][0]
- multiple_dict = dimension_config['multiple'][0]
- report_dict = {
- "name": "安全性",
- "weight": f"{weight_safe * 100}%",
- "noObjectCar": False,
- }
- # calculate score_safe and grade_safe
- score_safe_list = df_safe_cases['score'].values.tolist()
- score_safe = cal_score_from_80(score_safe_list)
- grade_safe = score_grade(score_safe)
- report_dict["score"] = score_safe
- report_dict["level"] = grade_safe
- report_dict["scoreList"] = score_safe_list
- # calculate grade_distribution
- grade_safe_list = df_safe_cases['level'].values.tolist()
- grade_safe_distribution = grade_statistic(grade_safe_list)
- report_dict["levelDistribution"] = grade_safe_distribution
- score_type_dict = {}
- value_list_dict = {}
- bad_count_dict = {}
- good_rate_dict = {}
- bad_rate_dict = {}
- type_details_dict = {}
- for type in type_list:
- type_dict = {
- "name": type_name_dict[type],
- }
- builtin_graph_dict = {}
- custom_graph_dict = {}
- df_safe_cases[type] = df_safe_cases["details"].apply(lambda x: x[type] if type in x.keys() else None)
- df_safe_cases1 = df_safe_cases.dropna(subset=[type])
- type_cases_dict = df_safe_cases1[type].to_dict()
- df_type_cases = pd.DataFrame(type_cases_dict).T.dropna(how='all')
- # calculate score_type and grade_type
- score_type_list = df_type_cases['score'].values.tolist()
- score_type = round(np.mean(score_type_list), 2)
- grade_type = score_grade(score_type)
- type_dict["score"] = score_type
- type_dict["level"] = grade_type
- score_type_dict[type] = score_type
- # calculate grade_distribution
- grade_type_list = df_type_cases['level'].values.tolist()
- grade_type_distribution = grade_statistic(grade_type_list)
- type_dict["gradeDistribution"] = grade_type_distribution
- # calculate type indexes
- # type_indexes_dict = df_type_cases['indexes'].explode().tolist()
- # df_type_indexes = pd.DataFrame(type_indexes_dict)
- dfs = df_type_cases['indexes'].apply(lambda x: pd.DataFrame(x).T)
- df_type_indexes = pd.concat(dfs.tolist(), ignore_index=True)
- # functionACC description
- type_metric1_list = [] # good
- type_metric2_list = [] # not good
- type_metric3_list = [] # bad
- # indexes
- type_dict_indexes = {}
- for metric in metric_dict[type]:
- df_metric_indexes = df_type_indexes[df_type_indexes['name'] == f"{name_dict[metric]}"]
- kind_metric = kind_dict[metric] if metric in bulitin_metric_list else custom_param_dict[metric]['kind'][0]
- optimal_metric = optimal_dict[metric] if metric in bulitin_metric_list else \
- custom_param_dict[metric]['optimal'][0]
- multiple_metric0 = multiple_dict[metric][0] if metric in bulitin_metric_list else \
- custom_param_dict[metric]['multiple'][0][0]
- multiple_metric1 = multiple_dict[metric][1] if metric in bulitin_metric_list else \
- custom_param_dict[metric]['multiple'][0][1]
- if kind_metric == 1: # 越大越好
- # metric_value_list = df_metric_indexes['min'].astype(float).values.tolist()
- metric_value_list = df_metric_indexes['extremum'].astype(str).values.tolist()
- metric_value_list = [float(x) for x in metric_value_list if '-' not in x]
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = max(metric_value_list) if metric_value_list else "-"
- if not optimal_metric:
- metric_bad_count = 0
- else:
- metric_bad_count = len([x for x in metric_value_list if x < float(optimal_metric)])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- type_metric1_list.append(metric) if metric_bad_rate == 0 else type_metric2_list.append(
- metric) if avg_metric_value > float(optimal_metric) else type_metric3_list.append(metric)
- elif kind_metric == -1: # 越小越好
- # metric_value_list = df_metric_indexes['max'].astype(float).values.tolist()
- metric_value_list = df_metric_indexes['extremum'].astype(str).values.tolist()
- metric_value_list = [float(x) for x in metric_value_list if '-' not in x]
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = max(metric_value_list) if metric_value_list else "-"
- if not optimal_metric:
- metric_bad_count = 0
- else:
- metric_bad_count = len([x for x in metric_value_list if x > float(optimal_metric)])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- type_metric1_list.append(metric) if metric_bad_rate == 0 else type_metric2_list.append(
- metric) if avg_metric_value < float(optimal_metric) else type_metric3_list.append(metric)
- elif kind_metric == 0:
- # metric_value_list = df_metric_indexes['avg'].astype(float).values.tolist()
- metric_value_list = df_metric_indexes['extremum'].astype(str).values.tolist()
- metric_value_list = [float(x) for x in metric_value_list if '-' not in x]
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = max(metric_value_list) if metric_value_list else "-"
- if not optimal_metric:
- metric_bad_count = 0
- else:
- metric_bad_count = len([x for x in metric_value_list if (
- x > float(optimal_metric) * multiple_metric1 or x < float(optimal_metric) *
- multiple_metric0)])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- if not optimal_metric:
- type_metric1_list.append(metric)
- else:
- type_metric1_list.append(metric) if metric_bad_rate == 0 else type_metric2_list.append(
- metric) if (
- float(optimal_metric) * multiple_metric1 > avg_metric_value > float(optimal_metric) *
- multiple_metric0) else type_metric3_list.append(metric)
- type_dict_indexes[metric] = {
- "name": f"{name_dict[metric]}",
- "average": avg_metric_value,
- "max": max_metric_value,
- "min": min_metric_value,
- "rate": f"{metric_bad_rate}%"
- # "range": f"[0, {optimal_dict['followSpeedDeviation']}]",
- }
- if not optimal_metric:
- type_dict_indexes[metric]["range"] = f"-"
- else:
- if kind_metric == -1:
- type_dict_indexes[metric]["range"] = f"[0, {optimal_metric}]"
- elif kind_metric == 1:
- type_dict_indexes[metric]["range"] = f"[{optimal_metric}, inf)"
- elif kind_metric == 0:
- type_dict_indexes[metric][
- "range"] = f"[{float(optimal_metric) * multiple_metric0}, {float(optimal_metric) * multiple_metric1}]"
- # else:
- # if custom_param_dict[metric]['kind'][0] == -1:
- # type_dict_indexes[metric][
- # "range"] = f"[0, {custom_param_dict[metric]['optimal'][0]}]"
- # elif custom_param_dict[metric]['kind'][0] == 1:
- # type_dict_indexes[metric][
- # "range"] = f"[{custom_param_dict[metric]['optimal'][0]}, inf)"
- # elif custom_param_dict[metric]['kind'][0] == 0:
- # type_dict_indexes[metric][
- # "range"] = f"[{custom_param_dict[metric]['optimal'][0] * multiple_dict[metric][0]}, {custom_param_dict[metric]['optimal'][0] * custom_param_dict[metric]['multiple'][0][1]}]"
- value_list_dict[metric] = metric_value_list
- bad_count_dict[metric] = metric_bad_count
- good_rate_dict[metric] = metric_good_rate
- bad_rate_dict[metric] = metric_bad_rate
- type_dict["indexes"] = type_dict_indexes
- for metric in metric_dict[type]:
- metric_data = {
- "name": f"{name_dict[metric]}",
- "data": value_list_dict[metric],
- # "markLine": [optimal_dict[metric]]
- }
- if metric in bulitin_metric_list:
- metric_data["markLine"] = [optimal_dict[metric]]
- builtin_graph_dict[metric] = metric_data
- else:
- metric_data["markLine"] = [custom_param_dict[metric]['optimal'][0]]
- custom_graph_dict[metric] = metric_data
- type_dict["builtin"] = builtin_graph_dict
- type_dict["custom"] = custom_graph_dict
- # description
- str_type_metric1 = ''
- str_type_metric2 = ''
- str_type_metric3 = ''
- if len(type_metric1_list) == len(metric_list):
- str_metric = string_concatenate(metric_list)
- type_description1 = f"{str_metric}指标均表现良好,平均值在合理范围内且不存在不合格用例。"
- elif len(type_metric3_list) == len(metric_list):
- str_metric = string_concatenate(metric_list)
- type_description1 = f"{str_metric}指标平均值在合理范围外,算法在大部分用例下均表现不佳,需重点优化。"
- else:
- if type_metric1_list:
- str_type1 = string_concatenate(type_metric1_list)
- str_type_metric1 += f"{str_type1}指标表现良好,平均值在合理范围内且不存在不合格用例;"
- for metric in type_metric2_list:
- str_type_metric2 += f"{name_dict[metric]}指标表现不佳,存在{bad_count_dict[metric]}个不合格用例,需要改进算法在这些用例中的表现;"
- if type_metric3_list:
- str_type3 = string_concatenate(type_metric3_list)
- str_type_metric3 += f"{str_type3}指标平均值在合理范围外,算法在大部分用例下均表现不佳,需重点优化。"
- type_description1 = ''
- type_description1 += (str_type_metric1 + '\n') if str_type_metric1 else ''
- type_description1 += (str_type_metric2 + '\n') if str_type_metric2 else ''
- type_description1 += str_type_metric3
- type_description1 = type_description1[:-1] + "。"
- type_description2 = "经计算可知,"
- for metric in metric_dict[type]:
- type_description2 += f"{metric}指标位于合理区间的占比为{good_rate_dict[metric]}%,"
- type_description2 = type_description2[:-1] + "。"
- type_dict["description1"] = replace_key_with_value(type_description1, name_dict)
- type_dict["description2"] = replace_key_with_value(type_description2, name_dict)
- type_details_dict[type] = type_dict
- report_dict["details"] = type_details_dict
- """
- # ------------------------------
- # safe summary dict
- """
- safe_type_list = []
- unsafe_type_list = []
- for key, value in score_type_dict.items():
- unsafe_type_list.append(key) if value < 80 else safe_type_list.append(key)
- # generate safe_description1
- safe_list_count = len(score_safe_list)
- over_80_count = len([num for num in score_safe_list if num >= 80])
- over_80_proportion = over_80_count / safe_list_count
- below_80_count = safe_list_count - over_80_count
- below_80_proportion = below_80_count / safe_list_count
- below_60_count = len([num for num in score_safe_list if num < 60])
- below_60_proportion = below_60_count / safe_list_count
- if grade_safe == '优秀':
- safe_description1 = '车辆在本轮测试中无碰撞风险;'
- elif grade_safe == '良好':
- safe_description1 = f'算法在本轮测试中的表现满足设计指标要求。其中有{over_80_count}个用例得分超过80分,占比为{over_80_proportion * 100:.2f}%;'
- elif grade_safe == '一般':
- str_unsafe_type = string_concatenate(unsafe_type_list)
- safe_description1 = f'未满足设计指标要求。其中有{below_80_count}个用例得分低于80分,占比为{below_80_proportion * 100:.2f}%,需优化算法在{str_unsafe_type}上的表现;'
- elif grade_safe == '较差':
- str_unsafe_type = string_concatenate(unsafe_type_list)
- safe_description1 = f'未满足设计指标要求。其中有{below_60_count}个用例得分低于60分,占比为{below_60_proportion * 100:.2f}%,需优化算法在{str_unsafe_type}上的表现;'
- if not unsafe_type_list:
- safe_description2 = '算法在安全性维度上的表现满足设计指标要求。'
- else:
- str_unsafe_type = string_concatenate(unsafe_type_list)
- safe_description2 = f"安全性在{str_unsafe_type}上存在严重风险,需要重点优化。"
- report_dict["description1"] = replace_key_with_value(safe_description1, type_name_dict)
- report_dict["description2"] = replace_key_with_value(safe_description2, type_name_dict)
- # report_dict = {
- # "name": "安全性",
- # "weight": f"{weight_safe * 100}%",
- # "score": score_safe,
- # "level": grade_safe,
- # "scoreList": score_safe_list,
- # "levelDistribution": grade_safe_distribution,
- #
- # "description1": safe_description1,
- # "description2": safe_description2,
- # "noObjectCar": False,
- #
- # "safeTime": time_dict,
- # "safeDistance": distance_dict,
- # "safeAcceleration": acceleration_dict,
- # "safeProbability": probability_dict
- # }
- return report_dict
- import pandas as pd
- import numpy as np
- def process_dataframe(df, column):
- # 初始化value列为NaN
- df['value'] = np.nan
- # 遍历DataFrame的每一行
- for index, row in df.iterrows():
- avg_val, max_val, min_val = row['avg'], row['max'], row['min']
- # 检查是否两个是'-',一个是数值
- count_minus = sum(val == '-' for val in [avg_val, max_val, min_val])
- if count_minus == 2:
- # 找出那个不是'-'的值,并赋值给value列
- numeric_val = [val for val in [avg_val, max_val, min_val] if val != '-'][0]
- df.at[index, 'value'] = float(numeric_val) # 转换为浮点数并赋值
- else:
- # 如果条件不满足,则将column列的值赋给value列
- df.at[index, 'value'] = row[column]
- return df
- def assign_value_column(df, column, avg_col='avg', max_col='max', min_col='min'):
- # 判断三列中有几个是'-'(作为空值或缺失值的代表)
- df[['num_avg', 'num_max', 'num_min']] = df[[avg_col, max_col, min_col]].applymap(
- lambda x: 0 if isinstance(x, (int, float)) else 1 if x == '-' else None)
- # 计算每行中'-'的数量
- df['num_hyphens'] = df[['num_avg', 'num_max', 'num_min']].sum(axis=1)
- # 判断是否满足条件:两个'-'和一个数值
- df['is_valid_condition'] = (df['num_hyphens'] == 2)
- # df['is_valid_condition'] = (df['num_hyphens'] == 2) & df[[avg_col, max_col, min_col]].apply(
- # lambda row: sum(isinstance(val, (int, float)) for val in row) == 1, axis=1)
- # 创建一个新的value列,根据条件填充值
- df['value'] = df.apply(
- lambda row: next((val for val in [row[avg_col], row[max_col], row[min_col]] if val != '-'), row[column]) if row['is_valid_condition'] else row[column], axis=1)
- # 删除辅助列
- df.drop(['num_avg', 'num_max', 'num_min', 'num_hyphens', 'is_valid_condition'], axis=1, inplace=True)
- # 返回修改后的DataFrame
- return df
- # 示例使用
- # 假设df是你的原始DataFrame,且包含avg, max, min和column列
- # df = pd.DataFrame({...}) # 这里省略了具体的DataFrame创建代码
- # result_df = assign_value_column(df)
- # print(result_df)
- def func_multi_case_statistic(func_cases_dict, config):
- """
- Args:
- func_cases_dict:
- config:
- Returns:
- """
- # report_dict = {
- # "name": "功能性",
- # "weight": f"{weight_dimension * 100}%",
- # "score": score_func,
- # "level": grade_func,
- # "scoreList": score_func_list,
- # "levelDistribution": grade_func_distribution,
- # "description1": func_description1,
- # "description2": func_description2,
- # "noObjectCar": False,
- # "functionACC": follow_dict,
- # "functionLKA": lane_dict
- # }
- df_func_cases = pd.DataFrame(func_cases_dict).T.dropna(how='all')
- # common data
- bulitin_metric_list = config.builtinMetricList
- # config infos
- dimension_config = config.config["function"]
- metric_list = dimension_config['metric']
- type_list = dimension_config['type']
- type_name_dict = dimension_config['typeName']
- name_dict = dimension_config['name']
- unit_dict = dimension_config['unit']
- metric_dict = dimension_config['typeMetricDict']
- # # custom metric data
- customMetricParam = dimension_config['customMetricParam']
- custom_metric_list = list(customMetricParam.keys())
- # custom_data = custom_data
- custom_param_dict = custom_metric_param_parser(customMetricParam)
- weight_dimension = float(dimension_config['weightDimension'])
- optimal_dict = dimension_config['optimal']
- kind_dict = dimension_config['kind']
- multiple_dict = dimension_config['multiple']
- report_dict = {
- "name": "功能性",
- "weight": f"{weight_dimension * 100}%",
- "noObjectCar": False,
- }
- # calculate score_func and grade_func
- score_func_list = df_func_cases['score'].values.tolist()
- score_func = cal_score_from_80(score_func_list)
- grade_func = score_grade(score_func)
- report_dict["score"] = score_func
- report_dict["level"] = grade_func
- report_dict["scoreList"] = score_func_list
- # calculate grade_distribution
- grade_func_list = df_func_cases['level'].values.tolist()
- grade_func_distribution = grade_statistic(grade_func_list)
- report_dict["levelDistribution"] = grade_func_distribution
- score_type_dict = {}
- value_list_dict = {}
- bad_count_dict = {}
- good_rate_dict = {}
- bad_rate_dict = {}
- type_details_dict = {}
- for type in type_list:
- type_dict = {
- "name": type_name_dict[type],
- }
- builtin_graph_dict = {}
- custom_graph_dict = {}
- df_func_cases[type] = df_func_cases["details"].apply(lambda x: x[type] if type in x.keys() else None)
- df_func_cases1 = df_func_cases.dropna(subset=[type])
- type_cases_dict = df_func_cases1[type].to_dict()
- df_type_cases = pd.DataFrame(type_cases_dict).T.dropna(how='all')
- # calculate score_type and grade_type
- score_type_list = df_type_cases['score'].values.tolist()
- score_type = round(np.mean(score_type_list), 2)
- grade_type = score_grade(score_type)
- type_dict["score"] = score_type
- type_dict["level"] = grade_type
- score_type_dict[type] = score_type
- # calculate grade_distribution
- grade_type_list = df_type_cases['level'].values.tolist()
- grade_type_distribution = grade_statistic(grade_type_list)
- type_dict["gradeDistribution"] = grade_type_distribution
- # calculate type indexes
- # type_indexes_dict = df_type_cases['indexes'].explode().tolist()
- # df_type_indexes = pd.DataFrame(type_indexes_dict)
- dfs = df_type_cases['indexes'].apply(lambda x: pd.DataFrame(x).T)
- df_type_indexes = pd.concat(dfs.tolist(), ignore_index=True)
- # functionACC description
- type_metric1_list = [] # good
- type_metric2_list = [] # not good
- type_metric3_list = [] # bad
- # indexes
- type_dict_indexes = {}
- for metric in metric_dict[type]:
- df_metric_indexes = df_type_indexes[df_type_indexes['name'] == f"{name_dict[metric]}"]
- kind_metric = kind_dict[metric] if metric in bulitin_metric_list else custom_param_dict[metric]['kind'][0]
- optimal_metric = optimal_dict[metric] if metric in bulitin_metric_list else \
- custom_param_dict[metric]['optimal'][0]
- multiple_metric0 = multiple_dict[metric][0] if metric in bulitin_metric_list else \
- custom_param_dict[metric]['multiple'][0][0]
- multiple_metric1 = multiple_dict[metric][1] if metric in bulitin_metric_list else \
- custom_param_dict[metric]['multiple'][0][1]
- if kind_metric == 1: # 越大越好
- # metric_value_list = df_metric_indexes['min'].astype(float).values.tolist()
- df_metric_indexes = assign_value_column(df_metric_indexes, "min")
- metric_value_list = df_metric_indexes['value'].astype(str).values.tolist()
- metric_value_list = [float(x) for x in metric_value_list if '-' not in x]
- metric_value_list = [x for x in metric_value_list if not np.isnan(x)]
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = max(metric_value_list) if metric_value_list else "-"
- if not optimal_metric:
- metric_bad_count = 0
- else:
- metric_bad_count = len([x for x in metric_value_list if x < float(optimal_metric)])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- type_metric1_list.append(metric) if metric_bad_rate == 0 else type_metric2_list.append(
- metric) if avg_metric_value > float(optimal_metric) else type_metric3_list.append(metric)
- elif kind_metric == -1: # 越小越好
- # metric_value_list = df_metric_indexes['max'].astype(float).values.tolist()
- # if metric in ["centerDistanceExpectation", "centerDistanceStandardDeviation", "centerDistanceFrequency",
- # "centerDistanceRange"]:
- # index_name = 'avg'
- # elif metric in ["centerDistanceMin"]:
- # index_name = 'min'
- # else: # centerDistanceMax, laneDistance
- # index_name = 'max'
- df_metric_indexes = assign_value_column(df_metric_indexes, "max")
- metric_value_list = df_metric_indexes['value'].astype(str).values.tolist()
- # metric_value_list = df_metric_indexes[index_name].astype(str).values.tolist()
- metric_value_list = [float(x) for x in metric_value_list if '-' not in x]
- metric_value_list = [x for x in metric_value_list if not np.isnan(x)]
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = max(metric_value_list) if metric_value_list else "-"
- if not optimal_metric:
- metric_bad_count = 0
- else:
- metric_bad_count = len([x for x in metric_value_list if x > float(optimal_metric)])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- type_metric1_list.append(metric) if metric_bad_rate == 0 else type_metric2_list.append(
- metric) if avg_metric_value < float(optimal_metric) else type_metric3_list.append(metric)
- elif kind_metric == 0:
- # metric_value_list = df_metric_indexes['avg'].astype(float).values.tolist()
- # metric_value_list = df_metric_indexes['avg'].astype(str).values.tolist()
- df_metric_indexes = assign_value_column(df_metric_indexes, "avg")
- metric_value_list = df_metric_indexes['value'].astype(str).values.tolist()
- metric_value_list = [float(x) for x in metric_value_list if '-' not in x]
- metric_value_list = [x for x in metric_value_list if not np.isnan(x)]
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = max(metric_value_list) if metric_value_list else "-"
- if not optimal_metric:
- metric_bad_count = 0
- else:
- metric_bad_count = len([x for x in metric_value_list if (
- x > float(optimal_metric) * multiple_metric1 or x < float(optimal_metric) *
- multiple_metric0)])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- if not optimal_metric:
- type_metric1_list.append(metric)
- else:
- type_metric1_list.append(metric) if metric_bad_rate == 0 else type_metric2_list.append(
- metric) if (
- float(optimal_metric) * multiple_metric1 > avg_metric_value > float(optimal_metric) *
- multiple_metric0) else type_metric3_list.append(metric)
- type_dict_indexes[metric] = {
- "name": f"{name_dict[metric]}",
- "average": avg_metric_value,
- "max": max_metric_value,
- "min": min_metric_value,
- # "range": f"[0, {optimal_dict['followSpeedDeviation']}]",
- }
- if not optimal_metric:
- type_dict_indexes[metric]["range"] = f"-"
- else:
- if kind_metric == -1:
- type_dict_indexes[metric]["range"] = f"[0, {optimal_metric}]"
- elif kind_metric == 1:
- type_dict_indexes[metric]["range"] = f"[{optimal_metric}, inf)"
- elif kind_metric == 0:
- type_dict_indexes[metric][
- "range"] = f"[{float(optimal_metric) * multiple_metric0}, {float(optimal_metric) * multiple_metric1}]"
- # else:
- # if custom_param_dict[metric]['kind'][0] == -1:
- # type_dict_indexes[metric][
- # "range"] = f"[0, {custom_param_dict[metric]['optimal'][0]}]"
- # elif custom_param_dict[metric]['kind'][0] == 1:
- # type_dict_indexes[metric][
- # "range"] = f"[{custom_param_dict[metric]['optimal'][0]}, inf)"
- # elif custom_param_dict[metric]['kind'][0] == 0:
- # type_dict_indexes[metric][
- # "range"] = f"[{custom_param_dict[metric]['optimal'][0] * multiple_dict[metric][0]}, {custom_param_dict[metric]['optimal'][0] * custom_param_dict[metric]['multiple'][0][1]}]"
- value_list_dict[metric] = metric_value_list
- bad_count_dict[metric] = metric_bad_count
- good_rate_dict[metric] = metric_good_rate
- bad_rate_dict[metric] = metric_bad_rate
- type_dict["indexes"] = type_dict_indexes
- for metric in metric_dict[type]:
- metric_data = {
- "name": f"{name_dict[metric]}",
- "data": value_list_dict[metric],
- # "markLine": [optimal_dict[metric]]
- }
- if metric in bulitin_metric_list:
- metric_data["markLine"] = [optimal_dict[metric]]
- builtin_graph_dict[metric] = metric_data
- else:
- metric_data["markLine"] = [custom_param_dict[metric]['optimal'][0]]
- custom_graph_dict[metric] = metric_data
- type_dict["builtin"] = builtin_graph_dict
- type_dict["custom"] = custom_graph_dict
- # description
- str_type_metric1 = ''
- str_type_metric2 = ''
- str_type_metric3 = ''
- if len(type_metric1_list) == len(metric_list):
- str_metric = string_concatenate(metric_list)
- type_description1 = f"{str_metric}指标均表现良好,平均值在合理范围内且不存在不合格用例。"
- elif len(type_metric3_list) == len(metric_list):
- str_metric = string_concatenate(metric_list)
- type_description1 = f"{str_metric}指标平均值在合理范围外,算法在大部分用例下均表现不佳,需重点优化。"
- else:
- if type_metric1_list:
- str_type1 = string_concatenate(type_metric1_list)
- str_type_metric1 += f"{str_type1}指标表现良好,平均值在合理范围内且不存在不合格用例;"
- for metric in type_metric2_list:
- str_type_metric2 += f"{name_dict[metric]}指标表现不佳,存在{bad_count_dict[metric]}个不合格用例,需要改进算法在这些用例中的表现;"
- if type_metric3_list:
- str_type3 = string_concatenate(type_metric3_list)
- str_type_metric3 += f"{str_type3}指标平均值在合理范围外,算法在大部分用例下均表现不佳,需重点优化。"
- type_description1 = ''
- type_description1 += (str_type_metric1 + '\n') if str_type_metric1 else ''
- type_description1 += (str_type_metric2 + '\n') if str_type_metric2 else ''
- type_description1 += str_type_metric3
- type_description1 = type_description1[:-1] + "。"
- type_description2 = "经计算可知,"
- for metric in metric_dict[type]:
- type_description2 += f"{metric}指标位于合理区间的占比为{good_rate_dict[metric]}%,"
- type_description2 = type_description2[:-1] + "。"
- type_dict["description1"] = replace_key_with_value(type_description1, name_dict)
- type_dict["description2"] = replace_key_with_value(type_description2, name_dict)
- type_details_dict[type] = type_dict
- report_dict["details"] = type_details_dict
- """
- # ------------------------------
- # func summary dict
- """
- # generate func_description1
- func_list_count = len(score_func_list)
- over_80_count = len([num for num in score_func_list if num >= 80])
- over_80_proportion = over_80_count / func_list_count
- below_80_count = func_list_count - over_80_count
- below_80_proportion = below_80_count / func_list_count
- below_60_count = len([num for num in score_func_list if num < 60])
- below_60_proportion = below_60_count / func_list_count
- func_type_list = []
- unfunc_type_list = []
- for key, value in score_type_dict.items():
- unfunc_type_list.append(key) if value < 80 else func_type_list.append(key)
- if grade_func == '优秀':
- str_func_type = string_concatenate(func_type_list)
- func_description1 = f'算法在{str_func_type}上表现优秀;'
- elif grade_func == '良好':
- str_func_type = string_concatenate(func_type_list)
- func_description1 = f'算法在{str_func_type}上表现良好,满足设计指标要求。其中有{over_80_count}个用例得分超过80分,占比为{over_80_proportion * 100:.2f}%;'
- elif grade_func == '一般':
- str_unfunc_type = string_concatenate(unfunc_type_list)
- func_description1 = f'未满足设计指标要求。其中有{below_80_count}个用例得分低于80分,占比为{below_80_proportion * 100:.2f}%,需优化算法在{str_unfunc_type}上的表现;'
- elif grade_func == '较差':
- str_unfunc_type = string_concatenate(unfunc_type_list)
- func_description1 = f'未满足设计指标要求。其中有{below_60_count}个用例得分低于60分,占比为{below_60_proportion * 100:.2f}%,需优化算法在{str_unfunc_type}上的表现;'
- if not unfunc_type_list:
- str_func_type = string_concatenate(func_type_list)
- func_description2 = f'算法在{str_func_type}功能上的表现满足设计指标要求。'
- else:
- str_unfunc_type = string_concatenate(unfunc_type_list)
- func_description2 = f"算法在{str_unfunc_type}功能上需要重点优化。"
- report_dict["description1"] = replace_key_with_value(func_description1, type_name_dict)
- report_dict["description2"] = replace_key_with_value(func_description2, type_name_dict)
- # report_dict = {
- # "name": "功能性",
- # "weight": f"{weight_dimension * 100}%",
- # "score": score_func,
- # "level": grade_func,
- # "scoreList": score_func_list,
- # "levelDistribution": grade_func_distribution,
- # "description1": func_description1,
- # "description2": func_description2,
- # "noObjectCar": False,
- # "functionACC": follow_dict,
- # "functionLKA": lane_dict
- # }
- return report_dict
- def comp_multi_case_statistic(comp_cases_dict, config):
- """
- Args:
- comp_cases_dict:
- config:
- Returns:
- """
- # report_dict = {
- # "name": "合规性",
- # "weight": f"{weight_comp * 100}%",
- # "score": score_comp,
- # "level": grade_comp,
- # "scoreList": score_comp_list,
- # "levelDistribution": grade_comp_distribution,
- # "description1": comp_description1,
- # "description2": comp_description2,
- # "deductPoints": [deduct_1_dict, deduct_3_dict, deduct_6_dict, deduct_9_dict, deduct_12_dict]
- # }
- df_comp_cases = pd.DataFrame(comp_cases_dict).T.dropna(how='all')
- # common data
- bulitin_metric_list = config.builtinMetricList
- # config infos
- dimension_config = config.config["compliance"]
- metric_list = dimension_config['metric']
- type_list = dimension_config['type']
- type_name_dict = dimension_config['typeName']
- name_dict = dimension_config['name']
- unit_dict = dimension_config['unit']
- metric_dict = dimension_config['typeMetricDict']
- weight_comp = float(dimension_config['weightDimension'])
- report_dict = {
- "name": "合规性",
- "weight": f"{weight_comp * 100}%",
- }
- # calculate score_comp and grade_comp
- score_comp_list = df_comp_cases['score'].values.tolist()
- score_comp = cal_score_from_80(score_comp_list)
- grade_comp = score_grade(score_comp)
- report_dict["score"] = score_comp
- report_dict["level"] = grade_comp
- report_dict["scoreList"] = score_comp_list
- # calculate grade_distribution
- grade_comp_list = df_comp_cases['level'].values.tolist()
- grade_comp_distribution = grade_statistic(grade_comp_list)
- report_dict["levelDistribution"] = grade_comp_distribution
- deduct_cases_dict = df_comp_cases['details'].to_dict()
- df_deduct_cases = pd.DataFrame(deduct_cases_dict).T.dropna(how='all')
- score_type_dict = {}
- type_details_dict = {}
- # report_dict["deductPoints"] = []
- for type in type_list:
- type_dict = {
- "name": type_name_dict[type],
- }
- type_cases_dict = df_deduct_cases[type].to_dict()
- df_type_cases = pd.DataFrame(type_cases_dict).T.dropna(how='all')
- # calculate score_type and grade_type
- score_type_list = df_type_cases['score'].values.tolist()
- score_type = round(np.mean(score_type_list), 2)
- grade_type = score_grade(score_type)
- type_dict["score"] = score_type
- type_dict["level"] = grade_type
- score_type_dict[type] = score_type
- dfs = df_type_cases['indexes'].apply(lambda x: pd.DataFrame(x).T)
- df_type_indexes = pd.concat(dfs.tolist(), ignore_index=True)
- type_dict_indexes = {}
- for metric in metric_dict[type]:
- df_metric_indexes = df_type_indexes[df_type_indexes['name'] == f"{name_dict[metric]}"]
- metric_times_list = df_metric_indexes['times'].astype(int).values.tolist()
- metric_times_count = sum(metric_times_list)
- type_dict_indexes[metric] = {
- "name": f"{name_dict[metric]}",
- "times": metric_times_count
- }
- type_dict["indexes"] = type_dict_indexes
- # report_dict[type] = type_dict
- type_details_dict[type] = type_dict
- report_dict["details"] = type_details_dict
- # get compliance description
- comp_list_count = len(score_comp_list)
- below_60_count = len([num for num in score_comp_list if num < 60])
- below_60_proportion = below_60_count / comp_list_count
- if grade_comp == '优秀':
- comp_description1 = '车辆在本轮测试中无违反交通法规行为;'
- else:
- comp_description1 = f'未满足设计指标要求。其中有{below_60_count}个用例得分低于60分,占比为{below_60_proportion * 100:.2f}%,需优化算法在合规性上的表现;'
- comp_description2 = f'共有{comp_list_count}个用例,其中{below_60_count}个用例出现违规行为。'
- report_dict["description1"] = comp_description1
- report_dict["description2"] = comp_description2
- # report_dict = {
- # "name": "合规性",
- # "weight": f"{weight_comp * 100}%",
- # "score": score_comp,
- # "level": grade_comp,
- # "scoreList": score_comp_list,
- # "levelDistribution": grade_comp_distribution,
- # "description1": comp_description1,
- # "description2": comp_description2,
- # "deductPoints": [deduct_1_dict, deduct_3_dict, deduct_6_dict, deduct_9_dict, deduct_12_dict]
- # }
- return report_dict
- def comf_multi_case_statistic(comf_cases_dict, config):
- """
- Args:
- comf_cases_dict:
- config:
- Returns:
- """
- # report_dict = {
- # "name": "舒适性",
- # "weight": f"{weight_comfort * 100}%",
- # "score": score_comf,
- # "level": grade_comf,
- # "scoreList": score_comf_list,
- # "levelDistribution": grade_comf_distribution,
- # "description1": comf_description1,
- # "description2": comf_description2,
- # "description3": comf_description3,
- # "description4": comf_description4,
- # "indexes": [],
- # "zigzagData": zigzag_score_list,
- # "shakeData": shake_score_list,
- # "cadenceData": cadence_score_list,
- # "slamBrakeData": slam_brake_score_list,
- # "slamAccelData": slam_accel_score_list
- # }
- df_comf_cases = pd.DataFrame(comf_cases_dict).T.dropna(how='all')
- # common data
- bulitin_metric_list = config.builtinMetricList
- # config infos
- dimension_config = config.config["comfort"]
- metric_list = dimension_config['metric']
- type_list = dimension_config['type']
- type_name_dict = dimension_config['typeName']
- name_dict = dimension_config['name']
- unit_dict = dimension_config['unit']
- metric_dict = dimension_config['typeMetricDict']
- # # custom metric data
- customMetricParam = dimension_config['customMetricParam']
- # custom_data = custom_data
- # custom_param_dict = custom_metric_param_parser(customMetricParam)
- weight_dimension = float(dimension_config['weightDimension'])
- # optimal_dict = dimension_config['optimal']
- # kind_dict = dimension_config['kind']
- # multiple_dict = dimension_config['multiple']
- report_dict = {
- "name": "舒适性",
- "weight": f"{weight_dimension * 100}%",
- }
- # calculate score_comf and grade_comf
- score_comf_list = df_comf_cases['score'].values.tolist()
- score_comf = cal_score_from_80(score_comf_list)
- grade_comf = score_grade(score_comf)
- report_dict["score"] = score_comf
- report_dict["level"] = grade_comf
- report_dict["scoreList"] = score_comf_list
- # calculate grade_distribution
- grade_comf_list = df_comf_cases['level'].values.tolist()
- grade_comf_distribution = grade_statistic(grade_comf_list)
- report_dict["levelDistribution"] = grade_comf_distribution
- score_type_dict = {}
- value_list_dict = {}
- bad_count_dict = {}
- good_rate_dict = {}
- bad_rate_dict = {}
- type_details_dict = {}
- for type in type_list:
- type_dict = {
- "name": type_name_dict[type],
- }
- builtin_graph_dict = {}
- custom_graph_dict = {}
- df_comf_cases[type] = df_comf_cases["details"].apply(lambda x: x[type] if type in x.keys() else None)
- df_comf_cases1 = df_comf_cases.dropna(subset=[type])
- type_cases_dict = df_comf_cases1[type].to_dict()
- df_type_cases = pd.DataFrame(type_cases_dict).T.dropna(how='all')
- # calculate score_type and grade_type
- score_type_list = df_type_cases['score'].values.tolist()
- score_type = round(np.mean(score_type_list), 2)
- grade_type = score_grade(score_type)
- type_dict["score"] = score_type
- type_dict["level"] = grade_type
- score_type_dict[type] = score_type
- # calculate grade_distribution
- grade_type_list = df_type_cases['level'].values.tolist()
- grade_type_distribution = grade_statistic(grade_type_list)
- type_dict["gradeDistribution"] = grade_type_distribution
- dfs = df_type_cases['indexes'].apply(lambda x: pd.DataFrame(x).T)
- df_type_indexes = pd.concat(dfs.tolist(), ignore_index=True)
- # functionACC description
- type_metric1_list = [] # good
- type_metric2_list = [] # not good
- type_metric3_list = [] # bad
- # indexes
- type_dict_indexes = {}
- for metric in metric_dict[type]:
- df_metric_indexes = df_type_indexes[df_type_indexes['name'] == f"{name_dict[metric]}"]
- metric_value_list = df_metric_indexes['score'].astype(float).values.tolist()
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = min(metric_value_list) if metric_value_list else "-"
- metric_bad_count = len([x for x in metric_value_list if x < 80])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- # metric_number_list = df_metric_indexes['numberReal'].astype(int).values.tolist()
- metric_number_list = df_metric_indexes['numberReal'].astype(float).values.tolist()
- metric_duration_list = df_metric_indexes['durationReal'].astype(float).values.tolist()
- metric_strength_list = df_metric_indexes['strengthReal'].astype(float).values.tolist()
- type_metric1_list.append(metric) if avg_metric_value > 80 else type_metric2_list.append(
- metric) if min_metric_value < 80 else type_metric3_list.append(metric)
- type_dict_indexes[metric] = {
- "name": f"{name_dict[metric]}",
- "avgScore": avg_metric_value,
- "maxScore": max_metric_value,
- "minScore": min_metric_value,
- "avgNumber": f"{np.mean(metric_number_list):.2f}",
- "avgDuration": f"{np.mean(metric_duration_list):.2f}",
- "avgStrength": f"{np.mean(metric_strength_list):.2f}"
- }
- value_list_dict[metric] = metric_value_list
- bad_count_dict[metric] = metric_bad_count
- good_rate_dict[metric] = metric_good_rate
- bad_rate_dict[metric] = metric_bad_rate
- type_dict["indexes"] = type_dict_indexes
- for metric in metric_dict[type]:
- metric_data = {
- "name": f"{name_dict[metric]}",
- "data": value_list_dict[metric],
- # "markLine": [optimal_dict[metric]]
- }
- if metric in bulitin_metric_list:
- # metric_data["markLine"] = [optimal_dict[metric]]
- builtin_graph_dict[metric] = metric_data
- else:
- # metric_data["markLine"] = [custom_param_dict[metric]['optimal'][0]]
- custom_graph_dict[metric] = metric_data
- type_dict["builtin"] = builtin_graph_dict
- type_dict["custom"] = custom_graph_dict
- # description
- str_type_metric1 = ''
- str_type_metric2 = ''
- str_type_metric3 = ''
- if len(type_metric1_list) == len(metric_list):
- str_metric = string_concatenate(metric_list)
- type_description1 = f"{str_metric}指标最低分均超过设计指标要求,算法在{len(score_comf_list)}个用例中均表现良好。"
- elif len(type_metric3_list) == len(metric_list):
- str_metric = string_concatenate(metric_list)
- type_description1 = f"{str_metric}指标平均分低于设计指标要求,算法整体表现不佳,需要优化算法在这些指标上的表现;"
- else:
- if type_metric1_list:
- str_type1 = string_concatenate(type_metric1_list)
- str_type_metric1 += f"{str_type1}指标最低分超过设计指标要求,算法在{len(score_comf_list)}个用例中均表现良好;"
- for metric in type_metric2_list:
- str_type_metric2 += f"{name_dict[metric]}指标平均分超过设计指标要求,但是算法存在{bad_count_dict[metric]}个表现不佳用例,需要改进算法在这些用例中的表现;"
- if type_metric3_list:
- str_type3 = string_concatenate(type_metric3_list)
- str_type_metric3 += f"{str_type3}指标平均分低于设计指标要求,算法整体表现不佳,需要优化算法在这些指标上的表现;"
- type_description1 = ''
- type_description1 += (str_type_metric1 + '\n') if str_type_metric1 else ''
- type_description1 += (str_type_metric2 + '\n') if str_type_metric2 else ''
- type_description1 += str_type_metric3
- type_description1 = type_description1[:-1] + "。"
- type_description2 = "经计算可知,算法"
- for metric in metric_dict[type]:
- type_description2 += f"在{metric}指标上表现良好的概率为{good_rate_dict[metric]}%,"
- type_description2 = type_description2[:-1] + "。"
- type_dict["description1"] = replace_key_with_value(type_description1, name_dict)
- type_dict["description2"] = replace_key_with_value(type_description2, name_dict)
- type_details_dict[type] = type_dict
- report_dict["details"] = type_details_dict
- # calculate comfort description
- # str for comfort description1
- comf_list = []
- uncomf_list = []
- for metric in metric_list:
- uncomf_list.append(metric) if bad_count_dict[metric] > 0 else comf_list.append(metric)
- # generate comf_description1
- comf_list_count = len(score_comf_list)
- over_80_count = len([num for num in score_comf_list if num >= 80])
- over_80_proportion = over_80_count / comf_list_count
- below_80_count = comf_list_count - over_80_count
- below_80_proportion = below_80_count / comf_list_count
- below_60_count = len([num for num in score_comf_list if num < 60])
- below_60_proportion = below_60_count / comf_list_count
- if grade_comf == '优秀':
- comf_description1 = '乘客在本轮测试中体验舒适;'
- elif grade_comf == '良好':
- comf_description1 = f'算法在本轮测试中的表现满足设计指标要求。其中有{over_80_count}个用例得分超过80分,占比为{over_80_proportion * 100:.2f}%;'
- elif grade_comf == '一般':
- str_uncomf_metric = string_concatenate(uncomf_list)
- comf_description1 = f'未满足设计指标要求。其中有{below_80_count}个用例得分低于80分,占比为{below_80_proportion * 100:.2f}%,需优化算法在{str_uncomf_metric}上的表现;'
- elif grade_comf == '较差':
- str_uncomf_metric = string_concatenate(uncomf_list)
- comf_description1 = f'未满足设计指标要求。其中有{below_60_count}个用例得分低于60分,占比为{below_60_proportion * 100:.2f}%,需优化算法在{str_uncomf_metric}上的表现;'
- # str for comfort description2
- control_type = []
- if '画龙指标' in uncomf_list or '晃动指标' in uncomf_list:
- control_type.append('横向')
- if '顿挫指标' in uncomf_list or '急刹指标' in uncomf_list or '急加速指标' in uncomf_list in uncomf_list:
- control_type.append('纵向')
- str_control_type = '和'.join(control_type)
- if not control_type:
- comf_description2 = f"算法在舒适性维度上的表现满足设计指标要求"
- else:
- comf_description2 = f"算法应该优化对车辆的{str_control_type}控制,优化乘坐体验"
- report_dict["description1"] = replace_key_with_value(comf_description1, name_dict)
- report_dict["description2"] = replace_key_with_value(comf_description2, type_name_dict)
- # report_dict = {
- # "name": "舒适性",
- # "weight": f"{weight_comfort * 100}%",
- # "score": score_comf,
- # "level": grade_comf,
- # "scoreList": score_comf_list,
- # "levelDistribution": grade_comf_distribution,
- # "description1": comf_description1,
- # "description2": comf_description2,
- # "indexes": [],
- # "zigzagData": zigzag_score_list,
- # "shakeData": shake_score_list,
- # "cadenceData": cadence_score_list,
- # "slamBrakeData": slam_brake_score_list,
- # "slamAccelData": slam_accel_score_list
- # }
- return report_dict
- def effi_deviation_extra(str):
- if str[0] == '+':
- return str[1:].split("%")[0]
- else:
- return str.split("%")[0]
- def effi_multi_case_statistic(effi_cases_dict, config):
- """
-
- Args:
- effi_cases_dict:
- config:
- Returns:
- """
- # report_dict = {
- # "name": "高效性",
- # "weight": f"{weight_efficient * 100}%",
- # "score": score_effi,
- # "level": grade_effi,
- # "scoreList": score_effi_list,
- # "levelDistribution": grade_effi_distribution,
- # "description1": effi_description1,
- # "description2": effi_description2,
- # "description3": effi_description3,
- # "indexes": []
- # }
- df_effi_cases = pd.DataFrame(effi_cases_dict).T.dropna(how='all')
- # common data
- bulitin_metric_list = config.builtinMetricList
- # config infos
- dimension_config = config.config["efficient"]
- metric_list = dimension_config['metric']
- type_list = dimension_config['type']
- type_name_dict = dimension_config['typeName']
- name_dict = dimension_config['name']
- unit_dict = dimension_config['unit']
- metric_dict = dimension_config['typeMetricDict']
- # # custom metric data
- customMetricParam = dimension_config['customMetricParam']
- # custom_data = custom_data
- custom_param_dict = custom_metric_param_parser(customMetricParam)
- weight_efficient = float(dimension_config['weightDimension'])
- optimal_dict = dimension_config['optimal']
- kind_dict = dimension_config['kind']
- multiple_dict = dimension_config['multiple']
- report_dict = {
- "name": "高效性",
- "weight": f"{weight_efficient * 100}%",
- }
- # calculate score_effi and grade_effi
- score_effi_list = df_effi_cases['score'].values.tolist()
- score_effi = cal_score_from_80(score_effi_list)
- grade_effi = score_grade(score_effi)
- report_dict["score"] = score_effi
- report_dict["level"] = grade_effi
- report_dict["scoreList"] = score_effi_list
- # calculate grade_distribution
- grade_effi_list = df_effi_cases['level'].values.tolist()
- grade_effi_distribution = grade_statistic(grade_effi_list)
- report_dict["levelDistribution"] = grade_effi_distribution
- score_type_dict = {}
- value_list_dict = {}
- bad_count_dict = {}
- good_rate_dict = {}
- bad_rate_dict = {}
- type_details_dict = {}
- for type in type_list:
- type_dict = {
- "name": type_name_dict[type],
- }
- builtin_graph_dict = {}
- custom_graph_dict = {}
- df_effi_cases[type] = df_effi_cases["details"].apply(lambda x: x[type] if type in x.keys() else None)
- df_effi_cases1 = df_effi_cases.dropna(subset=[type])
- type_cases_dict = df_effi_cases1[type].to_dict()
- df_type_cases = pd.DataFrame(type_cases_dict).T.dropna(how='all')
- # calculate score_type and grade_type
- score_type_list = df_type_cases['score'].values.tolist()
- score_type = round(np.mean(score_type_list), 2)
- grade_type = score_grade(score_type)
- type_dict["score"] = score_type
- type_dict["level"] = grade_type
- score_type_dict[type] = score_type
- # calculate grade_distribution
- grade_type_list = df_type_cases['level'].values.tolist()
- grade_type_distribution = grade_statistic(grade_type_list)
- type_dict["gradeDistribution"] = grade_type_distribution
- # calculate type indexes
- # type_indexes_dict = df_type_cases['indexes'].explode().tolist()
- # df_type_indexes = pd.DataFrame(type_indexes_dict)
- dfs = df_type_cases['indexes'].apply(lambda x: pd.DataFrame(x).T)
- df_type_indexes = pd.concat(dfs.tolist(), ignore_index=True)
- # functionACC description
- type_metric1_list = [] # good
- type_metric2_list = [] # not good
- type_metric3_list = [] # bad
- # indexes
- type_dict_indexes = {}
- for metric in metric_dict[type]:
- df_metric_indexes = df_type_indexes[df_type_indexes['name'] == f"{name_dict[metric]}"]
- kind_metric = kind_dict[metric] if metric in bulitin_metric_list else custom_param_dict[metric]['kind'][0]
- optimal_metric = optimal_dict[metric] if metric in bulitin_metric_list else \
- custom_param_dict[metric]['optimal'][0]
- multiple_metric0 = multiple_dict[metric][0] if metric in bulitin_metric_list else \
- custom_param_dict[metric]['multiple'][0][0]
- multiple_metric1 = multiple_dict[metric][1] if metric in bulitin_metric_list else \
- custom_param_dict[metric]['multiple'][0][1]
- if kind_metric == 1: # 越大越好
- metric_value_list = df_metric_indexes['value'].astype(float).values.tolist()
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = max(metric_value_list) if metric_value_list else "-"
- if not optimal_metric:
- metric_bad_count = 0
- else:
- metric_bad_count = len([x for x in metric_value_list if x < float(optimal_metric)])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- type_metric1_list.append(metric) if metric_bad_rate == 0 else type_metric2_list.append(
- metric) if avg_metric_value > float(optimal_metric) else type_metric3_list.append(metric)
- elif kind_metric == -1: # 越小越好
- metric_value_list = df_metric_indexes['value'].astype(float).values.tolist()
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = max(metric_value_list) if metric_value_list else "-"
- if not optimal_metric:
- metric_bad_count = 0
- else:
- metric_bad_count = len([x for x in metric_value_list if x > float(optimal_metric)])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- type_metric1_list.append(metric) if metric_bad_rate == 0 else type_metric2_list.append(
- metric) if avg_metric_value < float(optimal_metric) else type_metric3_list.append(metric)
- elif kind_metric == 0:
- metric_value_list = df_metric_indexes['value'].astype(float).values.tolist()
- avg_metric_value = round(np.mean(metric_value_list), 2) if metric_value_list else "-"
- max_metric_value = max(metric_value_list) if metric_value_list else "-"
- min_metric_value = max(metric_value_list) if metric_value_list else "-"
- if not optimal_metric:
- metric_bad_count = 0
- else:
- metric_bad_count = len([x for x in metric_value_list if (
- x > float(optimal_metric) * multiple_metric1 or x < float(
- optimal_metric) * multiple_metric0)])
- metric_bad_rate = round(metric_bad_count / len(metric_value_list) * 100, 2) if metric_value_list else 0
- metric_good_rate = round(100 - metric_bad_rate, 2)
- if not optimal_metric:
- type_metric1_list.append(metric)
- else:
- type_metric1_list.append(metric) if metric_bad_rate == 0 else type_metric2_list.append(metric) if (
- float(optimal_metric) * multiple_metric1 > avg_metric_value > float(
- optimal_metric) * multiple_metric0) else type_metric3_list.append(
- metric)
- type_dict_indexes[metric] = {
- "name": f"{name_dict[metric]}",
- "average": avg_metric_value,
- "max": max_metric_value,
- "min": min_metric_value,
- "number": metric_bad_count
- }
- if not optimal_metric:
- type_dict_indexes[metric]["range"] = f"-"
- else:
- if kind_metric == -1:
- type_dict_indexes[metric]["range"] = f"[0, {optimal_metric}]"
- elif kind_metric == 1:
- type_dict_indexes[metric]["range"] = f"[{optimal_metric}, inf)"
- elif kind_metric == 0:
- type_dict_indexes[metric][
- "range"] = f"[{float(optimal_metric) * multiple_metric0}, {float(optimal_metric) * multiple_metric1}]"
- value_list_dict[metric] = metric_value_list
- bad_count_dict[metric] = metric_bad_count
- good_rate_dict[metric] = metric_good_rate
- bad_rate_dict[metric] = metric_bad_rate
- type_dict["indexes"] = type_dict_indexes
- for metric in metric_dict[type]:
- metric_data = {
- "name": f"{name_dict[metric]}",
- "data": value_list_dict[metric],
- # "markLine": [optimal_dict[metric]]
- }
- if metric in bulitin_metric_list:
- metric_data["markLine"] = [optimal_dict[metric]]
- builtin_graph_dict[metric] = metric_data
- else:
- metric_data["markLine"] = [custom_param_dict[metric]['optimal'][0]]
- custom_graph_dict[metric] = metric_data
- type_dict["builtin"] = builtin_graph_dict
- type_dict["custom"] = custom_graph_dict
- # description
- str_type_metric1 = ''
- str_type_metric2 = ''
- str_type_metric3 = ''
- if len(type_metric1_list) == len(metric_list):
- str_metric = string_concatenate(metric_list)
- type_description1 = f"{str_metric}指标均表现良好,平均值在合理范围内且不存在不合格用例。"
- elif len(type_metric3_list) == len(metric_list):
- str_metric = string_concatenate(metric_list)
- type_description1 = f"{str_metric}指标平均值在合理范围外,算法在大部分用例下均表现不佳,需重点优化。"
- else:
- if type_metric1_list:
- str_type1 = string_concatenate(type_metric1_list)
- str_type_metric1 += f"{str_type1}指标表现良好,平均值在合理范围内且不存在不合格用例;"
- for metric in type_metric2_list:
- str_type_metric2 += f"{name_dict[metric]}指标表现不佳,存在{bad_count_dict[metric]}个不合格用例,需要改进算法在这些用例中的表现;"
- if type_metric3_list:
- str_type3 = string_concatenate(type_metric3_list)
- str_type_metric3 += f"{str_type3}指标平均值在合理范围外,算法在大部分用例下均表现不佳,需重点优化。"
- type_description1 = ''
- type_description1 += (str_type_metric1 + '\n') if str_type_metric1 else ''
- type_description1 += (str_type_metric2 + '\n') if str_type_metric2 else ''
- type_description1 += str_type_metric3
- type_description1 = type_description1[:-1] + "。"
- # type_description2 = "经计算可知,"
- # for metric in metric_dict[type]:
- # type_description2 += f"{metric}指标位于合理区间的占比为{good_rate_dict[metric]}%,"
- # type_description2 = type_description2[:-1] + "。"
- type_dict["description1"] = replace_key_with_value(type_description1, name_dict)
- # type_dict["description2"] = replace_key_with_value(type_description2, name_dict)
- type_details_dict[type] = type_dict
- report_dict["details"] = type_details_dict
- # efficient description1
- effi_list = []
- ineffi_list = []
- for metric in metric_list:
- ineffi_list.append(metric) if bad_count_dict[metric] > 0 else effi_list.append(metric)
- # generate effi_description1
- effi_list_count = len(score_effi_list)
- over_80_count = len([num for num in score_effi_list if num >= 80])
- over_80_proportion = over_80_count / effi_list_count
- below_80_count = effi_list_count - over_80_count
- below_80_proportion = below_80_count / effi_list_count
- below_60_count = len([num for num in score_effi_list if num < 60])
- below_60_proportion = below_60_count / effi_list_count
- effi_description1 = ''
- if grade_effi == '优秀':
- effi_description1 = '车辆行驶效率高;'
- elif grade_effi == '良好':
- effi_description1 = f'算法在本轮测试中的表现满足设计指标要求。其中有{over_80_count}个用例得分超过80分,占比为{over_80_proportion * 100:.2f}%;'
- elif grade_effi == '一般':
- str_ineffi_type = string_concatenate(ineffi_list)
- effi_description1 = f'未满足设计指标要求。其中有{below_80_count}个用例得分低于80分,占比为{below_80_proportion * 100:.2f}%,需优化算法在{str_ineffi_type}上的表现;'
- elif grade_effi == '较差':
- str_ineffi_type = string_concatenate(ineffi_list)
- effi_description1 = f'未满足设计指标要求。其中有{below_60_count}个用例得分低于60分,占比为{below_60_proportion * 100:.2f}%,需优化算法在{str_ineffi_type}上的表现;'
- # efficient description2
- if not ineffi_list:
- effi_description2 = "算法在高效性维度上的表现满足设计指标要求。"
- else:
- effi_description2 = "算法应该优化车辆的规划控制逻辑,提高算法的通行效率。"
- report_dict["description1"] = replace_key_with_value(effi_description1, type_name_dict)
- report_dict["description2"] = replace_key_with_value(effi_description2, type_name_dict)
- # report_dict = {
- # "name": "高效性",
- # "weight": f"{weight_efficient * 100}%",
- # "score": score_effi,
- # "level": grade_effi,
- # "scoreList": score_effi_list,
- # "levelDistribution": grade_effi_distribution,
- # "description1": effi_description1,
- # "description2": effi_description2,
- # "description3": effi_description3,
- # "indexes": [
- # {
- # "name": "平均速度(km/h)",
- # "average": round(np.mean(avg_v_list), 2),
- # "max": max(avg_v_list),
- # "min": min(avg_v_list),
- # "range": "-",
- # "number": avg_v_bad_count
- # }, {
- # "name": "停车次数(次)",
- # "average": round(np.mean(stop_count_list), 2),
- # "max": max(stop_count_list),
- # "min": min(stop_count_list),
- # "range": f"[0, {optimal_dict['stopCount']}]",
- # "number": stop_count_bad_count
- # }, {
- # "name": "停车平均时长(s)",
- # "average": round(np.mean(stop_time_list), 2),
- # "max": max(stop_time_list),
- # "min": min(stop_time_list),
- # "range": f"[0, {optimal_dict['stopDuration']}]",
- # "number": stop_time_bad_count
- # }
- # ]
- # }
- return report_dict
- def inverse_mileage_format(mileage):
- if "公里" in mileage:
- num = float(mileage[:-2]) * 1000
- elif "米" in mileage:
- num = float(mileage[:-1])
- else:
- raise ValueError("输入的字符串格式不正确")
- return num
- def inverse_duration_format(duration):
- time_parts = duration.split("时")
- hour = int(time_parts[0]) if len(time_parts) > 1 else 0
- time_parts = time_parts[-1].split("分")
- minute = int(time_parts[0]) if len(time_parts) > 1 else 0
- if hour or minute:
- second = int(time_parts[-1][:-1]) if "秒" in time_parts[-1] else 0
- else:
- second = float(time_parts[-1][:-1]) if "秒" in time_parts[-1] else 0
- total_seconds = hour * 3600 + minute * 60 + second
- return total_seconds
- def multi_case_statistic(cases_dict, config):
- """
- Args:
- cases_dict:
- config:
- Returns:
- """
- logger = log.get_logger()
- cases_df = pd.DataFrame(cases_dict).T.dropna(how='all')
- case_number = cases_df.shape[0]
- # done_number = 0
- # fail_number = 0
- # sceneNumber = f"共测试{case_number}个用例,其中成功评价{done_number}个用例,有{fail_number}个用例评价失败"
- sceneNumber = f"共测试{case_number}个用例"
- cases_df['testMileage'] = cases_df['testMileage'].apply(inverse_mileage_format)
- cases_df['testDuration'] = cases_df['testDuration'].apply(inverse_duration_format)
- mileage_sum = mileage_format(cases_df['testMileage'].sum())
- duration_sum = duration_format(cases_df['testDuration'].sum())
- score_all = cal_score_from_80(cases_df['algorithmComprehensiveScore'].astype(float).values.tolist())
- grade_all = score_grade(score_all)
- multi_dict = {
- 'sceneNumber': sceneNumber,
- 'testMileageSum': mileage_sum,
- 'testDurationSum': duration_sum,
- 'algorithmComprehensiveScore': score_all,
- 'algorithmLevel': grade_all,
- }
- dimension_details_dict = {}
- # metric check
- dimension_list = config.dimension_list
- dimension_name_dict = config.dimension_name
- bad_dimension_list = []
- score_dimension_dict = {}
- for dimension in dimension_list:
- cases_df[dimension] = cases_df["details"].apply(lambda x: x[dimension] if dimension in x.keys() else None)
- dimension_cases_dict = cases_df[dimension].to_dict()
- if dimension in config.builtinDimensionList:
- dimension_dict = globals()[f"{dimension[:4]}_multi_case_statistic"](dimension_cases_dict, config)
- else:
- dimension_dict = custom_multi_case_statistic(dimension_cases_dict, config, dimension)
- pass
- score_dimension_dict[dimension] = dimension_dict['score']
- if score_dimension_dict[dimension] < 80:
- bad_dimension_list.append(dimension)
- dimension_details_dict[dimension] = dimension_dict
- multi_dict["details"] = dimension_details_dict
- if not bad_dimension_list:
- algorithmResultDescription = '综上所述,算法在各个维度的表现俱佳。'
- else:
- str_bad_dimension = string_concatenate(bad_dimension_list)
- algorithmResultDescription = f'综上所述,建议算法优化在{str_bad_dimension}指标上的表现。'
- multi_dict['algorithmResultDescription'] = replace_key_with_value(algorithmResultDescription, dimension_name_dict)
- # multi_dict = {
- # 'sceneNumber': sceneNumber,
- # 'testMileageSum': mileage_sum,
- # 'testDurationSum': duration_sum,
- # 'algorithmComprehensiveScore': score_all,
- # 'algorithmResultDescription': algorithmResultDescription,
- # 'algorithmLevel': grade_all,
- # 'safe': report_dict,
- # 'function': func_dict,
- # 'compliance': report_dict,
- # 'comfort': report_dict,
- # 'efficient': report_dict
- # }
- return multi_dict
- def multi_report_post(multi_dict, task_name):
- """
- This function generate the multiple cases report based on multi_dict.
- Arguments:
- multi_dict: A dict of single case scores and descriptions.
- task_files: A str of path of files, which says where the generated report is to be stored.
- Returns:
- None
- """
- url_json = 'http://36.110.106.156:18081/report/generate'
- data_json = json.dumps(multi_dict)
- response = requests.post(url_json, data_json, headers={'Content-Type': 'application/json; charset=utf-8'})
- runtime = time.strftime('%Y%m%d%H%M%S', time.localtime())
- p = pathlib.Path(rf'C:\Users\cicv\Desktop\{task_name}_{runtime}.pdf')
- # p = pathlib.Path(rf'..\results\report\{algorithmName}_{runtime}.pdf')
- p.write_bytes(response.content)
- def multi_report_generate(task_path, cases_dict_json_path, config_path, resPath):
- logger = log.get_logger()
- cases_dict = json2dict(os.path.join(cases_dict_json_path, "cases_dict.json"))
- config = json2dict(os.path.join(config_path, "config.json"))
- if len(cases_dict) > 1:
- try:
- # multiple cases report statistic and generate
- multi_dict = multi_case_statistic(cases_dict, config)
- if resPath:
- with open(f'{resPath}/report.json', 'w', encoding='utf-8') as f:
- f.write(json.dumps(multi_dict, ensure_ascii=False))
- with open(f'{task_path}/report.json', 'w', encoding='utf-8') as f:
- f.write(json.dumps(multi_dict, ensure_ascii=False))
- except:
- traceback.print_exc()
- print(1)
- logger.error("MULTIPLE_CASES_EVAL: Evaluate multiple cases ERROR!")
- sys.exit(-1)
|