首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python联想表

Python联想表
EN

Stack Overflow用户
提问于 2018-07-12 05:26:01
回答 1查看 1.3K关注 0票数 4

作为我正在编写的一个项目的一部分,我正在生成许多许多列联表。

工作流程是:

  • 获取一个具有连续(浮点)行的大型数据数组,并通过装箱将这些数组转换为离散整数值(例如,结果行具有值0-9 )
  • 将两行分成向量X&Y并从它们生成contingency table,因此我有一个二维频率分布
  • 例如,我有一个10 x 10数组,计算出现的(xi,yi)的数量
  • 使用列联表做一些信息理论数学<代码>H29<代码>F210

最初,我是这样写的:

代码语言:javascript
复制
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优化是:

代码语言:javascript
复制
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中做到这一点?

另外,这是一个基准测试函数。

代码语言:javascript
复制
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)))
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-07-12 05:41:43

np.stack((x, y))的元素表示为整数的聪明技巧可以更快地实现:

代码语言:javascript
复制
In [92]: %timeit np.dot(np.stack((x, y)).transpose(), np.array([bins, 1]))
109 µs ± 6.55 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [94]: %timeit bins*x + y
12.1 µs ± 260 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

此外,您的第二个解决方案的最后一部分可以稍微简化,只需考虑

代码语言:javascript
复制
np.unique(bins * x + y, return_counts=True)[1].reshape((bins, bins))

更重要的是,由于我们处理的是等间距的非负整数,np.bincount的性能将优于np.unique;因此,上面的结论可以归结为

代码语言:javascript
复制
np.bincount(bins * x + y).reshape((bins, bins))

总而言之,这比你目前正在做的事情提供了相当多的性能:

代码语言:javascript
复制
In [78]: %timeit make_table(x, y, bins)  # Your first solution
3.86 ms ± 159 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [79]: %timeit make_table2(x, y, bins)  # Your second solution
443 µs ± 23.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [101]: %timeit np.unique(bins * x + y, return_counts=True)[1].reshape((bins, bins))
307 µs ± 25 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [118]: %timeit np.bincount(bins * x + y).reshape((10, 10))
30.3 µs ± 3.44 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

您可能还希望了解np.histogramdd,它同时处理四舍五入和入库,尽管它可能比四舍五入和使用np.bincount慢。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51294382

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档