【问题标题】:fastest way to arrange data in python numpy based on list基于列表在python numpy中排列数据的最快方法
【发布时间】:2011-03-28 08:07:22
【问题描述】:

我在 numpy 中排列数据时遇到问题 示例有数据范围列表:

numpy.array([1,3,5,4,6])

我有数据:

numpy.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19])

我需要将数据安排到

numpy.array([

[1,9999,9999,9999,9999,9999,9999]

[2,3,4,9999,9999,9999]

[5,6,7,8,9,9999]

[10,11,12,13,9999,9999]

[14,15,16,17,18,19]

])

我认为它与诊断/对角线/跟踪功能有点相似。

我通常通过使用基本迭代来完成这项工作...... numpy 是否具有此功能,因此它可以更快地执行??

【问题讨论】:

  • @eat: 第 1 行有“1”非 9999 元素,第 2 行有“3”,第 3 行有“5”,第 4 行有“4”最后一行有“6”。
  • 第一行的 7 个元素显然是个错误?
  • 想展示您的基本迭代代码吗?您正在处理多大的阵列?你真的分析过瓶颈在哪里吗?您期望什么样的性能提升?

标签: python arrays numpy


【解决方案1】:

这里有一些排列数据的方法:

from numpy import arange, array, ones, r_, zeros
from numpy.random import randint

def gen_tst(m, n):
    a= randint(1, n, m)
    b, c= arange(a.sum()), ones((m, n), dtype= int)* 999
    return a, b, c

def basic_1(a, b, c):
    # some assumed basic iteration based
    n= 0
    for k in xrange(len(a)):
        m= a[k]
        c[k, :m], n= b[n: n+ m], n+ m

def advanced_1(a, b, c):
    # based on Svens answer
    cum_a= r_[0, a.cumsum()]
    i= arange(len(a)).repeat(a)
    j= arange(cum_a[-1])- cum_a[:-1].repeat(a)
    c[i, j]= b

def advanced_2(a, b, c):
    # other loopless version
    c[arange(c.shape[1])+ zeros((len(a), 1), dtype= int)< a[:, None]]= b

还有一些时间安排:

In []: m, n= 10, 100
In []: a, b, c= gen_tst(m, n)
In []: 1.* a.sum()/ (m* n)
Out[]: 0.531
In []: %timeit advanced_1(a, b, c)
10000 loops, best of 3: 99.2 us per loop
In []: %timeit advanced_2(a, b, c)
10000 loops, best of 3: 68 us per loop
In []: %timeit basic_1(a, b, c)
10000 loops, best of 3: 47.1 us per loop

In []: m, n= 50, 500
In []: a, b, c= gen_tst(m, n)
In []: 1.* a.sum()/ (m* n)
Out[]: 0.455
In []: %timeit advanced_1(a, b, c)
1000 loops, best of 3: 1.03 ms per loop
In []: %timeit advanced_2(a, b, c)
1000 loops, best of 3: 1.06 ms per loop
In []: %timeit basic_1(a, b, c)
1000 loops, best of 3: 227 us per loop

In []: m, n= 250, 2500
In []: a, b, c= gen_tst(m, n)
In []: 1.* a.sum()/ (m* n)
Out[]: 0.486
In []: %timeit advanced_1(a, b, c)
10 loops, best of 3: 30.4 ms per loop
In []: %timeit advanced_2(a, b, c)
10 loops, best of 3: 32.4 ms per loop
In []: %timeit basic_1(a, b, c)
1000 loops, best of 3: 2 ms per loop

所以基本的迭代似乎很有效。

更新
当然,基于基本迭代的实现的性能仍然可以进一步提高。作为起点建议;例如考虑一下(基于减少加法的基本迭代):

def basic_2(a, b, c):
    n= 0
    for k, m in enumerate(a):
        nm= n+ m
        c[k, :m], n= b[n: nm], nm

【讨论】:

  • 令人印象深刻的证明,所以当使用 numpy 可以比基本循环更快??大尺寸数组有多“大”??
  • @Arief Goldalworming:只是一个演示,但基本上看起来(当前)advanced numpy 对您的情况来说永远不会更快。对于“胖”到“方形”矩阵,简单的迭代似乎总是更快。对于“瘦”到“方形”矩阵也可以证明这一点。 (续...)
  • @Arief Goldalworming:很简单,(典型的现代硬件)的问题是更“高级”的解决方案也需要更多的内存,而简单的迭代(和适当的切片)不需要。所以宁愿在做(看似)更多的计算而不是使用更多的内存方面犯错。但是当然不要忘记用常见的模式来衡量你的实际表现。谢谢
【解决方案2】:

以下是如何使用高级索引在没有任何 Python 循环的情况下执行此操作:

r = numpy.array([1,3,5,4,6])
data = numpy.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19])

result = numpy.empty((len(r), r.max()), data.dtype)
result.fill(9999)
cum_r = numpy.r_[0, r.cumsum()]
i = numpy.arange(len(r)).repeat(r)
j = numpy.arange(cum_r[-1]) - cum_r[:-1].repeat(r)
result[i, j] = data
print result

打印

[[   1 9999 9999 9999 9999 9999]
 [   2    3    4 9999 9999 9999]
 [   5    6    7    8    9 9999]
 [  10   11   12   13 9999 9999]
 [  14   15   16   17   18   19]]

【讨论】:

  • 这与基本迭代相比有多快?根据数组大小,基本迭代可能仍然很容易更有效。 OP应该发布更多细节
  • @eat:当然不可能回答这是否比 OP 的代码快,因为我们不知道 OP 的代码。不过,对于大数组,它会比任何 Python 循环都快,而对于小数组,性能无论如何都不重要。
  • @Arief Goldalworming:在这种规模下,基本迭代可能会快 4 倍。谢谢
【解决方案3】:

Sven 再次击败了我们所有人 :) 接下来是我卑微的尝试,

from numpy import arange,array,split
from numpy import concatenate as cat
from numpy import repeat as rep

a = arange(1,20)

i = array([1,3,5,4,6])
j = max(i) - i

s = split(a,i.cumsum())
z = array([cat((t,rep(9999,k))) for t,k in zip(s[:-1],j)])

print z

交付,

[[   1 9999 9999 9999 9999 9999]
 [   2    3    4 9999 9999 9999]
 [   5    6    7    8    9 9999]
 [  10   11   12   13 9999 9999]
 [  14   15   16   17   18   19]]

【讨论】:

  • FWIW,您的解决方案可能比基于基本迭代的解决方案慢 40 倍(对于 OP 的指示大小和假定的“平均三角形”。谢谢
  • @eat:同意。 timeit 重复 10^6 次,basic_1:30.50s,advanced_1:64.25s,advanced_2:41.90s,lafrasu:388.37s。大约慢 5-12 倍。
猜你喜欢
  • 2012-11-16
  • 2020-06-20
  • 1970-01-01
  • 2010-10-08
  • 2011-08-25
  • 2011-02-01
  • 1970-01-01
  • 2022-07-21
  • 1970-01-01
相关资源
最近更新 更多