并行处理 - 使用 pysal python 进行最近邻搜索?
parallel processing - nearest neighbour search using pysal python?
我有这个数据框 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 大小。
应该可以将你的最后一段代码并行化为这样的东西:
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)
但要小心,因为 multiprocessing
库 pickles
所有数据都在往返于工作人员的途中,这可能会增加数据密集型任务的大量开销,可能会取消由于并行处理而节省的费用。
我看不出你从哪里得到内存不足的错误。 800 万条记录对于 pandas 来说并不算多。也许如果您的搜索每行产生数百个匹配项,那可能是个问题。如果你再多说一点,我也许能给你更多的建议。
听起来 pysal 执行此操作可能花费的时间比必要的时间更长。您可以通过使用 GeoPandas 或 "rolling your own" 解决方案来获得更好的性能,如下所示:
- 将每个点分配给周围 1 公里的网格单元(例如,计算 UTM 坐标
x
和 y
,然后创建列 cx=x//1000
和 cy=y//1000
);
- 在网格单元格坐标
cx
和 cy
上创建索引(例如,df=df.set_index(['cx', 'cy'])
);
- 对于每个点,找出周围9个单元格中的点;您可以通过
df.loc[[(cx-1,cy-1),(cx-1,cy),(cx-1,cy+1),(cx,cy-1),...(cx+1,cy+1)], :]
直接从索引中 select 这些内容;
- 过滤您刚刚 select 的点以找到 1 公里以内的点。
我有这个数据框 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 大小。
应该可以将你的最后一段代码并行化为这样的东西:
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)
但要小心,因为 multiprocessing
库 pickles
所有数据都在往返于工作人员的途中,这可能会增加数据密集型任务的大量开销,可能会取消由于并行处理而节省的费用。
我看不出你从哪里得到内存不足的错误。 800 万条记录对于 pandas 来说并不算多。也许如果您的搜索每行产生数百个匹配项,那可能是个问题。如果你再多说一点,我也许能给你更多的建议。
听起来 pysal 执行此操作可能花费的时间比必要的时间更长。您可以通过使用 GeoPandas 或 "rolling your own" 解决方案来获得更好的性能,如下所示:
- 将每个点分配给周围 1 公里的网格单元(例如,计算 UTM 坐标
x
和y
,然后创建列cx=x//1000
和cy=y//1000
); - 在网格单元格坐标
cx
和cy
上创建索引(例如,df=df.set_index(['cx', 'cy'])
); - 对于每个点,找出周围9个单元格中的点;您可以通过
df.loc[[(cx-1,cy-1),(cx-1,cy),(cx-1,cy+1),(cx,cy-1),...(cx+1,cy+1)], :]
直接从索引中 select 这些内容; - 过滤您刚刚 select 的点以找到 1 公里以内的点。