【问题标题】:Pandas - Group/bins of data per longitude/latitudePandas - 每个经度/纬度的数据组/箱
【发布时间】:2017-01-08 08:16:38
【问题描述】:

我有一堆地理数据如下。 我想按经度 0.2 度和纬度 0.2 度的 bin 对数据进行分组。

虽然对纬度或经度进行处理很简单,但对这两个变量执行此操作最合适的是什么?

|User_ID  |Latitude  |Longitude|Datetime           |u    |v    |
|---------|----------|---------|-------------------|-----|-----|
|222583401|41.4020375|2.1478710|2014-07-06 20:49:20|0.3  | 0.2 |
|287280509|41.3671346|2.0793115|2013-01-30 09:25:47|0.2  | 0.7 |
|329757763|41.5453577|2.1175164|2012-09-25 08:40:59|0.5  | 0.8 |
|189757330|41.5844998|2.5621569|2013-10-01 11:55:20|0.4  | 0.4 |
|624921653|41.5931846|2.3030671|2013-07-09 20:12:20|1.2  | 1.4 |
|414673119|41.5550136|2.0965829|2014-02-24 20:15:30|2.3  | 0.6 |
|414673119|41.5550136|2.0975829|2014-02-24 20:16:30|4.3  | 0.7 |
|414673119|41.5550136|2.0985829|2014-02-24 20:17:30|0.6  | 0.9 |

到目前为止,我所做的是创建了 2 个线性空间:

lonbins = np.linspace(df.Longitude.min(), df.Longitude.max(), 10) 
latbins = np.linspace(df.Latitude.min(), df.Latitude.max(), 10)

然后我可以分组使用:

groups = df.groupby(pd.cut(df.Longitude, lonbins))

然后我显然可以遍历组以创建第二个级别。我的目标是对每个组进行统计分析,并可能将它们显示在一张看起来不太方便的地图上。

bucket = {}
for name, group in groups: 
    print name bucket[name] = group.groupby(pd.cut(group.Latitude, latbins))

例如,我想做一个热图,它会显示每个 latlon 框的行数,显示每个 latlon 框中的速度分布,...

【问题讨论】:

  • 为什么不先做一个,然后再做另一个?
  • 到目前为止你做了什么?请发布您的代码。
  • 您的示例数据框的预期结果是什么?如果您发布它,我们可以更好地理解您的问题。谢谢!

标签: python pandas binning


【解决方案1】:

这个怎么样?

step = 0.2
to_bin = lambda x: np.floor(x / step) * step
df["latBin"] = df.Latitude.map(to_bin)
df["lonBin"] = df.Longitude.map(to_bin)
groups = df.groupby(["latBin", "lonBin"])

【讨论】:

  • 谢谢,这是一个很好的解决方案。如果我想更轻松地将统计信息转换回我可能添加到底图的图层(我不确定这是否可能),我可能应该将您的解决方案与 linspace 混合。例如:to_lonbin = lambda x: lonbin.searchsorted(x) 你瘦什么?
  • 应该可以,但这里似乎不需要搜索。 to_lonbin = lambda x: np.floor((x + 180) / step) 应该产生相同的结果。
  • 说我必须对数据进行分组,而不是在简单的常规 0.2 网格上,而是在给定的网格上(我有 lat_bin_edges 和 lon_bin_edges 值,但它不完全是规则的)。我该如何修改?
  • 您可以将 to_bin 替换为将坐标映射到任意 bin 的函数。然后你可以像上面的例子一样在 bin(s) 上做groupby()
  • 谢谢 - 我认为在你的回复中你应该有“圆形”而不是“地板”,对吗? groupby 中的 latbin,lonbin 是 bin 的中心,而不是边缘,所以我认为这很重要吗?我走了吗?
【解决方案2】:

这是一个明显更快的解决方案:

选项 1:

如果您希望 binEdges 精确到每 0.2 度并且在 [66.6, 66.8, 67.0, .....] 之类的浮点数上,请使用此选项:

import numpy as np
step = 0.2
boundingBox = {"lat":
               {"min": np.floor(df.Latitude.min()/step)*step,
                "max": np.ceil(df.Latitude.max()/step)*step},
               "lon":
               {"min": np.floor(df.Longitude.min()/step)*step,
                "max": np.ceil(df.Longitude.max()/step)*step}
               }
noOfLatEdges = int(
    (boundingBox["lat"]["max"] - boundingBox["lat"]["min"]) / step)
noOfLonEdges = int(
    (boundingBox["lon"]["max"] - boundingBox["lon"]["min"]) / step)
latBins = np.linspace(boundingBox["lat"]["min"],
                      boundingBox["lat"]["max"], noOfLatEdges)
lonBins = np.linspace(boundingBox["lon"]["min"],
                      boundingBox["lon"]["max"], noOfLatEdges)
H, _, _ = np.histogram2d(df.Latitude, df.Longitude, bins=[latBins, lonBins])
binnedData = H.T # Important as otherwise the axes are wrong way around (I missed this for ages, see "Notes" of Numpy docs for histogram2d())

选项 2:

如果您希望 binEdges 几乎恰好每 0.2 度,并且像 [66.653112, 66.853112, 67.053112, .....] 这样的浮动,请使用此选项:

import numpy as np
step = 0.2
boundingBox = {"lat":
               {"min": df.Latitude.min(), "max": df.Latitude.max()},
               "lon":
               {"min": df.Longitude.min(), "max": df.Longitude.max()}
               }
noOfLatEdges = int(
    (boundingBox["lat"]["max"] - boundingBox["lat"]["min"]) / step)
noOfLonEdges = int(
    (boundingBox["lon"]["max"] - boundingBox["lon"]["min"]) / step)
H, xedges, yedges = np.histogram2d(df.Latitude, df.Longitude, bins=[
                                   noOfLatEdges, noOfLonEdges])
binnedData = H.T # Important as otherwise the axes are wrong way around (I missed this for ages, see "Notes" of Numpy docs for histogram2d())

选项 1、2 与 Martin Valgur 接受的解决方案之间的运行时比较:

这个答案对很多人来说可能看起来更长,但是我最近做了一个项目,这是一个非常频繁地运行的时间关键组件,所以这个答案帮助我极大地(% 明智地)减少了我们的 API 计算时间。

在 16k 行 DataFrame 上计算的运行时间被分成 964 x 1381 个桶。

Martin Valgur 当前接受的答案的运行时间为:

每个循环 30.1 ms ± 799 µs(平均值 ± 标准偏差,7 次运行,每次 10 个循环)

选项 1 的运行时间为:

每个循环 6.78 ms ± 130 µs(平均值 ± 标准偏差,7 次运行,每次 100 个循环)

选项 2 的运行时间为:

每个循环 8.17 ms ± 164 µs(平均值 ± 标准偏差,7 次运行,每次 100 个循环)

因此,选项 1 的速度几乎是当前解决方案的 5 倍。 但是,如果桶的维度对于现代内存来说变得太大,Martin 的 Pandas 解决方案可能会更高效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-09
    • 1970-01-01
    • 1970-01-01
    • 2013-04-05
    • 1970-01-01
    • 1970-01-01
    • 2019-07-03
    相关资源
    最近更新 更多