You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用K-means聚类由连续连线组成的轨迹?

完整轨迹聚类的可行方法

针对连续线段构成的完整轨迹聚类,不能直接用单线段的K-means思路——因为轨迹是有序的连续序列,需要结合轨迹的整体形态、序列特征来处理,以下是几种实用方案:


方案1:提取轨迹全局特征 + 传统聚类

把每条轨迹转换成固定长度的特征向量,再用你熟悉的K-means这类算法聚类。核心是提取能代表轨迹整体特征的指标,比如起点/终点坐标、轨迹总长度、平均方向角、x/y方向最大位移、拐点数量等。

示例代码

import numpy as np
from sklearn.cluster import KMeans

# 提取单条轨迹的特征
def extract_trajectory_features(trajectory_df):
    # 把连续线段转换成完整点序列
    points = [(trajectory_df.iloc[0]['start_x'], trajectory_df.iloc[0]['start_y'])]
    for _, row in trajectory_df.iterrows():
        points.append((row['end_x'], row['end_y']))
    points = np.array(points)
    
    # 计算各类特征
    start_point = points[0]
    end_point = points[-1]
    total_length = np.sum(np.linalg.norm(points[1:] - points[:-1], axis=1))
    
    # 计算线段方向角的均值
    dx = points[1:, 0] - points[:-1, 0]
    dy = points[1:, 1] - points[:-1, 1]
    avg_angle = np.mean(np.arctan2(dy, dx))
    
    # x/y方向的最大位移
    max_disp_x = np.max(points[:,0]) - np.min(points[:,0])
    max_disp_y = np.max(points[:,1]) - np.min(points[:,1])
    
    # 统计拐点数量(方向角变化超过90度的次数)
    angle_diff = np.abs(np.diff(np.arctan2(dy, dx)))
    inflection_count = np.sum(angle_diff > np.pi/2)
    
    # 拼接成特征向量
    return np.hstack([start_point, end_point, total_length, avg_angle, max_disp_x, max_disp_y, inflection_count])

# 假设你有一个列表trajectory_dfs,每个元素是一条完整轨迹的DataFrame
feature_matrix = np.array([extract_trajectory_features(df) for df in trajectory_dfs])

# 运行K-means聚类
kmeans = KMeans(n_clusters=3)  # 替换为你需要的聚类数
cluster_labels = kmeans.fit_predict(feature_matrix)

方案2:动态时间规整(DTW) + 基于距离的聚类

如果轨迹长度不一但形态相似(比如一条是另一条的慢放/快放版),可以用DTW计算两条轨迹的相似度,再用层次聚类或DBSCAN这类基于距离的算法。DTW能对齐不同长度的序列,精准计算形状相似度。

示例代码

import numpy as np
from sklearn.cluster import AgglomerativeClustering
from scipy.spatial.distance import cdist
import fastdtw  # 需要先安装:pip install fastdtw

# 把每条轨迹转换成点序列
def get_trajectory_points(trajectory_df):
    points = [(trajectory_df.iloc[0]['start_x'], trajectory_df.iloc[0]['start_y'])]
    for _, row in trajectory_df.iterrows():
        points.append((row['end_x'], row['end_y']))
    return np.array(points)

trajectory_points_list = [get_trajectory_points(df) for df in trajectory_dfs]

# 定义DTW距离计算函数
def dtw_similarity(t1, t2):
    distance, _ = fastdtw.fastdtw(t1, t2, dist=lambda x,y: np.linalg.norm(x-y))
    return distance

# 生成两两轨迹的距离矩阵
distance_matrix = cdist(trajectory_points_list, trajectory_points_list, metric=dtw_similarity)

# 用层次聚类
cluster = AgglomerativeClustering(n_clusters=3, affinity='precomputed', linkage='average')
cluster_labels = cluster.fit_predict(distance_matrix)

方案3:轨迹简化 + 特征聚类

如果轨迹节点太多,先通过Douglas-Peucker算法简化轨迹,保留关键节点(比如拐点),再用简化后的轨迹提取特征或直接聚类——既能大幅减少计算量,又能保留轨迹核心形态。

示例代码

import numpy as np
from sklearn.cluster import KMeans

# Douglas-Peucker轨迹简化算法
def douglas_peucker(points, epsilon):
    if len(points) <= 2:
        return points.tolist()
    start, end = points[0], points[-1]
    # 计算中间点到线段的距离
    cross = (end[0]-start[0])*(start[1]-points[1:-1,1]) - (start[0]-points[1:-1,0])*(end[1]-start[1])
    distances = np.abs(cross) / np.linalg.norm(end - start)
    max_dist_idx = np.argmax(distances) + 1
    if distances[max_dist_idx-1] > epsilon:
        left = douglas_peucker(points[:max_dist_idx+1], epsilon)
        right = douglas_peucker(points[max_dist_idx:], epsilon)
        return left[:-1] + right
    else:
        return [start.tolist(), end.tolist()]

# 简化所有轨迹(epsilon根据坐标尺度调整,值越大简化越彻底)
simplified_trajectories = []
for df in trajectory_dfs:
    raw_points = get_trajectory_points(df)
    simplified = np.array(douglas_peucker(raw_points, epsilon=5.0))
    simplified_trajectories.append(simplified)

# 提取简化轨迹的特征并聚类
feature_matrix = []
for simp_pts in simplified_trajectories:
    start = simp_pts[0]
    end = simp_pts[-1]
    total_length = np.sum(np.linalg.norm(simp_pts[1:] - simp_pts[:-1], axis=1))
    avg_angle = np.mean(np.arctan2(simp_pts[1:,1]-simp_pts[:-1,1], simp_pts[1:,0]-simp_pts[:-1,0]))
    feature_matrix.append(np.hstack([start, end, total_length, avg_angle, len(simp_pts)]))

kmeans = KMeans(n_clusters=3)
cluster_labels = kmeans.fit_predict(np.array(feature_matrix))

注意事项

  1. 如果轨迹包含时间信息,可以加入总时长、平均速度等时间特征,提升聚类准确性。
  2. 若坐标是经纬度,需先转换为平面坐标(比如UTM投影)再计算距离,避免球面距离带来的误差。
  3. DTW计算量较大,当轨迹数量超过100条时,建议先做特征降维,或使用近似DTW算法优化速度。

内容的提问来源于stack exchange,提问作者Magnus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 18:13:10