Pandas dataframe apply函数具有iterrows

2024-06-17 11:16:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个熊猫的数据框(10亿条记录),需要从另一个数据框中查找位置信息。这个方法有效,但我想知道是否有更好的方法来执行这个操作。在

首先,创建地理数据帧

import pandas as pd
import shapefile
from matplotlib import path

#downloaded and unzipped https://www.zillowstatic.com/static/shp/ZillowNeighborhoods-NY.zip
sf = shapefile.Reader('ZillowNeighborhoods-NY.shp')
cols = ['State', 'County', 'City', 'Name', 'RegionID']
geo = pd.DataFrame(sf.records(), columns=cols)
geo['Path'] = [path.Path(s.points) for s in sf.iterShapes()]

enter image description here

其次,创建一个包含我的数据的dataframe。它实际上有10亿条记录。在

^{pr2}$

第三,查找地理信息。在

有没有更有效/更干净的方式来写这篇文章?我觉得也许有一个熊猫的方法可以避免iterrows()。在

def get_location(row):    
    for _, g in geo.iterrows():
        match = g.Path.contains_point(row['latlon'])
        if match:
            return g[['City', 'Name']]

df.join(df.apply(get_location, axis=1))

enter image description here


Tags: 数据path方法importcity记录sfgeo
2条回答

这个答案避免了iterrows方法(因此速度更快),但它仍然使用apply(axis=1),这不是很好,尤其是在估计10亿行时。另外,我用的是geopandas和shapely

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

geopandas有read_file(),这对形状文件非常有用

^{pr2}$

使用Shapely处理点

df = pd.DataFrame([('some data 1', (-73.973943, 40.760632)),
                   ('some data 2', (-74.010087, 40.709546))], 
                  columns=['h1', 'latlon'])
df['point'] = [Point(xy) for xy in df['latlon']] 

使用geopandas contains()和一些布尔索引。注意:您可能需要加入一些逻辑来处理“不匹配”的情况

def get_location(row):  
    return pd.Series(geo[geo.contains(row['point'])][['City', 'Name']].values[0])

df.join(df.apply(get_location, axis=1))

OP,E.K.,发现了一个漂亮的geopandas函数,叫做sjoin

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

正在读取形状文件

^{pr2}$

将熊猫数据帧转换为geopandas数据帧。注意:我们使用与形状文件相同的坐标参考系(CRS)。这对我们把两个框架连接在一起是必要的

df = pd.DataFrame([('some data 1', (-73.973943, 40.760632)),
                   ('some data 2', (-74.010087, 40.709546))], 
                  columns=['h1', 'latlon'])
geometry = [Point(xy) for xy in df['latlon']] 
gdf = gpd.GeoDataFrame(df, crs=geo.crs, geometry=geometry)
print (geo.crs, gdf.crs)
>> {'init': 'epsg:4269'} {'init': 'epsg:4269'}

现在使用'within'即gdf中的哪些点在geo的多边形内

gpd.tools.sjoin(gdf, geo, how='left', op='within')

一些计时注意事项:

OP的解决方案

import pandas as pd
import shapefile
from matplotlib import path

#downloaded and unzipped https://www.zillowstatic.com/static/shp/ZillowNeighborhoods-NY.zip
sf = shapefile.Reader('ZillowNeighborhoods-NY.shp')
cols = ['State', 'County', 'City', 'Name', 'RegionID']
geo = pd.DataFrame(sf.records(), columns=cols)
geo['Path'] = [path.Path(s.points) for s in sf.iterShapes()]

df = pd.DataFrame([('some data 1', (-73.973943, 40.760632)),
                   ('some data 2', (-74.010087, 40.709546))], 
                  columns=['h1', 'latlon'])

def get_location(row):    
    for _, g in geo.iterrows():
        match = g.Path.contains_point(row['latlon'])
        if match:
            return g[['City', 'Name']]

%timeit df.join(df.apply(get_location, axis=1))
>> 10 loops, best of 3: 91.1 ms per loop

我的第一个答案是使用geopandas、apply()和布尔索引

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

geo = gpd.read_file('ZillowNeighborhoods-NY.shp')  

df = pd.DataFrame([('some data 1', (-73.973943, 40.760632)),
                   ('some data 2', (-74.010087, 40.709546))], 
                  columns=['h1', 'latlon'])
df['geometry'] = [Point(xy) for xy in df['latlon']] 


def get_location(row):  
    return pd.Series(geo[geo.contains(row['geometry'])][['City', 'Name']].values[0])

%timeit df.join(df.apply(get_location, axis=1))
>> 100 loops, best of 3: 15.3 ms per loop

使用sjoin

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

geo = gpd.read_file('ZillowNeighborhoods-NY.shp')

df = pd.DataFrame([('some data 1', (-73.973943, 40.760632)),
                   ('some data 2', (-74.010087, 40.709546))], 
                  columns=['h1', 'latlon'])
geometry = [Point(xy) for xy in df['latlon']] 
gdf = gpd.GeoDataFrame(df, crs=geo.crs, geometry=geometry)

%timeit gpd.tools.sjoin(gdf, geo, how='left', op='within')
>> 10 loops, best of 3: 53.3 ms per loop

虽然sjoin不是最快的,但它可能是最好的(不处理任何匹配,在联接类型和操作中有更多的功能)

相关问题 更多 >