【发布时间】:2019-12-08 21:02:41
【问题描述】:
我正在使用激光雷达的 3D 点云。这些点由 numpy 数组给出,如下所示:
points = np.array([[61651921, 416326074, 39805], [61605255, 416360555, 41124], [61664810, 416313743, 39900], [61664837, 416313749, 39910], [61674456, 416316663, 39503], [61651933, 416326074, 39802], [61679969, 416318049, 39500], [61674494, 416316677, 39508], [61651908, 416326079, 39800], [61651908, 416326087, 39802], [61664845, 416313738, 39913], [61674480, 416316668, 39503], [61679996, 416318047, 39510], [61605290, 416360572, 41118], [61605270, 416360565, 41122], [61683939, 416313004, 41052], [61683936, 416313033, 41060], [61679976, 416318044, 39509], [61605279, 416360555, 41109], [61664837, 416313739, 39915], [61674487, 416316666, 39505], [61679961, 416318035, 39503], [61683943, 416313004, 41054], [61683930, 416313042, 41059]])
我想将我的数据分组到大小为 50*50*50 的多维数据集中,以便每个多维数据集都保留它包含的 points 的一些可散列索引和 numpy 索引。为了进行拆分,我将cubes = points \\ 50 分配给:
cubes = np.array([[1233038, 8326521, 796], [1232105, 8327211, 822], [1233296, 8326274, 798], [1233296, 8326274, 798], [1233489, 8326333, 790], [1233038, 8326521, 796], [1233599, 8326360, 790], [1233489, 8326333, 790], [1233038, 8326521, 796], [1233038, 8326521, 796], [1233296, 8326274, 798], [1233489, 8326333, 790], [1233599, 8326360, 790], [1232105, 8327211, 822], [1232105, 8327211, 822], [1233678, 8326260, 821], [1233678, 8326260, 821], [1233599, 8326360, 790], [1232105, 8327211, 822], [1233296, 8326274, 798], [1233489, 8326333, 790], [1233599, 8326360, 790], [1233678, 8326260, 821], [1233678, 8326260, 821]])
我想要的输出如下所示:
{(1232105, 8327211, 822): [1, 13, 14, 18]),
(1233038, 8326521, 796): [0, 5, 8, 9],
(1233296, 8326274, 798): [2, 3, 10, 19],
(1233489, 8326333, 790): [4, 7, 11, 20],
(1233599, 8326360, 790): [6, 12, 17, 21],
(1233678, 8326260, 821): [15, 16, 22, 23]}
我的真实点云包含多达几亿个 3D 点。进行这种分组的最快方法是什么?
我已经尝试了大多数不同的解决方案。以下是假设点大小约为 2000 万且不同立方体大小约为 100 万的情况下的时间消耗比较:
熊猫 [tuple(elem) -> np.array(dtype=int64)]
import pandas as pd
print(pd.DataFrame(cubes).groupby([0,1,2]).indices)
#takes 9sec
默认 [elem.tobytes() 或元组 -> 列表]
#thanks @abc:
result = defaultdict(list)
for idx, elem in enumerate(cubes):
result[elem.tobytes()].append(idx) # takes 20.5sec
# result[elem[0], elem[1], elem[2]].append(idx) #takes 27sec
# result[tuple(elem)].append(idx) # takes 50sec
numpy_indexed [int -> np.array]
# thanks @Eelco Hoogendoorn for his library
values = npi.group_by(cubes).split(np.arange(len(cubes)))
result = dict(enumerate(values))
# takes 9.8sec
Pandas + 降维 [int -> np.array(dtype=int64)]
# thanks @Divakar for showing numexpr library:
import numexpr as ne
def dimensionality_reduction(cubes):
#cubes = cubes - np.min(cubes, axis=0) #in case some coords are negative
cubes = cubes.astype(np.int64)
s0, s1 = cubes[:,0].max()+1, cubes[:,1].max()+1
d = {'s0':s0,'s1':s1,'c0':cubes[:,0],'c1':cubes[:,1],'c2':cubes[:,2]}
c1D = ne.evaluate('c0+c1*s0+c2*s0*s1',d)
return c1D
cubes = dimensionality_reduction(cubes)
result = pd.DataFrame(cubes).groupby([0]).indices
# takes 2.5 seconds
可以下载cubes.npz文件here并使用命令
cubes = np.load('cubes.npz')['array']
检查性能时间。
【问题讨论】:
-
结果中的每个列表中的索引数量是否总是相同?
-
是的,它总是一样的:983234 个不同的立方体用于上述所有解决方案。
-
这样一个简单的 Pandas 解决方案不太可能被简单的方法打败,因为已经花费了大量精力来优化它。基于 Cython 的方法可能会接近它,但我怀疑它会胜过它。
-
@mathfux 您是否必须将最终输出作为字典,或者将组及其索引作为两个输出是否可以?
-
@norok2
numpy_indexed也只接近它。我想是对的。我目前在我的分类过程中使用pandas。
标签: python numpy hash grouping lidar