【问题标题】:Fast conversion of easting and northing to latitude and longitude for a large DataFrame of locations快速将东向和北向转换为大型 DataFrame 位置的纬度和经度
【发布时间】:2020-09-13 02:15:38
【问题描述】:

我正在使用 Pandas 和 PyProj 将东向和北向转换为经度和纬度,然后将拆分输出保存到像这样的 2 列中......

v84 = Proj(proj="latlong",towgs84="0,0,0",ellps="WGS84")
v36 = Proj(proj="latlong", k=0.9996012717, ellps="airy",
        towgs84="446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894")
vgrid = Proj(init="world:bng")


def convertLL(row):

    easting = row['easting']
    northing = row['northing']

    vlon36, vlat36 = vgrid(easting, northing, inverse=True)

    converted = transform(v36, v84, vlon36, vlat36)

    row['longitude'] = converted[0]
    row['latitude'] = converted[1]

    return row


values = pd.read_csv("values.csv")
values = values.apply(convertLL, axis=1)

这是可行的,但速度很慢,并且在较大的数据集上会超时。为了改进事情,我试图将其转换为使用lamba函数,希望能加快速度。到目前为止我有这个......

def convertLL(easting, northing):

    vlon36, vlat36 = vgrid(easting, northing, inverse=True)

    converted = transform(v36, v84, vlon36, vlat36)

    row = row['longitude'] = converted[0]

    return row


values ['longitude'] = values.apply(lambda row: convertLL(row['easting'], row['northing']), axis=1)

这个转换后的版本正在运行,比我的旧版本更快,并且在更大的数据集上不会超时,但这仅适用于经度,有没有办法让它也能做纬度?

另外,这是矢量化的吗?我可以再加快速度吗?

编辑

数据样本...

name | northing | easting | latitude | longitude
------------------------------------------------
tl1  | 378778   | 366746  |          |
tl2  | 384732   | 364758  |          |

【问题讨论】:

  • 你能给我们df.head()的输出,让我有东西玩吗?
  • 我已经用示例更新了帖子,够了吗?
  • 对不起,我被叫走了,所以没有机会看它。我最初认为“好吧,我们可能可以取消所有对 PyProj 的函数调用并实现矢量化版本”,然后我发现 this 这真的让我不敢尝试这种方法:P
  • 啊哈,我知道我们现在该怎么做。 transform 已经接受了数组输入。请显示您的导入(对于vgrid)以及v36v84 在哪里定义,以便我可以进行可重复的测试?
  • 已更新操作

标签: python pandas pyproj


【解决方案1】:

由于主题,我认为我们无法只见树木不见森林。如果我们查看the docs for transform,您会看到:

  • xx(标量或数组(numpy 或 python))- 输入 x 坐标。
  • yy(标量或数组(numpy 或 python))- 输入 y 坐标。

太棒了; numpy 数组正是我们所需要的。 pd.DataFrame 可以被认为是一个数组字典,所以我们只需要隔离这些列并将它们传递给函数。有一个小问题 - DataFrame 的列将是 Seriestransform 将拒绝,所以我们只需要使用 values 属性。这个迷你示例直接等同于您的初始方法:

def vectorized_convert(df):
    vlon36, vlat36 = vgrid(df['easting'].values, 
                           df['northing'].values, 
                           inverse=True)
    converted = transform(v36, v84, vlon36, vlat36)
    df['longitude'] = converted[0]
    df['latitude'] = converted[1]
    return df

df = pd.DataFrame({'northing': [378778, 384732],
                   'easting': [366746, 364758]})

print(vectorized_convert(df))

我们完成了。除此之外,我们可以查看 100 行的时序(当前的方法在我通常的 100,000 行时序示例中爆炸式增长):

def current_way(df):
    df = df.apply(convertLL, axis=1)
    return df


def vectorized_convert(df):
    vlon36, vlat36 = vgrid(df['easting'].values, 
                           df['northing'].values, 
                           inverse=True)

    converted = transform(v36, v84, vlon36, vlat36)
    df['longitude'] = converted[0]
    df['latitude'] = converted[1]
    return df


df = pd.DataFrame({'northing': [378778, 384732] * 50,
                   'easting': [366746, 364758] * 50})

给予:

%timeit current_way(df)
289 ms ± 15.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit vectorized_convert(df)
2.95 ms ± 59.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

【讨论】:

  • 看起来真不错,给我一些时间消化一切,我会回来的。非常感谢!
  • @fightstarr20 重点是避免使用apply。如果您运行第一个代码 sn-p 您将看到 两行 在单个函数调用中填充了 latitutdelongitude
  • @fightstarr20 这是向量化操作的本质——它们对数组的作用就像它们是标量一样,所以我们不需要遍历行(这很慢)。 PyProj 似乎大量使用 Cython,因此它是一个可以编译成 C++ 的代码库。我们希望传递数组并让它同时处理所有值,这可能能够利用诸如 BLAS/LAPACK 和 SIMD 之类的东西。 apply 将默认为 python for 循环,它有很多开销。将整个 df 传递给函数
  • 了解,感谢您的澄清,现在已经成功运行。速度提升令人难以置信!没有更多的超时,非常感谢您对此的帮助!
  • @fightstarr20 不客气。不过,我想重命名您的问题以使其更具体地针对该主题,如果可以吗?我认为它太宽泛,对其他人有用
猜你喜欢
  • 1970-01-01
  • 2011-12-13
  • 2016-10-09
  • 1970-01-01
  • 1970-01-01
  • 2019-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多