基于Pandas的人员邻近位置聚类分组技术问询
问题需求
现有包含latitude、longitude、story字段的Pandas DataFrame,需将其拆分为每组9行的子数据集(chunk),需满足以下要求:
- 每组中不得包含
latitude和longitude完全相同的行(代表同一建筑人员) - 组内人员的
latitude和longitude需相近(邻近区域),可通过最近邻算法定义邻近关系 - 最终将所有chunk合并为完整DataFrame
示例数据
# 修正语法错误后的原始数据 data = { "latitude": [49.5619579, 49.5619579, 49.5628938, 49.5628938, 49.5630028, 49.5633175, 49.56397639999999, 49.5659508, 49.566359, 49.56643220000001, 49.56643220000001, 49.5672061, 49.567729, 49.5677449, 49.5679685, 49.5679685, 49.568089, 49.5686342, 49.5687609, 49.5688543, 49.5690616, 49.5695834, 49.5706579, 49.5711228, 49.5713705, 49.5716422, 49.5717749], "longitude": [10.9995758, 10.9995758, 11.000319, 11.000319, 10.9990996, 10.9993819, 11.004145, 10.9873409, 11.0003023, 10.9999593, 10.9999593, 10.9935709, 11.0011213, 10.9954016, 10.9982288, 10.9982288, 10.9894035, 10.9896749, 10.9887881, 10.9975928, 10.9931367, 10.9851579, 10.9853273, 10.9912959, 10.9939141, 10.9910182, 10.9867083], "story": [2.0, 4.0, 3.0, 4.0, 1.0, 2.0, 3.0, 1.0, 3.0, 1.0, 5.0, 1.0, 1.0, 1.0, 1.0, 5.0, 5.0, 1.0, 3.0, 2.0, 3.0, 2.0, 2.0, 4.0, 4.0, 5.0, 5.0] }
数据集前9行示例
MasterKitchen_Latitude MasterKitchen_Longitude MasterKitchen_Story 0 49.561958 10.999576 2.0 1 49.561958 10.999576 4.0 2 49.562894 11.000319 3.0 3 49.562894 11.000319 4.0 4 49.563003 10.999100 1.0 5 49.563317 10.999382 2.0 6 49.563976 11.004145 3.0 7 49.565951 10.987341 1.0 8 49.566359 11.000302 3.0
讨论阶段代码
df = pd.DataFrame(data) # 创建合并经纬度的字符串列 df["lat_long"] = df["latitude"].astype(str) + "_" + df["longitude"].astype(str) # 按合并列分组 grouped_df = df.groupby("lat_long") print(grouped_df.mean())
解决方案
以下是满足需求的完整实现步骤:
1. 预处理:标记唯一人员
为每个唯一的经纬度组合分配ID,区分不同建筑人员,同时保留所有原始行数据:
import pandas as pd import numpy as np from sklearn.neighbors import NearestNeighbors # 加载数据 df = pd.DataFrame(data) # 生成人员ID:每个经纬度组合对应唯一ID df['person_id'] = df.groupby(['latitude', 'longitude']).ngroup()
2. 提取唯一人员的坐标集合
创建仅包含唯一人员经纬度的数据集,用于后续最近邻计算:
# 提取唯一人员的信息 unique_persons = df[['person_id', 'latitude', 'longitude']].drop_duplicates().reset_index(drop=True) # 转换为numpy数组,用于模型输入 coords = unique_persons[['latitude', 'longitude']].values
3. 基于最近邻构建分组
使用Haversine距离(适用于经纬度坐标的距离计算)的K近邻算法,构建符合要求的chunk:
# 初始化K近邻模型,设置每组最多9个人员 nn = NearestNeighbors(n_neighbors=9, metric='haversine') # 经纬度需转换为弧度后输入模型 nn.fit(np.radians(coords)) chunks = [] # 记录已分配到chunk的人员ID,避免重复分配 assigned_persons = set() # 遍历每个唯一人员,构建邻近分组 for idx in range(len(unique_persons)): current_person_id = unique_persons.loc[idx, 'person_id'] if current_person_id in assigned_persons: continue # 获取当前人员的9个最近邻(包含自身) _, neighbor_indices = nn.kneighbors([np.radians(coords[idx])]) # 提取邻近人员的ID neighbor_person_ids = unique_persons.loc[neighbor_indices[0], 'person_id'].tolist() # 过滤掉已分配的人员 available_ids = [pid for pid in neighbor_person_ids if pid not in assigned_persons] # 选取最多9个可用人员,生成当前chunk selected_ids = available_ids[:9] chunk = df[df['person_id'].isin(selected_ids)] chunks.append(chunk) # 更新已分配人员集合 assigned_persons.update(selected_ids) # 处理剩余未分配的人员(不足9个的情况) remaining_ids = [pid for pid in unique_persons['person_id'] if pid not in assigned_persons] if remaining_ids: chunks.append(df[df['person_id'].isin(remaining_ids)]) # 合并所有chunk,得到最终的完整DataFrame final_df = pd.concat(chunks, ignore_index=True)
4. 验证分组有效性
可以通过以下代码检查每个chunk是否符合“无重复经纬度行”的要求:
for i, chunk in enumerate(chunks, 1): duplicate_count = chunk.duplicated(subset=['latitude', 'longitude']).sum() print(f"Chunk {i}: 重复经纬度行数 = {duplicate_count}, 总行数 = {len(chunk)}")
内容的提问来源于stack exchange,提问作者PParker
相关产品推荐
相关产品推荐

