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

如何为DataFrame中各地点分配限定半径内的无重复最近关联地点

优化地点分配的Pandas代码实现

需求说明

  • 现有两个Pandas DataFrame:df1是目标地点列表(含城市+州、经纬度),df2是待分配地点数据集
  • 需将df2中的地点分配给df1中距离最近的地点,确保无重复分配
  • 设置最大半径阈值,超过阈值的地点直接排除

数据示例

df1(目标地点)

import pandas as pd

city_state = [
    ['Austin, Texas', 30.264265060424805, -97.74750518798828], 
    ['San Marcos, Texas', 29.882080, -97.939987], 
    ['Denver, Colorado', 39.7392364, -104.984862] 
]
df1 = pd.DataFrame(city_state, columns=['Location', 'Latitude', 'Longitude'])

df2(待分配地点)

data = [
    ['San Antonio, Texas', 29.425171, -98.494614],
    ['Oklahoma City, Oklahoma', 35.468491, -97.521263],
    ['Fort Collins, Colorado', 40.588970, -105.082458],
    ['Salt Lake City, Utah', 40.758480, -111.888138],
    ['Springfield, Massachusetts', 42.102051, -72.585762],
    ['Hartford, Connecticut', 41.764582, -72.6908547]
]
df2 = pd.DataFrame(data, columns=['Location', 'Latitude', 'Longitude'])

期望输出格式

{
    'Austin, Texas': [...], 
    'San Marcos, Texas': ['San Antonio, Texas', ...], 
    'Denver, Colorado': ['Fort Collins, Colorado', ...]
}

当前实现代码

from math import radians, sin, cos, sqrt, atan2

def calculate_distance(lat1, lon1, lat2, lon2):
    # 转换为弧度
    lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])

    # 哈弗辛公式
    dlat = lat2 - lat1
    dlon = lon2 - lon1
    a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
    c = 2 * atan2(sqrt(a), sqrt(1 - a))
    radius = 3958.8  # 地球半径(英里)
    distance = radius * c
    return distance

max_radius = 100

result = {}
closest_locations_x = {}
for _, city_row in df1.iterrows():
    city_name = city_row['Location']
    city_lat = float(city_row['Latitude'])
    city_lon = float(city_row['Longitude'])
    closest_locations = {}

    for _, location_row in df2.iterrows():
        if location_row['Latitude'] != 'Not Found' or location_row['Longitude'] != 'Not Found':
            location_name = location_row['Location']
            location_lat = float(location_row['Latitude'])
            location_lon = float(location_row['Longitude'])
            distance = calculate_distance(city_lat, city_lon, location_lat, location_lon)

            if distance <= max_radius:
                if location_name not in closest_locations_x:
                    closest_locations[location_name] = distance
                    closest_locations_x[location_name] = distance
                else:
                    if distance < closest_locations_x[location_name]:
                        result = {key: [value for value in values if value != location_name] for key, values in result.items()}
                        closest_locations[location_name] = distance
                        closest_locations_x[location_name] = distance

    result[city_name] = list(closest_locations.keys())

当前输出结果

{'Austin, Texas': [], 'San Marcos, Texas': ['San Antonio, Texas'], 'Denver, Colorado': ['Fort Collins, Colorado']}

优化方案

优化思路

  1. 抛弃嵌套循环,用Pandas向量化运算提升效率
  2. 先生成所有df2与df1地点的距离矩阵,再筛选符合半径要求的记录
  3. 通过排序+去重实现“最近且无重复分配”的核心逻辑

优化代码

import pandas as pd
from math import radians, sin, cos, sqrt, atan2

def haversine_distance(lat1, lon1, lat2, lon2):
    lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
    dlat = lat2 - lat1
    dlon = lon2 - lon1
    a = sin(dlat/2)**2 + cos(lat1)*cos(lat2)*sin(dlon/2)**2
    c = 2 * atan2(sqrt(a), sqrt(1-a))
    return 3958.8 * c  # 英里

max_radius = 100

# 生成所有df2与df1的地点组合
cross_df = df1.assign(key=1).merge(df2.assign(key=1), on='key').drop('key', axis=1)
# 计算每对地点的距离
cross_df['distance'] = haversine_distance(cross_df['Latitude_x'], cross_df['Longitude_x'], cross_df['Latitude_y'], cross_df['Longitude_y'])

# 筛选半径内的记录,按距离排序后保留每个df2地点的最近df1分配
valid_assignments = cross_df[cross_df['distance'] <= max_radius].sort_values('distance')
unique_assignments = valid_assignments.drop_duplicates(subset='Location_y', keep='first')

# 整理为目标字典格式
result = unique_assignments.groupby('Location_x')['Location_y'].apply(list).to_dict()
# 补充df1中未分配到地点的条目
for loc in df1['Location']:
    result.setdefault(loc, [])

print(result)

优化说明

  • 效率提升:向量化运算替代嵌套循环,处理大数据集时性能优势明显
  • 逻辑清晰:分步完成距离计算、筛选、去重、分组,代码可读性更强
  • 完整性保障:自动补全df1中无分配记录的地点,确保结果覆盖所有目标地点
  • 代码精简:利用Pandas内置方法替代冗余的字典操作,代码量大幅减少

优化后输出结果

{'Austin, Texas': [], 'San Marcos, Texas': ['San Antonio, Texas'], 'Denver, Colorado': ['Fort Collins, Colorado']}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 18:34:53