如何使用递减来拉伸numpy数组的特定项?

3
给定边界值 k,有一种向量化的方法来将每个数字 n 替换为从 n-1k 的连续递减数?例如,如果 k 是 0,则想要用 np.array([3,4,2,2,1,3,1]) 替换它,结果是 np.array([2,1,0,3,2,1,0,1,0,1,0,0,2,1,0,0])。输入数组的每个项都大于k
我尝试了 np.repeatnp.cumsum 的组合,但似乎不是理想的解决方案:
x = np.array([3,4,2,2,1,3,1])
y = np.repeat(x, x)
t = -np.ones(y.shape[0])
t[np.r_[0, np.cumsum(x)[:-1]]] = x-1
np.cumsum(t)

还有其他方法吗?我希望像 np.add.reduceat 的逆运算,它可以将整数广播到递减的序列而不是最小化它们。

2个回答

2
这里有另一种使用数组赋值来跳过重复部分的方法 -
def func1(a):
    l = a.sum()
    out = np.full(l, -1, dtype=int)
    out[0] = a[0]-1
    idx = a.cumsum()[:-1]
    out[idx] = a[1:]-1
    return out.cumsum()

基准测试

# OP's soln
def OP(x):
    y = np.repeat(x, x)
    t = -np.ones(y.shape[0], dtype=int)
    t[np.r_[0, np.cumsum(x)[:-1]]] = x-1
    return np.cumsum(t)

使用 benchit 包(多个基准测试工具打包在一起;免责声明:我是其作者)来对提出的解决方案进行基准测试。
import benchit

a = np.array([3,4,2,2,1,3,1])
in_ = [np.resize(a,n) for n in [10, 100, 1000, 10000]]
funcs = [OP, func1]
t = benchit.timings(funcs, in_)
t.plot(logx=True, save='timings.png')

enter image description here

Extend to take k as arg

def func1(a, k):
    l = a.sum()+len(a)*(-k)
    out = np.full(l, -1, dtype=int)
    out[0] = a[0]-1
    idx = (a-k).cumsum()[:-1]
    out[idx] = a[1:]-1-k
    return out.cumsum()

样例运行 -

In [120]: a
Out[120]: array([3, 4, 2, 2, 1, 3, 1])

In [121]: func1(a, k=-1)
Out[121]: 
array([ 2,  1,  0, -1,  3,  2,  1,  0, -1,  1,  0, -1,  1,  0, -1,  0, -1,
        2,  1,  0, -1,  0, -1])

所以,numpy 功能中没有任何隐藏的方法或途径,正如我一直在等待的那样。虽然 2 倍的加速效果更好,但感谢您的合作。这帮助我将 itertools.combinations 的速度提高了 1.5 倍! - mathfux

0

这是简洁的,对于效率来说可能还可以;我认为这里的apply没有向量化,因此您将主要受限于原始数组中元素的数量(我猜它们的值不太重要):

import pandas as pd
x = np.array([3,4,2,2,1,3,1])

values = pd.Series(x).apply(lambda val: np.arange(val-1,-1,-1)).values
output = np.concatenate(values)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接