GeoDataFrame von x, y-Koordinaten mit GROUPBY in Linestrings umwandeln?

8

Ich habe einen Datenrahmen mit X- und Y-Koordinaten, die Punkte entlang der Pfade darstellen, die von mehreren verschiedenen Entitäten genommen wurden. Pseudodaten hier, aber es hat ungefähr die Form:

entity_id   lat   lon   time

1001        34.5  14.2  4:55 pm
1001        34.7  14.5  4:58 pm
1001        35.0  14.6  5.03 pm

1002        27.1  19.2  2:01 pm
1002        27.4  19.3  2:08 pm
1002        27.4  19.9  2:09 pm

Was ich tun möchte, ist, diese Punkte nach zu gruppieren entity_idund dann die Punkte nacheinander zeitlich anzuordnen, um LineStringfür jeden ein Objekt zu erstellen entity_id. Die Ausgabe besteht aus mehreren Zeilen / Pfaden, von denen jede einem entspricht entity_id.

Ich kann dies tun, indem ich entity_idjeden Punkt in jedem Schritt durchlaufe und entity_iddie hier bereitgestellten Anweisungen verwende. Gibt es jedoch eine schnellere / effizientere Möglichkeit, GeoPandas oder Shapely zu nutzen, vielleicht mit groupby?

atkat12
quelle

Antworten:

16

Ich glaube, ich habe eine Zwischenlösung gefunden, die ich veröffentliche, falls sie für jemanden nützlich ist:

import pandas as pd
import numpy as np
from geopandas import GeoDataFrame
from shapely.geometry import Point, LineString

# Zip the coordinates into a point object and convert to a GeoDataFrame
geometry = [Point(xy) for xy in zip(df.lon, df.lat)]
df = GeoDataFrame(df, geometry=geometry)

# Aggregate these points with the GroupBy
df = df.groupby(['entity_id'])['geometry'].apply(lambda x: LineString(x.tolist()))
df = GeoDataFrame(df, geometry='geometry')

Beachten Sie, dass Sie, wenn Ihre Daten Einzelpunkt-Trajektorien enthalten, diese zuerst verwerfen müssen, da sonst LineString einen Fehler auslöst.

Dieser und dieser Beitrag waren beim Schreiben der GroupBy-Funktion hilfreich.


Update : Wenn Sie den einzelnen Punkt nicht verworfen haben, können Sie auch den bedingten Satz wie folgt verwenden:

 df = df.groupby(['entity_id'])['geometry'].apply(lambda x: LineString(x.tolist()) if x.size > 1 else x.tolist())
atkat12
quelle
das ist großartig!
Ufos
Wenn Sie nur das gruppierte Dataset möchten und die ID als Spalte behalten möchten, sollte dies helfen:df.groupby('entity_id', as_index=False).agg({'geometry': lambda x: ...})
Ufos