Numpy(np.unique)对于非常大的数组占用了太多的空间和时间,有什么有效的替代方案吗?

9o685dep  于 2023-08-05  发布在  其他
关注(0)|答案(3)|浏览(144)

我正在使用Numpy对点云文件进行一些下采样处理。在这个过程中,我使用np.unique从数组中获取唯一值计数。请注意,这是一个非常大的数组,大约有3600万个3D点。有没有其他有效的替代方法可以使用?或者我应该转换到其他数据结构来做np.unique在这里做的事情,以使过程更快?现在大概需要300秒。我知道unique已经优化了,但是有没有其他的数据结构可以用来获得更好的结果?数组只包含x,y,z格式的点。
我在下面附上我的代码片段。提前感谢您的帮助,请随时向我询问您可能需要的任何其他信息。我试着改变精度等级,但没有效果。我在Ubuntu 22.04上使用numpy 1.24.4。

import numpy as np
import time

points = np.random.random(size = (38867362,3))*10000

# print(points)
# print("points bytes:",points.nbytes)

start_time = time.time()
unique_points, inverse, counts = np.unique(((points - np.min(points, axis=0)) // 3).astype(int), axis=0, return_inverse=True, return_counts=True)
print("::INFO:: Total time taken: ", time.time()-start_time)

字符串
等等。

zbq4xfa0

zbq4xfa01#

你可以尝试从你的数据中创建一个集合。集合中的元素不会有任何重复。

data = [1,1,2,3]
s = set(data)
print(len(s))

字符串
不过,我还没有测试过这是否比你的方法快。而且,这不会给予你np.unique()的其他返回值。

编辑

作为OP给出的一个例子,我测量了(1)np.unique,(2)转换到元组列表,(3)set()的运行时间

import numpy as np
import time

points = np.random.random(size = (38867362, 3)) * 10000
points = ((points - np.min(points, axis=0)) // 3).astype(int)

start_time = time.time()
unique_points, inverse, counts = np.unique(points, axis=0, return_inverse=True, return_counts=True)
print("::INFO:: Total time taken np.unique: ", time.time() - start_time)

start_time = time.time()
points = tuple(map(tuple, points))
print("::INFO:: Total time tuple conversion: ", time.time() - start_time)

points = tuple(map(tuple, points))
start_time = time.time()
unique_points = set(points)
print("::INFO:: Total time taken set: ", time.time() - start_time)


带输出

::INFO:: Total time taken np.unique:  115.49143147468567
::INFO:: Total time tuple conversion:  36.052345991134644
::INFO:: Total time taken set:  9.044668436050415


所以set()确实是一个选项,如果其他返回值可以丢失的话…

3xiyfsfu

3xiyfsfu2#

根据OP的最终目标,这是一个一维数据的解决方案(它很容易调整,只是不清楚每个维度是单独处理还是同时处理)。

from collections import defaultdict
from tqdm import tqdm  # for nice loop animations
import numpy as np

floats = np.random.random(size=(388)) * 100
ints = floats.astype(np.int32)

D = defaultdict(list)

for f, i in tqdm(zip(floats, ints), total=len(floats)):
    D[i].append(f)

means = []
for key, vals in D.items():
    means.append(np.mean(vals))

字符串

slhcrj9b

slhcrj9b3#

下面是一个使用pandas DataFrame.drop_duplicates的版本。这很好,因为它不需要像set()那样进行元组转换。

import numpy as np
import time
import pandas as pd

points = np.random.random(size = (38867362, 3)) * 10000
points = ((points - np.min(points, axis=0)) // 3).astype(int)

df = pd.DataFrame(points)

start_time = time.time()
df.drop_duplicates()
print("::INFO:: Total time taken by drop_duplicates: ", time.time() - start_time)

字符串
输出为

::INFO:: Total time taken by drop_duplicates:  10.315263986587524


这比set()加上元组转换快4倍!

注意df.drop_duplicates(...).index是输入索引的子集,因此具有可比性。

相关问题