首页 > 解决方案 > 从地理坐标和/或邮政编码获取 NUTS2 区域

问题描述

我有一个 df ,其中包含包括地理坐标和邮政编码在内的数据。

lat     | lon  | postcode
54.3077 | 12.7 | 18314   
51.898  | 9.26 | 32676

我需要一个带有 NUTS2 区域的新列,因此在这种情况下,生成的 df 应该如下所示:

lat     | lon  | postcode | NUTS_ID
54.3077 | 12.7 | 18314    | DE80
51.898  | 9.26 | 32676    | DEA4

我找到了这个包:我设法运行的https://github.com/vis4/pyshpgeocode 。我的第一种方法是以下两个功能:

def get_gc(nuts='geoc\\shapes\\nuts2\\nuts2.shp'):
    """
    nuts -> path to nuts file
    """
    gc = geocoder(nuts, filter=lambda r: r['LEVL_CODE'] == 2)
    return gc
def add_nuts_to_df(df):
    """
    df must have lon/lat geocoodinates in it
    This function will add a column ['NUTS_ID'] with the corresponding
    NUTS region
    """
    start_time = time.time()
    for idx, row in df.iterrows():
        df.loc[idx, 'NUTS_ID'] = get_gc().geocode(row.lat,
                                                  row.lon,
              filter=lambda r: r['NUTS_ID'][:2] == 'DE')['NUTS_ID']
        print('Done with index {}\nTime since start: {}s'.format(idx,
              round(time.time() - start_time, 0 )))
    return df

这确实有效!但是,一个条目大约需要 0.6 秒,而我的一些 df 条目超过一百万。由于我的原始数据框通常包含邮政编码,我正在考虑使用 groupby / apply / transform 的组合来聚合它们?

或者有没有其他(更有效)的方式来做到这一点?

我非常感谢任何帮助,并期待收到回复。

标签: pythonpandasgeopandas

解决方案


gc如果我正确理解您的代码,那么您正在为来自同一输入文件的每个请求重新创建对象。我不明白为什么。

因此,一种可能性是执行以下操作:

def add_nuts_to_df(df):
    """
    df must have lon/lat geocoodinates in it
    This function will add a column ['NUTS_ID'] with the corresponding
    NUTS region
    """
    nuts='geoc\\shapes\\nuts2\\nuts2.shp'
    gc = geocoder(nuts, filter=lambda r: r['LEVL_CODE'] == 2)

    start_time = time.time()
    for idx, row in df.iterrows():
        df.loc[idx, 'NUTS_ID'] = gc.geocode(row.lat,
                                                  row.lon,
              filter=lambda r: r['NUTS_ID'][:2] == 'DE')['NUTS_ID']
        print('Done with index {}\nTime since start: {}s'.format(idx,
              round(time.time() - start_time, 0 )))
    return df

df.apply()如果您尝试使用该方法并将您的地理编码逻辑传递到那里的函数中,也许它会加快这个过程。

就像是:

nuts='geoc\\shapes\\nuts2\\nuts2.shp'
gc = geocoder(nuts, filter=lambda r: r['LEVL_CODE'] == 2)

def get_nuts_id(row):
    return gc.geocode(row.lat, row.lon, 
                      filter=lambda r: r['NUTS_ID'][:2] == 'DE')['NUTS_ID']

df["NUTS_ID"] = df.apply(get_nuts_id,axis=1)

不过我没有尝试过,所以要小心拼写错误。


推荐阅读