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

Python计算Excel两组经纬度最近位置时遇类型错误求助

问题:计算两组Excel位置数据的最近地点时遇到类型错误

运行代码时出现以下错误:

File "C:\Users\mohamed.h.mohamad\.spyder-py3\temp.py", line 19, in dist
    lat1, long1, lat2, long2 = map(radians, [lat1, long1, lat2, long2])

TypeError: must be real number, not str

已尝试将Lat和Long转为Float64类型但问题未解决,代码如下:

import pandas as pd
from math import radians, cos, sin, asin, sqrt
Sites = pd.read_excel("E:\Request/site.xlsx")
Sites.head()
Complaint = pd.read_excel("E:\Request/complaints.xlsx")
Complaint.head()
Sites['lat'].astype(dtype = 'float64')
Sites['long'].astype(dtype = 'float64')
Complaint['lat'].astype(dtype = 'float64')
Complaint['long'].astype(dtype = 'float64')
def dist(lat1, long1, lat2, long2):
    # convert decimal degrees to radians 
    lat1, long1, lat2, long2 = map(radians, [lat1, long1, lat2, long2])
    # haversine formula 
    dlon = long2 - long1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 
    # Radius of earth in kilometers is 6371
    km = 6371* c
    return km

def find_nearest(lat, long):
    distances = Sites.apply(
        lambda row: dist(lat, long, row['lat'], row['long']), 
        axis=1)
    return Sites.loc[distances.idxmin(), 'Site']
Complaint['Site'] = Complaint.apply(
    lambda row: find_nearest(row['lat'], row['long']), 
    axis=1)
# To check the data frame if it has a new column of hotel name (for each and every member's location in the list)
Complaint.head()
Complaint = pd.merge(Complaint,Sites[['Site','lat','lon']],on='Site', how='left')
# Rename the new columns as both the columns has same name, and python gets confused 
Complaint=Complaint.rename(columns = {'lat_x':'m_lat','lon_x':'m_lon','lat_y':'h_lat','lon_y':'h_lon'})
Complaint.head()

def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points 
    on the earth (specified in decimal degrees)
    """
    # convert decimal degrees to radians 
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
    # haversine formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 
    # Radius of earth in kilometers is 6371
    km = 6371* c
    return km
# Creating a new column to generate the output by passing lat long information to Haversine Equation
Complaint['distance'] = [haversine(Complaint.m_lon[i],Complaint.m_lat[i],Complaint.h_lon[i],Complaint.h_lat[i]) for i in range(len(Complaint))]
Complaint['distance'] = Complaint['distance'].round(decimals=3)
# Printing the data table 
Complaint.head()
Complaint.to_excel("output.xlsx")
解决方法

1. 修复类型转换问题

astype()方法不会原地修改DataFrame,必须将结果赋值回原列,否则原列数据类型仍为字符串:

# 替换原来的类型转换代码
Sites['lat'] = Sites['lat'].astype('float64')
Sites['long'] = Sites['long'].astype('float64')
Complaint['lat'] = Complaint['lat'].astype('float64')
Complaint['long'] = Complaint['long'].astype('float64')

如果数据中存在无法转换的非数值字符,可添加errors='coerce'将无效值转为NaN,方便后续处理:

Sites['lat'] = pd.to_numeric(Sites['lat'], errors='coerce')
Sites['long'] = pd.to_numeric(Sites['long'], errors='coerce')
Complaint['lat'] = pd.to_numeric(Complaint['lat'], errors='coerce')
Complaint['long'] = pd.to_numeric(Complaint['long'], errors='coerce')

2. 修复列名不一致问题

合并数据时,Sites表中使用的列是long,但合并代码里写的是lon,这会导致合并后h_lon全为NaN,需要统一列名:

# 修改合并代码,匹配Sites表的列名
Complaint = pd.merge(Complaint,Sites[['Site','lat','long']],on='Site', how='left')
# 对应修改重命名代码
Complaint=Complaint.rename(columns = {'lat_x':'m_lat','long_x':'m_lon','lat_y':'h_lat','long_y':'h_lon'})

3. 优化距离计算效率

原代码用循环计算haversine距离效率较低,可改用pandas的向量化操作:

# 替换循环计算的代码
Complaint['distance'] = haversine(Complaint['m_lon'], Complaint['m_lat'], Complaint['h_lon'], Complaint['h_lat'])
Complaint['distance'] = Complaint['distance'].round(decimals=3)

同时确保haversine函数支持向量化输入(math模块函数不支持,可改用numpy实现):

import numpy as np

def haversine(lon1, lat1, lon2, lat2):
    # 转换为弧度
    lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])
    # 半正矢公式
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = np.sin(dlat/2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2)**2
    c = 2 * np.arcsin(np.sqrt(a)) 
    km = 6371 * c
    return km

4. 处理缺失值

转换类型后若存在NaN,可根据需求删除或填充:

# 删除包含缺失值的行
Sites = Sites.dropna(subset=['lat', 'long'])
Complaint = Complaint.dropna(subset=['lat', 'long'])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 11:23:09