版本对比时首行标签错误问题的排查及替代方案咨询
问题
现有如下结构的DataFrame:
api_spec_id commit_date info_version label 500 2020-07-22 1.1 500 2020-11-09 1.1 500 2020-11-16 1.1 500 2020-11-16 1.1 500 2020-11-23 1.1 500 2021-02-01 1.1 138641 2020-06-25 0.1.0 major 138641 2020-06-25 0.1.0 138641 2020-06-27 0.1.0 138641 2020-06-27 0.1.9 patch 138641 2020-06-27 0.1.10 patch 138641 2020-06-27 0.1.11 patch 138641 2020-06-27 0.1.13 patch 138641 2020-06-27 0.1.14 patch 138641 2020-06-27 0.1.15 patch 138641 2020-06-28 0.2.0 minor.patch 138641 2020-06-30 0.2.1 patch 138641 2020-07-01 0.3.0 minor.patch 138641 2020-07-08 0.4.0 minor 138641 2020-07-11 0.5.0 minor 138641 2020-07-12 0.6.0 minor
尝试对比连续行的版本并打标签时,出现问题:部分api_spec_id的首行被错误打上标签,实际该行无前置行可对比,标签应为空。
使用的两段处理代码如下:
第一段:正则提取标准语义化版本
pat = r'(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:\.(?P<micro>\d+))?' sem = new['info_version'].str.extract(pat).fillna(0).astype(int) diff = sem.diff().fillna(0).ne(0) new['label'] = diff.dot(sem.columns + '.').str.rstrip('.')
第二段:借助Version类解析非标准版本
attrs = ['major', 'minor', 'micro', 'pre', 'post', 'dev', 'local'] def extract_version(ver): ver = Version(ver) return pd.Series({attr: getattr(ver, attr) for attr in attrs}, dtype=str) sem = new['info_version'].agg(extract_version).fillna('').rename(columns={'micro': 'patch'}) diff = sem.ne(sem.shift().fillna(sem.iloc[0])) new['label'] = diff.dot(sem.columns + '.').str.rstrip('.')
需要排查问题根源,并获取其他计算版本差异的可行方案。
排查思路与解决方案
问题根源
- 未按
api_spec_id分组处理:当前代码对整个DataFrame做全局版本对比,会跨不同API进行版本对比,导致分组首行错误继承上一个API的版本差异标签。 - 首行差异处理错误:两段代码中,首行的
diff处理(fillna(0)或fillna(sem.iloc[0]))会让首行和自身对比,产生无意义的差异标签,而非置空。
改进方案
核心思路是按api_spec_id分组,在组内做版本对比,并强制组内首行标签为空。
方案一:正则提取标准语义化版本(改进版)
import pandas as pd pat = r'(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:\.(?P<micro>\d+))?' def process_group(group): # 提取版本字段 sem = group['info_version'].str.extract(pat).fillna(0).astype(int) # 组内计算差异,首行保留NaN diff = sem.diff().ne(0) # 生成标签,首行转为空字符串 label = diff.dot(sem.columns + '.').str.rstrip('.') label.iloc[0] = '' group['label'] = label return group # 按api_spec_id分组处理 new = new.groupby('api_spec_id', group_keys=False).apply(process_group)
方案二:Version类解析非标准版本(改进版)
from packaging.version import Version import pandas as pd attrs = ['major', 'minor', 'micro', 'pre', 'post', 'dev', 'local'] def extract_version(ver): ver = Version(ver) return pd.Series({attr: getattr(ver, attr) for attr in attrs}, dtype=str) def process_group(group): # 提取版本属性 sem = group['info_version'].agg(extract_version).fillna('').rename(columns={'micro': 'patch'}) # 组内对比上一行,首行保留False(无差异) diff = sem.ne(sem.shift()) # 生成标签,首行置空 label = diff.dot(sem.columns + '.').str.rstrip('.') label.iloc[0] = '' group['label'] = label return group # 按api_spec_id分组处理 new = new.groupby('api_spec_id', group_keys=False).apply(process_group)
额外优化点
如果commit_date存在乱序,建议在分组后先按commit_date排序,保证版本对比是按时间顺序进行:
def process_group(group): group = group.sort_values('commit_date') # 后续处理逻辑不变 ...
内容的提问来源于stack exchange,提问作者Brie MerryWeather
相关产品推荐
相关产品推荐

