pandas计算两个经纬度距离,用了网上能找到的方法,运行半天都没见进度
lon1, lat1, lon2, lat2 = map(np.radians, tt.tolist())
# haversine公式
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 * a * np.sin(np.sqrt(a))
r = 6371
c * r * 1000
运行时间太长了
暂无
高效率算法
既然已经已经用了能用的方法还不能降低运算时间,已经不是算法优化的问题了,那么你的问题是机器运算性能不够。
如果电脑的显卡还不错建议使用minpy加速运算,如果电脑显卡不怎么样或者没有独立显卡,建议申请算力进行。
注:python在运算速度上可能没有C/C++快,你可以换一种语言试试看。
这种相当大的数据可以考虑多线程,并行计算,考虑matlab语言进行处理,matlab的矩阵运算相当快,不过考虑到你的数据量有点大,建议到大一点的内存的电脑上运行。
读题主的代码,感觉题主的问题和pandas无关,应该是numpy的应用问题,而题主似乎没有使用numpy的矢量化运算。写了段测试代码,测试数据少于2千万条,速度较快,超过2千万时,明显变慢,1亿条数据耗时大约72秒。如果采用多进程,进程间合并计算结果有点麻烦,因此我建议题主可以在一个进程内分多组计算,每组不超过2千万数据,合并计算结果相对简单。
import time
import numpy as np
def create_test_data(n):
"""生成n组测试数据"""
lon1 = np.radians(np.random.random(n) * 360 - 180)
lon2 = np.radians(np.random.random(n) * 360 - 180)
lat1 = np.radians(np.random.random(n) * 180 - 90)
lat2 = np.radians(np.random.random(n) * 180 - 90)
return lon1, lat1, lon2, lat2
def calculate(lon1, lat1, lon2, lat2):
"""计算距离"""
dlon, dlat = lon2-lon1, lat2-lat1
a = np.power(np.sin(dlat/2), 2) + np.cos(lat1) * np.cos(lat2) * np.power(np.sin(dlon/2), 2)
return 2 * a * np.sin(np.sqrt(a)) * 6371 * 1000
if __name__ == '__main__':
n = 100_000_000
t0 = time.time()
lon1, lat1, lon2, lat2 = create_test_data(n)
t1 = time.time()
print('生成%d组测试数据耗时%0.3f秒'%(n, t1-t0))
#t0 = time.time()
#result = calculate(lon1, lat1, lon2, lat2)
#t1 = time.time()
#print('一次计算%d组测试数据耗时%0.3f秒'%(n, t1-t0))
t0 = time.time()
result = list()
for i in range(10):
print(i)
a, b = i*10_000_000, (i+1)*10_000_000
result.append(calculate(lon1[a:b], lat1[a:b], lon2[a:b], lat2[a:b]))
result = np.hstack(result)
t1 = time.time()
print('分10次计算%d组测试数据耗时%0.3f秒'%(n, t1-t0))
numba,你值得拥有, 千万级只要2秒
from numba import jit
@jit(nopython=True) # jit,numba装饰器中的一种
def foo():
for i in range(10000000):
lon1, lat1, lon2, lat2 = map(np.radians, [1, 2, 3, 4])
# haversine公式
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 * a * np.sin(np.sqrt(a))
r = 6371
res = c * r * 1000
在你资源有限的情况下,提供给你思路:
提示:当你用循环处理时,使用pandas内置模块apply,不用for,以内apply的效率会更高
当计算量大于1000万怎么办?
偶然间想起了之前自己将csv文件分割的文章,当计算量大于1000万,我们对原表进行分割,分割个数就是计算量/10000000,不能整除时,需要先上取整,多分割一个文件
pieces = ceil(count_a * count_b / 10000000) # 计算量上限为1000万
分割数目有了,文件分片大小也就有了
linesPerFile = ceil(count_a / pieces)+1
文件分割代码:
filecount = 1
# 以0为起点,文件行数为终点,分片大小为间隔,循环遍历文件,每次遍历行数即为分片大小,而不是每行遍历一次,处理效率极高,但是比较吃内存
for i in range(0, len(csv_file), linesPerFile):
# 打开目标文件准备写入,不存在则创建
with open(file_name[:-4] + '_' + str(filecount) + '.csv', 'w+') as f:
# 判断是否为第一个文件,不是的话需要先写入标题行
if filecount > 1:
f.write(csv_file[0])
# 批量写入i至i+分片大小的多行数据,效率极高
f.writelines(csv_file[i:i+linesPerFile])
# 完成一个文件写入之后,文件编号增加1
filecount += 1
将文件分割之后,我们便可以循环处理分片文件与目标文件,将得到的结果合并到一个空的Dataframe里
distance =pd.DataFrame(columns=('name','lon','lat','name2', 'lon2', 'lat2', 'distance'))
#创建空dataframe
for i in range(1,filecount):
df_temp = pd.read_csv(file_name[:-4] + '_' + str(i) + '.csv')
#循环读取分割文件
m = pd.concat([pd.concat([df_temp]*len(df2)).sort_index().reset_index(drop=True),
pd.concat([df2]*len(df_temp)).reset_index(drop=True) ], 1)
n=m[abs(m.lon-m.lon2)<diff_lon][abs(m.lat-m.lat2)<diff_lat]
n['distance']=n.apply(lambda ser: geodistance(ser['lon'], ser['lat'], ser['lon2'], ser['lat2']),axis=1)
# nx=n n['distance']
distance=distance.append(n[n.distance <= minx_mile])
result.to_csv('D:/python/geo/result4.csv')
endtime=time.time()
cost_time = endtime - starttime
print('处理完成,程序运行时间: {}秒'.format(float('%.2f' % cost_time)
矩阵运算效率高,matlab矩阵运算
如果是已知一点计算最近的另外一点距离可以优化,像你问的一点到任意一点的距离是没法优化的。图论里面计算最短路最快的算法也才nlogn,你这上亿级数据,谁来都不好使。
最简单的就是勾股定理,a^2+b^2=c^2