Python 包含ItError的dataframe apply函数

Python 包含ItError的dataframe apply函数,python,pandas,dataframe,Python,Pandas,Dataframe,我有一个熊猫的数据框(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.

我有一个熊猫的数据框(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()]

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

df = pd.DataFrame([('some data 1', (-73.973943, 40.760632)),
                   ('some data 2', (-74.010087, 40.709546))], 
                  columns=['h1', 'latlon'])
第三,查找地理信息

有没有更有效/更干净的方法来写这个?我觉得可能有办法避免
iterrows()


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

import pandas as pd
import geopandas as gpd
from shapely.geometry import Point
geopandas已读取_file(),这对于形状文件非常有用

geo = gpd.read_file('ZillowNeighborhoods-NY.shp')
使用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发现了一个漂亮的geopandas函数,名为

在形状文件中读取

geo = gpd.read_file('ZillowNeighborhoods-NY.shp')
将熊猫数据帧转换为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'}
现在使用“内”进行连接,即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不是最快的,但它可能是最好的(不处理匹配,在连接类型和操作中有更多功能)

可能能够执行布尔索引而不是get_location()中的for循环来获取匹配。这会产生什么结果<代码>地理[geo['Path']。包含_点(-73.973943,40.760632))]此外,请查看地理标记。我认为它在这里可能很方便
geo[geo['Path']。包含_点((-73.973943,40.760632))
生成布尔值,并基于它们函数返回当前的邻域信息,
g
。好的,我会检查的。好的,是的,但是那一行应该允许你省略for循环,对吗?我怎样才能避免
iterrows
或for循环?你最后做了什么?这太棒了!非常感谢你,鲍勃!
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
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