Python >> Python opplæring >  >> Python

Bygge GeoDataFrame rad for rad

Du trenger ikke å bygge GeoDataFrame rad for rad her, se på pandas.DataFrame.from_dict¶

import pandas as pd
df = pd.DataFrame.from_dict(my_dict,orient='index')
print(df)
     name     lat        lon    type
007    A  48.843664   2.302672   small
008    B  50.575813   7.258148  medium
010    C  47.058420  15.437464     big
from shapely.geometry import Point
df["geometry"] = df.apply (lambda row: Point(row.lon,row.lat), axis=1)

Konverter til en GeoDataFrame

gdf = gpd.GeoDataFrame(df, geometry=df.geometry)
print(gdf)
     name    lat        lon      type            geometry
007    A  48.843664   2.302672   small  POINT (2.302672 48.843664)
008    B  50.575813   7.258148  medium  POINT (7.258148 50.575813)
010    C  47.058420  15.437464     big  POINT (15.437464 47.05842)

Eller direkte:

gdf = gpd.GeoDataFrame(df, geometry=df.apply(lambda row: Point(row.lon,row.lat), axis=1)

Med andre ord, ikke lag en ny DataFrame for hver rad. Samle i stedet alle dataene i en liste med dikter, og ring deretter df =pd.DataFrame(data) en gang på slutten, utenfor loopen.
Hvert kall til df.append krever tildeling av plass til en ny DataFrame med én ekstra rad, kopiering av alle dataene fra den originale DataFrame inn i den nye DataFrame, og deretter kopiering av data til den nye raden. All den allokeringen og kopieringen gjør det svært ineffektivt å kalle df.append i en loop. Tidskostnaden ved kopiering vokser kvadratisk med antall rader. Ikke bare er call-DataFrame-once-koden enklere å skrive, dens ytelse vil være mye bedre - tidskostnaden for kopiering vokser lineært med antall rader. (fra Hvordan legge til rader i en panda-dataramme i en for-løkke?)


Jeg tror ikke at en rad for rad bygning ville ha bedre ytelse. Jeg har testet.

Resultat:

import geopandas as gpd
import pandas as pd
from shapely.geometry import  Point

d = {'007': {'name': 'A', 'lat': 48.843664, 'lon': 2.302672, 'type': 'small' },
     '008': {'name': 'B', 'lat': 50.575813, 'lon': 7.258148, 'type': 'medium'},
     '010': {'name': 'C', 'lat': 47.058420, 'lon': 15.437464,'type': 'big'}}

## IN THE ABOVE CASE. Duration: ~1 ms (milisecond)
tmp_list = []
for item_key, item_value in d.items() :
    tmp_list.append({
      'geometry' : Point(item_value['lon'], item_value['lat']),
      'id': item_key,
      'name': item_value ['name'],
      'type': item_value ['type']
     })
gdf = gpd.GeoDataFrame(tmp_list)
##


## SOLUTION 1. Duration: ~2.3 ms, @gene's answer.
df = pd.DataFrame.from_dict(d, orient='index')
df["geometry"] = df.apply (lambda row: Point(row.lon,row.lat), axis=1)
gdf = gpd.GeoDataFrame(df, geometry=df.geometry)
##


## SOLUTION 2. Duration: ~2.5 ms
gdf = gpd.GeoDataFrame()    
gdf["id"]   = [k for k in d.keys()]
gdf["name"] = [d[k]["name"] for k in d.keys()]
gdf["type"] = [d[k]["type"] for k in d.keys()]
gdf["geometry"]  = [Point(d[k]["lon"], d[k]["lat"]) for k in d.keys()]    
gdf.set_index('id', inplace=True)
##


## SOLUTION 3. Duration: ~9.5 ms
gdf = gpd.GeoDataFrame(columns=["name", "type", "geometry"])
for k, v in d.items():
    gdf.loc[k] = (v["name"], v["type"], Point(v["lon"], v["lat"]))
##

print(gdf)

# OUTPUT for the last solution
#     name    type                   geometry
# 007    A   small   POINT (2.30267 48.84366)
# 008    B  medium   POINT (7.25815 50.57581)
# 010    C     big  POINT (15.43746 47.05842)