pandas计算两个经纬度距离,数据量太大了,上亿行,有没有高效的算法?

问题遇到的现象和发生背景

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))

img

img

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)

https://blog.csdn.net/weixin_32759777/article/details/122449972?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164497965016780261955496%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=164497965016780261955496&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-122449972.nonecase&utm_term=%E7%BB%8F%E7%BA%AC%E5%BA%A6&spm=1018.2226.3001.4450

矩阵运算效率高,matlab矩阵运算

如果是已知一点计算最近的另外一点距离可以优化,像你问的一点到任意一点的距离是没法优化的。图论里面计算最短路最快的算法也才nlogn,你这上亿级数据,谁来都不好使。

最简单的就是勾股定理,a^2+b^2=c^2