并行处理 - 使用pysal python进行最近邻搜索?

时间:2017-09-27 04:19:58

标签: python python-2.7 multiprocessing python-multiprocessing pysal

我有这个数据框df1,

          id      lat_long
400743  2504043 (175.0976323, -41.1141412)
43203   1533418 (173.976683, -35.2235338)
463952  3805508 (174.6947496, -36.7437555)
1054906 3144009 (168.0105269, -46.36193)
214474  3030933 (174.6311167, -36.867717)
1008802 2814248 (169.3183615, -45.1859095)
988706  3245376 (171.2338968, -44.3884099)
492345  3085310 (174.740957, -36.8893026)
416106  3794301 (174.0106383, -35.3876921)
937313  3114127 (174.8436185, -37.80499)

我在这里构建了搜索树,

def construct_geopoints(s):
    data_geopoints = [tuple(x) for x in s[['longitude','latitude']].to_records(index=False)]
    tree = KDTree(data_geopoints, distance_metric='Arc', radius=pysal.cg.RADIUS_EARTH_KM)
    return tree

tree = construct_geopoints(actualdata)

现在,我正在尝试搜索数据框df1中每个地理位置1KM范围内的所有地理点。这就是我的工作方式,

dfs = []
for name,group in df1.groupby(np.arange(len(df1))//10000):
    s = group.reset_index(drop=True).copy()
    pts = list(s['lat_long'])
    neighbours = tree.query_ball_point(pts, 1)
    s['neighbours'] = pd.Series(neighbours)
    dfs.append(s)

output = pd.concat(dfs,axis = 0)

这里的一切都运行正常,但我试图将此任务并行化,因为我的df1大小为2M记录,此过程运行超过8小时。谁可以帮我这个事?另一件事是,query_ball_point返回的结果是一个列表,因此当我处理大量记录时,它会抛出内存错误。任何方式来处理这个。

编辑: - 内存问题,请查看VIRT大小。

enter image description here

1 个答案:

答案 0 :(得分:1)

应该可以将最后一段代码并行化,如下所示:

from multiprocessing import Pool
...

def process_group(group):
    s = group[1].reset_index(drop=True)  # .copy() is implicit
    pts = list(s['lat_long'])
    neighbours = tree.query_ball_point(pts, 1)
    s['neighbours'] = pd.Series(neighbours)
    return s

groups = df1.groupby(np.arange(len(df1))//10000)

p = Pool(5)
dfs = p.map(process_group, groups)

output = pd.concat(dfs, axis=0)

但请注意,因为multiprocessingpickles所有来往工作人员的数据,这可能会增加大量数据密集型任务的开销,可能会取消节省的成本由于并行处理。

我无法查看您从哪里获得内存不足错误。对于大熊猫来说,800万条记录并不多。也许如果你的搜索每行产生数百个匹配可能是个问题。如果你说更多关于我的话,我可能会给你更多的建议。

听起来pysal可能花费的时间超过了必要的时间。您可以使用GeoPandas或"滚动自己的"来提高性能。像这样的解决方案:

  1. 将每个点分配给周围1 km的网格单元格(例如,计算UTM坐标xy,然后创建列cx=x//1000cy=y//1000);
  2. 在网格单元格坐标cxcy上创建索引(例如df=df.set_index(['cx', 'cy']));
  3. 对于每个点,找到9个周围单元格中的点;您可以通过df.loc[[(cx-1,cy-1),(cx-1,cy),(cx-1,cy+1),(cx,cy-1),...(cx+1,cy+1)], :]直接从索引中选择这些;
  4. 过滤您刚刚选择的点,以找到1公里范围内的点。
相关问题