我有一个很大的(O(10 ^ 6)行)数据集(带有值的点),在这里我需要对所有点进行以下操作:
“非矢量化”方法是简单地循环所有点...针对所有点,然后应用逻辑。但是,伸缩性很差。
我提供了一个玩具示例,可以满足我的要求。我已经考虑过的想法有:
这是我要实现的逻辑的一个玩具示例:
import pandas as pd
import numpy as np
from shapely.wkt import loads
import geopandas as gp
points=[
'POINT (1 1.1)', 'POINT (1 1.9)', 'POINT (1 3.1)',
'POINT (2 1)', 'POINT (2 2.1)', 'POINT (2 2.9)',
'POINT (3 0.8)', 'POINT (3 2)', 'POINT (3 3)'
]
values=[9,8,7,6,5,4,3,2,1]
df=pd.DataFrame({'points':points,'values':values})
gdf=gp.GeoDataFrame(df,geometry=[loads(x) for x in df.points], crs={'init': 'epsg:' + str(25832)})
for index,row in gdf.iterrows(): # Looping over all points
gdf['dist'] = np.nan
for index2,row2 in gdf.iterrows(): # Looping over all the other points
if index==index2: continue
d=row['geometry'].distance(row2['geometry']) # Calculate distance
if d<3: gdf.at[index2,'dist']=d # If within cutoff: Store
else: gdf.at[index2,'dist']=np.nan # Otherwise, be paranoid and leave NAN
# Calculating mean of values for the 3 nearest points and storing
gdf.at[index,'mean']=np.mean(gdf.sort_values('dist').head(3)['values'].tolist())
print(gdf)
生成的GeoDataframe在这里:
points values geometry dist mean
0 POINT (1 1.1) 9 POINT (1 1.1) 2.758623 6.333333
1 POINT (1 1.9) 8 POINT (1 1.9) 2.282542 7.000000
2 POINT (1 3.1) 7 POINT (1 3.1) 2.002498 5.666667
3 POINT (2 1) 6 POINT (2 1) 2.236068 5.666667
4 POINT (2 2.1) 5 POINT (2 2.1) 1.345362 4.666667
5 POINT (2 2.9) 4 POINT (2 2.9) 1.004988 4.333333
6 POINT (3 0.8) 3 POINT (3 0.8) 2.200000 4.333333
7 POINT (3 2) 2 POINT (3 2) 1.000000 3.000000
8 POINT (3 3) 1 POINT (3 3) NaN 3.666667
您可以看到上一次迭代的状态。
我该如何以更可扩展的方式做到这一点?
答案 0 :(得分:1)
我会为此使用空间索引。您可以使用libpysal
的功能,该功能在后台使用KDTree。对于2000个随机点,与您的代码相比,以下代码运行了3.5 s,而且运行了很长时间(我在第一分钟后就失去了耐心)。将值保存到列表中,然后将列表转换为DF列也可以节省一些时间。
import pandas as pd
import numpy as np
from shapely.wkt import loads
import geopandas as gp
import libpysal
points=[
'POINT (1 1.1)', 'POINT (1 1.9)', 'POINT (1 3.1)',
'POINT (2 1)', 'POINT (2 2.1)', 'POINT (2 2.9)',
'POINT (3 0.8)', 'POINT (3 2)', 'POINT (3 3)'
]
values=[9,8,7,6,5,4,3,2,1]
df=pd.DataFrame({'points':points,'values':values})
gdf=gp.GeoDataFrame(df,geometry=[loads(x) for x in df.points], crs={'init': 'epsg:' + str(25832)})
knn3 = libpysal.weights.KNN.from_dataframe(gdf, k=3)
means = []
for index, row in gdf.iterrows(): # Looping over all points
knn_neighbors = knn3.neighbors[index]
knnsubset = gdf.iloc[knn_neighbors]
neighbors = []
for ix, r in knnsubset.iterrows():
if r.geometry.distance(row.geometry) < 3: # max distance here
neighbors.append(ix)
subset = gdf.iloc[list(neighbors)]
means.append(np.mean(subset['values']))
gdf['mean'] = means
这是结果:
points values geometry mean
0 POINT (1 1.1) 9 POINT (1 1.1) 6.333333
1 POINT (1 1.9) 8 POINT (1 1.9) 7.000000
2 POINT (1 3.1) 7 POINT (1 3.1) 5.666667
3 POINT (2 1) 6 POINT (2 1) 5.666667
4 POINT (2 2.1) 5 POINT (2 2.1) 4.666667
5 POINT (2 2.9) 4 POINT (2 2.9) 4.333333
6 POINT (3 0.8) 3 POINT (3 0.8) 4.333333
7 POINT (3 2) 2 POINT (3 2) 3.000000
8 POINT (3 3) 1 POINT (3 3) 3.666667
答案 1 :(得分:0)
这使我想起了我上大学时遇到的数学问题。它与Chapter 7 Example 7密切相关。因此,问题是
请考虑某个城镇中的一组移动计算客户端,每个客户端 需要连接到几个可能的基站之一。好 假设有n个客户,每个客户的位置 由其在平面中的(x,y)坐标指定。也有k 基站;每个位置由(x,y)指定 坐标。对于每个客户,我们希望将其准确地连接到 基站之一。我们对连接的选择受到限制 可以通过以下方式进行操作:有一个范围参数r,客户可以 只能连接到距离r以内的基站。那里 也是负载参数L,因此最多只能有L个客户端 连接到任何单个基站。您的目标是设计一个 多项式时间算法可解决以下问题。鉴于 一组客户端和一组基站的位置,以及 范围和负载参数,确定是否每个客户端都可以 同时连接到基站,取决于范围和 上一段中的负载条件。
我相信您可以在多项式时间内将此问题转换为网络流问题,然后假设您仅在O(n * m + cmax)时间内使用修改的ford-fulkerson算法来解决您要寻找的问题向福特富尔克森添加恒定时间操作。这可能不是一个可扩展的问题,可能会出现在多项式时间问题列表中,但这也许比持续运行O(n ^ 2)运行时间更好。
有关如何将其转换为网络流量问题的信息,我将尝试阅读此人的pseudoish code。 pdf密码为鸟