我正在生成许多,许多列联表作为我正在编写的项目的一部分。
工作流程为:
- 取一个包含连续(浮点)行的大型数据数组,并通过合并将其转换为离散整数值(例如,结果行的值为0-9)
- 将两行分割成向量X和Y,并从中生成contingency table,这样我就得到了二维频率分布
- 例如,我有一个10 x 10的数组,计算出现的(xi,yi)的数量
- 用列联表做一些信息论数学
最初,我这样写:
def make_table(x, y, num_bins):
ctable = np.zeros((num_bins, num_bins), dtype=np.dtype(int))
for xn, yn in zip(x, y):
ctable[xn, yn] += 1
return ctable
这工作正常,但速度太慢,以至于占用了整个项目90%的运行时间。
我能想到的最快的Python优化是这样的:
def make_table(x, y, num_bins):
ctable = np.zeros(num_bins ** 2, dtype=np.dtype(int))
reindex = np.dot(np.stack((x, y)).transpose(),
np.array([num_bins, 1]))
idx, count = np.unique(reindex, return_counts=True)
for i, c in zip(idx, count):
ctable[i] = c
return ctable.reshape((num_bins, num_bins))
这(不知何故)快得多,但它仍然是相当昂贵的东西,似乎不应该是一个瓶颈。有没有什么有效的方法来做这件事,我只是没有看到,或者我应该给予,并在cython中做这件事?
另外,这里还有一个基准测试功能。
def timetable(func):
size = 5000
bins = 10
repeat = 1000
start = time.time()
for i in range(repeat):
x = np.random.randint(0, bins, size=size)
y = np.random.randint(0, bins, size=size)
func(x, y, bins)
end = time.time()
print("Func {na}: {ti} Ms".format(na=func.__name__, ti=(end - start)))
2条答案
按热度按时间wb1gzix01#
将
np.stack((x, y))
的元素表示为整数的巧妙技巧可以更快:此外,第二个解决方案的最后一部分可以稍微简化,只需考虑
更重要的是,由于我们处理的是等间距的非负整数,
np.bincount
将优于np.unique
;因此,上述内容可以归结为总而言之,这提供了相当多的性能比你目前正在做的:
您可能还希望了解
np.histogramdd
,它同时负责舍入和合并,尽管它可能会比舍入和使用np.bincount
慢。qncylg1j2#
这个答案仅仅是将Fuglede的答案扩展到x和y可以离散成不同数量的箱的情况。它确实假设x和y的类别分别编号为
0, 1, ..., n_bins_x
和0, 1, ..., n_bins_y
。