基于Scikit Learn/Numpy区分线性飞行航迹与非线性异常路径
基于Numpy与Scikit-learn的线性/非线性航迹区分实现
你已经完成航迹中心化,无需再处理全局坐标偏移问题,核心抓两类航迹的本质差异即可:民航线性航迹几乎沿直线行进,仅存在小幅方向微调;异常军机航迹偏离直线程度高,存在大角度急转弯。整个实现分两步走,特征工程用Numpy完成,分类用Scikit-learn实现,不需要复杂模型。
第一步:特征计算(Numpy实现,核心环节)
先统一处理每条航迹:先按时间戳排序避免点序混乱,再计算5个区分度极高的统计特征,代码如下:
import numpy as np def extract_track_features(track): """ 输入单条中心化后的航迹数组,shape=(N,3),列顺序为纬度、经度、时间戳 输出该航迹的特征向量 """ # 按时间戳重排,避免原始数据乱序 track = track[np.argsort(track[:, 2])] lats, lons, ts = track[:, 0], track[:, 1], track[:, 2] features = [] # 1. 线性拟合残差:线性航迹的点会紧贴时间-经纬度的拟合直线,残差极小 t_norm = (ts - ts.min()) / (ts.max() - ts.min() + 1e-8) # 时间归一化避免数值问题 # 分别对纬度、经度做一阶线性拟合 lat_coef = np.polyfit(t_norm, lats, deg=1) lon_coef = np.polyfit(t_norm, lons, deg=1) lat_pred = np.polyval(lat_coef, t_norm) lon_pred = np.polyval(lon_coef, t_norm) total_residual = np.mean(np.abs(lats - lat_pred)) + np.mean(np.abs(lons - lon_pred)) features.append(total_residual) # 2. 转向角统计:异常航迹存在大角度急转,该类特征区分度最高 displacements = np.diff(track[:, :2], axis=0) # 相邻点位移向量 angles = np.arctan2(displacements[:, 1], displacements[:, 0]) # 每个航段的方位角 turn_angles = np.abs(np.diff(np.unwrap(angles))) # 相邻航段的转角绝对值,unwrap处理角度环绕问题 features.extend([ np.max(turn_angles), # 最大转角 np.mean(turn_angles), # 平均转角 np.std(turn_angles) # 转角波动标准差 ]) # 3. 航迹弯曲度:总路径长度/首尾点直线距离,直线航迹该值接近1,越弯曲值越大 segment_lengths = np.linalg.norm(displacements, axis=1) total_length = segment_lengths.sum() start_end_length = np.linalg.norm(track[-1, :2] - track[0, :2]) sinuosity = total_length / (start_end_length + 1e-8) features.append(sinuosity) return np.array(features)
第二步:航迹分类(Scikit-learn实现)
根据你有没有标注数据,选监督或者无监督方案即可:
有标注数据(监督分类,准确率最高)
特征维度只有5个,不需要复杂模型,用随机森林或者逻辑回归就足够,泛化性强还不容易过拟合:
from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report # 先批量提取所有航迹的特征,X shape=(航迹总数, 5),y为标签:0=民航线性航迹,1=异常军机航迹 # X = np.array([extract_track_features(t) for t in all_tracks]) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 构建分类流水线:先做特征标准化,再训练分类器 clf = make_pipeline( StandardScaler(), RandomForestClassifier(n_estimators=100, random_state=42) ) clf.fit(X_train, y_train) # 效果评估 print(classification_report(y_test, clf.predict(X_test)))
无标注数据(无监督异常检测)
实际场景中民航航迹占绝大多数,异常航迹属于离群点,直接用孤立森林检测即可,甚至手动设阈值都能达到很高的准确率:
手动阈值参考(可根据自有数据集微调):
- 最大转角超过0.5弧度(约30度)直接判定为异常
- 航迹弯曲度大于1.15直接判定为异常
- 线性拟合残差超过正常航迹均值+3倍标准差判定为异常
无监督检测代码:
from sklearn.ensemble import IsolationForest # contamination为数据集中异常航迹的预估占比,按实际场景调整 detector = IsolationForest(contamination=0.05, random_state=42) detector.fit(X) # 预测结果:1=正常线性航迹,-1=异常非线性航迹 predict_result = detector.predict(X)
补充说明
- 如果航迹采样间隔不均匀,先按固定时间间隔对航迹重采样再算特征,避免采样点疏密带来的计算偏差
- 如果航迹覆盖的纬度范围超过5度,建议先把经纬度转成局部平面坐标(比如UTM投影)再计算角度、距离,结果会更精准
- 这几个手工特征的区分度已经足够,不需要上深度学习或者复杂的轨迹模型,可解释性远高于黑盒模型
内容的提问来源于stack exchange,提问作者JHM
相关产品推荐
相关产品推荐

