Одновременное объединение GeoDataFrames как с геометрией Point, так и с другими столбцами - PullRequest
0 голосов
/ 17 сентября 2018

Как можно объединить две GeoDataFrame с геометрией Point и произвольными другими столбцами одновременно?Я понимаю, что эта задача неоднозначна для всех других геометрий, отличных от Point, потому что "равенство" не совсем определено для линий и многоугольников, но все же.

Следующее MWE выдает ошибку, если я просто пытаюсь gdf2.merge(gdf),правильно жаловаться, что

не подлежащий обработке тип: 'Point'.

Как обойти это?

import geopandas as gpd
import pandas as pd
from io import StringIO
import shapely

df = pd.read_csv(StringIO('''
Name Value x y
'a' 1.5 0. 0.
'b' 22  0. 1.
'c' 0.2 0. 1.
'''),sep=r"\s*",engine='python')

df2 = pd.read_csv(StringIO('''
Name OtherValue x y
'a' 9.9 0. 0.
'b' 4.5 0. 1.
'c' 2e3 1. 1.
'''),sep=r"\s*",engine='python')

def dataframe_to_geodataframe(df):
    geometry = [shapely.geometry.Point(xy) for xy in zip(df.x, df.y)]
    df = df.drop(['x','y'], axis=1)
    gdf = gpd.GeoDataFrame(df, geometry=geometry)
    return gdf

gdf = dataframe_to_geodataframe(df)
gdf2 = dataframe_to_geodataframe(df2)

gdf.merge(gdf2,how='left')

В идеале вывод будет выглядеть примерно так:

  Name  Value     geometry OtherValue
0  'a'    1.5  POINT (0 0)        9.9
1  'b'   22.0  POINT (0 1)        4.5
2  'c'    0.2  POINT (0 1)        NaN

(конечно, в зависимости от ключевого слова how).

(я понимаю, что это можно легко сделать после преобразования обратно в обычные панды DataFrames, но я считаю, чтоспособ сделать это без преобразования вперед и назад.)

1 Ответ

0 голосов
/ 18 сентября 2018

Один (возможно, грязный) способ - сделать Point хешируемым, расширив класс shapely.geometry.Point:

class HPoint(shapely.geometry.Point):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def __hash__(self):
       return hash(tuple(self.coords))

Это основано на том факте, что оператор равенства для Point (предоставляется через родительский класс BaseGeometry) просто сравнивает кортежи координат.

Тогда вы можете использовать этот класс как:

def dataframe_to_geodataframe(df):
    geometry = [HPoint(xy) for xy in zip(df.x, df.y)]
    df = df.drop(['x','y'], axis=1)
    gdf = gpd.GeoDataFrame(df, geometry=geometry)
    return gdf

gdf = dataframe_to_geodataframe(df)
gdf2 = dataframe_to_geodataframe(df2)

print(gdf2.merge(gdf, how='right'))

что дает:

  Name  OtherValue     geometry  Value
0  'a'         9.9  POINT (0 0)    1.5
1  'b'         4.5  POINT (0 1)   22.0
2  'c'         NaN  POINT (0 1)    0.2
...