如何高效统计海量坐标数组中重复元素的频次及最高频元素?
寻找高频坐标的更快实现方案
我有一个长度约20万的二维数组,每个元素代表(x, y)坐标,需要找出数组中出现频次最高的坐标及其出现次数。例如数组A = [(1, 2), (2, 3), (1, 2), (4, 5)]中,(1, 2)是出现频次最高的坐标,次数为2。
我尝试过用numpy.unique()处理,但觉得速度不够理想,有没有更快的替代方法?
以下是我的测试代码及运行耗时:
print(f"Array shape: {sub_res.shape}") t6 = time.perf_counter() unique_values, counts = np.unique(sub_res, axis=0, return_counts=True) sorted_indces = np.argsort(-counts) max_counts = np.max(counts[sorted_indces]) t7 = time.perf_counter() print("'np unique' time : {}".format(round(t7-t6, 2))) sub_res_list_tuple = list(tuple(map(tuple, sub_res))) counts_res = Counter(sub_res_list_tuple) most_common_temp = counts_res.most_common(1)[0] unique_values_2, counts_2 = most_common_temp[0], most_common_temp[1] t8 = time.perf_counter() print("'Counter' time : {}".format(round(t8 - t7, 2)))
运行输出:
Array shape: (218820, 2) 'np unique' time : 0.12 'Counter' time : 0.19
更快的替代方案
1. 优化np.unique的使用逻辑
原代码中做了排序操作,但如果只需要找频次最高的元素,完全不需要对所有计数排序,直接用np.argmax找最大值索引即可,省去排序的时间开销:
import numpy as np import time t_start = time.perf_counter() unique_vals, counts = np.unique(sub_res, axis=0, return_counts=True) max_idx = np.argmax(counts) most_freq_coord = unique_vals[max_idx] most_freq_count = counts[max_idx] t_end = time.perf_counter() print(f"Optimized np.unique time: {round(t_end - t_start, 2)}")
2. 坐标转一维整数+np.bincount(最快方案之一)
把二维坐标转换成唯一的一维整数(利用哈希思想),然后用np.bincount做统计——这个方法的时间复杂度接近O(n),远优于np.unique的O(n log n):
import numpy as np import time # 根据你的坐标范围选择合适的基数,确保x*base + y不会重复 base = 10**6 # 假设x和y的绝对值都小于1e6 flat_coords = sub_res[:, 0] * base + sub_res[:, 1] t_start = time.perf_counter() counts = np.bincount(flat_coords) max_count = counts.max() most_freq_flat = np.argmax(counts) # 还原回二维坐标 most_freq_coord = (most_freq_flat // base, most_freq_flat % base) t_end = time.perf_counter() print(f"np.bincount time: {round(t_end - t_start, 2)}")
如果坐标范围较大,可以改用更大的基数,或者使用np.int64类型避免溢出。
3. 使用pandas的value_counts
pandas内部对这类统计做了优化,实际运行速度也会优于collections.Counter:
import pandas as pd import time t_start = time.perf_counter() df = pd.DataFrame(sub_res, columns=['x', 'y']) count_result = df.value_counts() most_freq_coord = count_result.index[0] most_freq_count = count_result.iloc[0] t_end = time.perf_counter() print(f"pandas value_counts time: {round(t_end - t_start, 2)}")
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

