这是我的第一个地理数据帧:
!pip install geopandas
import pandas as pd
import geopandas
city1 = [{'City':"Buenos Aires","Country":"Argentina","Latitude":-34.58,"Longitude":-58.66},
{'City':"Brasilia","Country":"Brazil","Latitude":-15.78 ,"Longitude":-70.66},
{'City':"Santiago","Country":"Chile ","Latitude":-33.45 ,"Longitude":-70.66 }]
city2 = [{'City':"Bogota","Country":"Colombia ","Latitude":4.60 ,"Longitude":-74.08},
{'City':"Caracas","Country":"Venezuela","Latitude":10.48 ,"Longitude":-66.86}]
city1df = pd.DataFrame(city1)
city2df = pd.DataFrame(city2)
gcity1df = geopandas.GeoDataFrame(
city1df, geometry=geopandas.points_from_xy(city1df.Longitude, city1df.Latitude))
gcity2df = geopandas.GeoDataFrame(
city2df, geometry=geopandas.points_from_xy(city2df.Longitude, city2df.Latitude))
城市1
City Country Latitude Longitude geometry
0 Buenos Aires Argentina -34.58 -58.66 POINT (-58.66000 -34.58000)
1 Brasilia Brazil -15.78 -47.91 POINT (-47.91000 -15.78000)
2 Santiago Chile -33.45 -70.66 POINT (-70.66000 -33.45000)
还有我的第二个地理数据框:City2:
City Country Latitude Longitude geometry
1 Bogota Colombia 4.60 -74.08 POINT (-74.08000 4.60000)
2 Caracas Venezuela 10.48 -66.86 POINT (-66.86000 10.48000)
我想第三个数据帧与最近的城市从城市1到城市2的距离像:
City Country Latitude Longitude geometry Nearest Distance
0 Buenos Aires Argentina -34.58 -58.66 POINT (-58.66000 -34.58000) Bogota 111 Km
下面是我使用geodjango和dict的实际解决方案(但太长了):
from django.contrib.gis.geos import GEOSGeometry
result = []
dict_result = {}
for city01 in city1 :
dist = 99999999
pnt = GEOSGeometry('SRID=4326;POINT( '+str(city01["Latitude"])+' '+str(city01['Longitude'])+')')
for city02 in city2:
pnt2 = GEOSGeometry('SRID=4326;POINT('+str(city02['Latitude'])+' '+str(city02['Longitude'])+')')
distance_test = pnt.distance(pnt2) * 100
if distance_test < dist :
dist = distance_test
result.append(dist)
dict_result[city01['City']] = city02['City']
以下是我的尝试:
from shapely.ops import nearest_points
# unary union of the gpd2 geomtries
pts3 = gcity2df.geometry.unary_union
def Euclidean_Dist(df1, df2, cols=['x_coord','y_coord']):
return np.linalg.norm(df1[cols].values - df2[cols].values,
axis=1)
def near(point, pts=pts3):
# find the nearest point and return the corresponding Place value
nearest = gcity2df.geometry == nearest_points(point, pts)[1]
return gcity2df[nearest].City
gcity1df['Nearest'] = gcity1df.apply(lambda row: near(row.geometry), axis=1)
gcity1df
这里:
City Country Latitude Longitude geometry Nearest
0 Buenos Aires Argentina -34.58 -58.66 POINT (-58.66000 -34.58000) Bogota
1 Brasilia Brazil -15.78 -70.66 POINT (-70.66000 -15.78000) Bogota
2 Santiago Chile -33.45 -70.66 POINT (-70.66000 -33.45000) Bogota
问候
这个解决方案可能不是解决问题的最快方法,但我相信它会奏效。
#New dataframe is basicly a copy of first but with more columns
gcity3df = gcity1df.copy()
gcity3df["Nearest"] = None
gcity3df["Distance"] = None
#For each city (row in gcity3df) we will calculate the nearest city from gcity2df and
fill the Nones with results
for index, row in gcity3df.iterrows():
#Setting neareast and distance to None,
#we will be filling those variables with results
nearest = None
distance = None
for df2index, df2row in gcity2df.iterrows():
d = row.geometry.distance(df2row.geometry)
#If df2index city is closer than previous ones, replace nearest with it
if distance is None or d < distance:
distance = d
nearest = df2row.City
#In the end we appends the closest city to gdf
gcity3df.at[index, "Nearest"] = nearest
gcity3df.at[index, "Distance"] = distance
如果你需要在米上工作,而不是在度上工作,你可以随时重新投影你的图层(这也会消除沃尔特所指的错误)。您可以通过gcity3df=gcity3df来完成。to_crs({'init':'epsg:XXXX'})
其中XXXX是您所在地区正在使用的crs的epsg代码。
我认为很难找到一个时间复杂度比O(m·n)更好的解决方案,其中m和n是city1
和city2
的大小。保持距离比较(唯一的O(m·n)操作)简单,并利用numpy和pandas提供的矢量化操作,对于任何合理的输入大小,速度都不应该是问题。
其思想是,要比较球体上的距离,可以比较3D中各点之间的距离。最近的城市也是穿过球体最近的城市。此外,通常使用平方根计算距离,但如果只需要比较它们,则可以避免使用平方根。
from geopy.distance import distance as dist
import numpy as np
import pandas as pd
def find_closest(lat1, lng1, lat2, lng2):
def x_y_z_of_lat_lng_on_unit_sphere(lat, lng):
rad_lat, rad_lng = np.radians(lat), np.radians(lng)
sin_lat, sin_lng = np.sin(rad_lat), np.sin(rad_lng)
cos_lat, cos_lng = np.cos(rad_lat), np.cos(rad_lng)
return cos_lat * cos_lng, cos_lat * sin_lng, sin_lat
x1, y1, z1 = x_y_z_of_lat_lng_on_unit_sphere(lat1, lng1)
x2, y2, z2 = x_y_z_of_lat_lng_on_unit_sphere(lat2, lng2)
return pd.Series(map(lambda x, y, z:
((x2-x)**2 + (y2-y)**2 + (z2-z)**2).idxmin(),
x1, y1, z1))
city1 = [{"City":"Tokyo", "Ctry":"JP", "Latitude": 35.68972, "Longitude": 139.69222},
{"City":"Pretoria", "Ctry":"ZA", "Latitude":-25.71667, "Longitude": 28.28333},
{"City":"London", "Ctry":"GB", "Latitude": 51.50722, "Longitude": -0.12574}]
city2 = [{"City":"Seattle", "Ctry":"US", "Latitude": 47.60972, "Longitude":-122.33306},
{"City":"Auckland", "Ctry":"NZ", "Latitude":-36.84446, "Longitude": 174.76364}]
city1df = pd.DataFrame(city1)
city2df = pd.DataFrame(city2)
closest = find_closest(city1df.Latitude, city1df.Longitude, city2df.Latitude, city2df.Longitude)
resultdf = city1df.join(city2df, on=closest, rsuffix='2')
km = pd.Series(map(lambda latlng1, latlng2: round(dist(latlng1, latlng2).km),
resultdf[['Latitude', 'Longitude' ]].to_numpy(),
resultdf[['Latitude2', 'Longitude2']].to_numpy()))
resultdf['Distance'] = km
print(resultdf.to_string())
# City Ctry Latitude Longitude City2 Ctry2 Latitude2 Longitude2 Distance
# 0 Tokyo JP 35.68972 139.69222 Seattle US 47.60972 -122.33306 7715
# 1 Pretoria ZA -25.71667 28.28333 Auckland NZ -36.84446 174.76364 12245
# 2 London GB 51.50722 -0.12574 Seattle US 47.60972 -122.33306 7723
请注意,任何将纬度和经度当作笛卡尔坐标使用的解决方案都是错误的,因为朝着极点移动的子午线(等经度线)彼此更接近。
首先,通过交叉连接合并两个数据帧。然后,我在python中使用map
找到两点之间的距离。我使用map
,因为大多数时候它比apply
、itertuples
、iterrows
等要快得多(参考:https://stackoverflow.com/a/52674448/8205554)
最后,我按数据帧分组并获取距离的最小值。
这里有图书馆,
import pandas as pd
import geopandas
import geopy.distance
from math import radians, cos, sin, asin, sqrt
这里是使用的函数,
def dist1(p1, p2):
lon1, lat1, lon2, lat2 = map(radians, [p1.x, p1.y, p2.x, p2.y])
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
return c * 6373
def dist2(p1, p2):
lon1, lat1, lon2, lat2 = map(radians, [p1[0], p1[1], p2[0], p2[1]])
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
return c * 6373
def dist3(p1, p2):
x = p1.y, p1.x
y = p2.y, p2.x
return geopy.distance.geodesic(x, y).km
def dist4(p1, p2):
x = p1[1], p1[0]
y = p2[1], p2[0]
return geopy.distance.geodesic(x, y).km
和数据,
city1 = [
{
'City': 'Buenos Aires',
'Country': 'Argentina',
'Latitude': -34.58,
'Longitude': -58.66
},
{
'City': 'Brasilia',
'Country': 'Brazil',
'Latitude': -15.78,
'Longitude': -70.66
},
{
'City': 'Santiago',
'Country': 'Chile ',
'Latitude': -33.45,
'Longitude': -70.66
}
]
city2 = [
{
'City': 'Bogota',
'Country': 'Colombia ',
'Latitude': 4.6,
'Longitude': -74.08
},
{
'City': 'Caracas',
'Country': 'Venezuela',
'Latitude': 10.48,
'Longitude': -66.86
}
]
city1df = pd.DataFrame(city1)
city2df = pd.DataFrame(city2)
与geopandas
数据帧交叉连接,
gcity1df = geopandas.GeoDataFrame(
city1df,
geometry=geopandas.points_from_xy(city1df.Longitude, city1df.Latitude)
)
gcity2df = geopandas.GeoDataFrame(
city2df,
geometry=geopandas.points_from_xy(city2df.Longitude, city2df.Latitude)
)
# cross join geopandas
gcity1df['key'] = 1
gcity2df['key'] = 1
merged = gcity1df.merge(gcity2df, on='key')
数学
函数和geopandas
,
# 6.64 ms ± 588 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
# find distance
merged['dist'] = list(map(dist1, merged['geometry_x'], merged['geometry_y']))
mapping = {
'City_x': 'City',
'Country_x': 'Country',
'Latitude_x': 'Latitude',
'Longitude_x': 'Longitude',
'geometry_x': 'geometry',
'City_y': 'Nearest',
'dist': 'Distance'
}
nearest = merged.loc[merged.groupby(['City_x', 'Country_x'])['dist'].idxmin()]
nearest.rename(columns=mapping)[list(mapping.values())]
City Country Latitude Longitude geometry \
2 Brasilia Brazil -15.78 -70.66 POINT (-70.66000 -15.78000)
0 Buenos Aires Argentina -34.58 -58.66 POINT (-58.66000 -34.58000)
4 Santiago Chile -33.45 -70.66 POINT (-70.66000 -33.45000)
Nearest Distance
2 Bogota 2297.922808
0 Bogota 4648.004515
4 Bogota 4247.586882
geopy
和geopandas
,
# 9.99 ms ± 764 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
# find distance
merged['dist'] = list(map(dist3, merged['geometry_x'], merged['geometry_y']))
mapping = {
'City_x': 'City',
'Country_x': 'Country',
'Latitude_x': 'Latitude',
'Longitude_x': 'Longitude',
'geometry_x': 'geometry',
'City_y': 'Nearest',
'dist': 'Distance'
}
nearest = merged.loc[merged.groupby(['City_x', 'Country_x'])['dist'].idxmin()]
nearest.rename(columns=mapping)[list(mapping.values())]
City Country Latitude Longitude geometry \
2 Brasilia Brazil -15.78 -70.66 POINT (-70.66000 -15.78000)
0 Buenos Aires Argentina -34.58 -58.66 POINT (-58.66000 -34.58000)
4 Santiago Chile -33.45 -70.66 POINT (-70.66000 -33.45000)
Nearest Distance
2 Bogota 2285.239605
0 Bogota 4628.641817
4 Bogota 4226.710978
如果要使用pandas
而不是geopandas
,
# cross join pandas
city1df['key'] = 1
city2df['key'] = 1
merged = city1df.merge(city2df, on='key')
使用math
函数,
# 8.65 ms ± 2.21 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
# find distance
merged['dist'] = list(
map(
dist2,
merged[['Longitude_x', 'Latitude_x']].values,
merged[['Longitude_y', 'Latitude_y']].values
)
)
mapping = {
'City_x': 'City',
'Country_x': 'Country',
'Latitude_x': 'Latitude',
'Longitude_x': 'Longitude',
'City_y': 'Nearest',
'dist': 'Distance'
}
nearest = merged.loc[merged.groupby(['City_x', 'Country_x'])['dist'].idxmin()]
nearest.rename(columns=mapping)[list(mapping.values())]
City Country Latitude Longitude Nearest Distance
2 Brasilia Brazil -15.78 -70.66 Bogota 2297.922808
0 Buenos Aires Argentina -34.58 -58.66 Bogota 4648.004515
4 Santiago Chile -33.45 -70.66 Bogota 4247.586882
用geopy
,
# 9.8 ms ± 807 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
# find distance
merged['dist'] = list(
map(
dist4,
merged[['Longitude_x', 'Latitude_x']].values,
merged[['Longitude_y', 'Latitude_y']].values
)
)
mapping = {
'City_x': 'City',
'Country_x': 'Country',
'Latitude_x': 'Latitude',
'Longitude_x': 'Longitude',
'City_y': 'Nearest',
'dist': 'Distance'
}
nearest = merged.loc[merged.groupby(['City_x', 'Country_x'])['dist'].idxmin()]
nearest.rename(columns=mapping)[list(mapping.values())]
City Country Latitude Longitude Nearest Distance
2 Brasilia Brazil -15.78 -70.66 Bogota 2285.239605
0 Buenos Aires Argentina -34.58 -58.66 Bogota 4628.641817
4 Santiago Chile -33.45 -70.66 Bogota 4226.710978
我有两个具有多列的数据帧。 我想比较df1['id']和df2['id'],并返回一个新的df,其中列['correct_id']具有匹配值。例子: df1: df2 这是我的代码: 我得到的结果是: 预期输出: 我该怎么解决这个问题拜托
我有一个熊猫数据框,如下所示,具有多个列,并希望获得列的总数。 我的尝试: 我试图使用和获取列的总和: 这会导致以下错误: 预期产出 我预计产出如下: 或者,我希望编辑< code>df,在标题为< code>TOTAL的新行中包含总计:
问题内容: 如何获得系列中最常出现的物品? 考虑系列 返回值应该是 问题答案: 您可以使用并提取第一个值: 这不一定是低效率的。与往常一样,对您的数据进行测试以查看适合的数据。
我正在学习CLR中的一节,它描述了使用分而治之的方法,使用两点之间的欧几里德距离来找到最近的点对。 有一个问题,要求找到最近的点对之间的manhatten距离,使用类似的方法。但是,我不能把握两者之间的区别。以下是我能想到的: 3)递归到我们的点子集<=3为止(在这种情况下使用蛮力) 4)最小距离可以是从任何一个递归调用返回的距离--称它为D。 5)找到线“L”周围2D宽度内所有点,然后对于每个这
问题内容: 我在Postgres 9.3数据库中有一个方案,在该方案中,我必须获取出售书籍的最近10个日期。考虑以下示例: table中目前没有任何限制,但是我们有一项服务,每天只插入一个计数。 我必须获得基于的结果。当我传递ID时,应使用书名,出售日期和出售份数生成报告。 所需的输出: 问题答案: 这看起来并不令人怀疑,但这 是个难题 。 假设条件 你的数目是。 表格中的所有列均已定义。 该表在
我正在从事一个小型Drools项目,因为我想了解更多关于使用规则引擎的知识。我有一个名为Event的类,它有以下字段: <代码>字符串标记 可以是任何字符串的标记 我在我的知识库中插入了数百个事件实例,现在我想得到3个最近的事件,它们都标记为“OK”(确定)。我想出了以下代码,它可以工作: 但是我有一种感觉,应该有更好的方法来做到这一点。这很冗长,不容易重复使用:如果我想获取具有