Python中提升大规模列表交叉匹配效率的优化建议求助
我正在实现记录间的交叉匹配:拥有一个由子列表构成的记录列表,需要逐行查找符合特定规则(如时间容差等)的最佳匹配,当前代码如下:
def CountOcurrencies(qsoToCheck: list, qsoList: list): # Loop in QSOs for qsoLine in qsoList: # Check if Call and DX matches if qsoToCheck[4] == qsoLine[0] and qsoToCheck[0] == qsoLine[4]: ... # Check if.... ... return resultCode
主代码中会为每条记录调用该方法:
# Loop for every QSO to get matches for qsoIndex in range(len(listValidQso)): # Write output of CountOcurrencies to Valid QSO array listValidQso[qsoIndex][19] = str(CountOcurrencies(listValidQso[qsoIndex], listValidQso))
问题在于listValidQso包含约6万个子列表,整套代码运行耗时约10分钟。我尝试用numpy.where过滤列表子集后再执行匹配,但整体耗时几乎无变化(大部分时间消耗在numpy.where操作上)。
我在CountOcurrencies方法中尝试了以下代码:
# Filter QSO list to save some time print("input size: " + str(len(qsoList))) npAry = numpy.array(qsoList) rows, cols = numpy.where(npAry == qsoToCheck[0]) filteredQsoList = npAry[rows] print("output size: " + str(len(filteredQsoList)))
但该过滤操作单次耗时约1.5秒,总运行时间几乎没有改善,请问有什么优化建议?
预构建配对索引字典:这是最有效的优化方式,避免每次全量扫描6万条记录。提前把所有记录按
(对方呼号, 我方DX)的配对做分组,用字典存储,后续查找时直接取对应分组的子集,不用再遍历全量数据。
示例代码:from collections import defaultdict # 只执行一次的预索引构建 match_index = defaultdict(list) for qso in listValidQso: # 键为(当前记录的呼号, 当前记录的DX)对应的反向配对 key = (qso[4], qso[0]) match_index[key].append(qso) # 修改后的匹配方法 def CountOcurrencies(qsoToCheck: list, match_index: dict): # 直接获取符合呼号+DX配对的候选记录 target_key = (qsoToCheck[0], qsoToCheck[4]) candidates = match_index.get(target_key, []) resultCode = 0 # 仅在候选集里检查时间容差等规则 for qsoLine in candidates: # 这里写时间容差等后续检查逻辑 ... return resultCode主代码调用时直接传入预构建的索引,无需再传全量列表:
for qsoIndex in range(len(listValidQso)): listValidQso[qsoIndex][19] = str(CountOcurrencies(listValidQso[qsoIndex], match_index))废弃numpy的实时转换方案:你之前每次调用方法都把全量列表转成numpy数组,这是巨大的性能浪费。即使要用numpy,也应该提前把
listValidQso转成数组一次,但numpy处理异构子列表(元素类型不一致时)的效率远不如字典索引,没必要坚持。预转换时间字段为数值类型:如果时间容差是核心检查逻辑,提前把所有记录的时间字符串转成Unix时间戳或数值型时间(比如分钟数),这样比较时直接做数值差判断,比字符串比对快很多。
批量处理配对组:可以直接遍历预构建的索引字典,处理每个配对组内的记录匹配,避免单条记录循环调用方法的开销,进一步提升效率。
减少不必要的类型转换:如果后续逻辑不需要字符串类型的结果,主代码里可以不用把
resultCode转成str,节省类型转换的微小开销。
内容的提问来源于stack exchange,提问作者iu2frl

