首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python如何将不同长度的多个数组添加到一个数组中

Python如何将不同长度的多个数组添加到一个数组中
EN

Stack Overflow用户
提问于 2019-03-29 03:16:00
回答 4查看 1.3K关注 0票数 3

我正在工作的程序,需要混合音频阵列与给定的起始索引在一起。例如

代码语言:javascript
复制
signal1 = np.array([1,2,3,4])
signal2 = np.array([5,5,5])
signal3 = np.array([7,7,7,7])
sig = np.array([signal1,signal2,signal3])
onset(0, 2, 8)
result = mixing_function(sig,onset)

根据起始,signal2将从索引2添加到signal1,signal3将从索引8添加到混合,因此混合部分将是零填充。它应该返回:

代码语言:javascript
复制
[1,2,8,9,5,0,0,0,7,7,7,7]

我不确定为此编写代码的有效方法是什么。现在,我创建了一个最大长度为maxlen的零数组。然后我将sig中的每个元素添加到结果的相应索引范围中:

代码语言:javascript
复制
def mixing_function(sig,onset):
    maxlen = np.max([o + len(s) for o, s in zip(onset, sig)])
    result =  np.zeros(maxlen)
    for i in range(len(onset)):
        result[onset[i]:onset[i] + len(sig[i])] += sig[i] 
    return result

然而,这可能是相当慢的,特别是当有许多信号混合在一起都具有不同的onset时。如果有更有效的方法,请指教。

非常感谢

J

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-03-29 06:27:39

以下是该问题的不同解决方案的一些统计数据。我可以通过对实现进行矢量化来获得maxlen,以获得更高的性能,但除此之外,我认为您必须尝试cython或尝试其他编程语言。

代码语言:javascript
复制
import numpy as np
from numba import jit
from time import time
np.random.seed(42)

def mixing_function(sig, onset):
    maxlen = np.max([o + len(s) for o, s in zip(onset, sig)])
    result =  np.zeros(maxlen)
    for i in range(len(onset)):
        result[onset[i]:onset[i] + len(sig[i])] += sig[i] 
    return result

def mix(sig, onset):
    siglengths = np.vectorize(len)(sig)
    maxlen = max(onset + siglengths)
    result = np.zeros(maxlen)
    for i in range(len(sig)):
        result[onset[i]: onset[i]+siglengths[i]] += sig[i]
    return result

@jit(nopython=True)
def mixnumba(sig, onset):
    # maxlen = np.max([onset[i] + len(sig[i]) for i in range(len(sig))])
    maxlen = -1
    for i in range(len(sig)):
        maxlen = max(maxlen, sig[i].size + onset[i])
    result = np.zeros(maxlen)
    for i in range(len(sig)):
        result[onset[i]: onset[i] + sig[i].size] += sig[i]
    return result

def signal_adder_with_onset(data, onset):
    data = np.array(data)
    # Get lengths of each row of data
    lens = np.array([len(i) for i in data])
    #adjust with offset for max possible lengths
    max_size = lens + onset
    # Mask of valid places in each row
    mask = ((np.arange(max_size.max()) >= onset.reshape(-1, 1)) 
            &  (np.arange(max_size.max()) < (lens + onset).reshape(-1, 1)))

    # Setup output array and put elements from data into masked positions
    out = np.zeros(mask.shape, dtype=data.dtype) #could perhaps change dtype here
    out[mask] = np.concatenate(data)
    return out.sum(axis=0)

sigbig = [np.random.randn(np.random.randint(1000, 10000)) for _ in range(10000)]
onsetbig = np.random.randint(0, 10000, size=10000)
sigrepeat = np.repeat(sig, 500000).tolist()
onsetrepeat = np.repeat(onset, 500000)

assert all(mixing_function(sigbig, onsetbig) == mix(sigbig, onsetbig))
assert all(mixing_function(sigbig, onsetbig) == mixnumba(sigbig, onsetbig))
assert all(mixing_function(sigbig, onsetbig) == signal_adder_with_onset(sigbig, onsetbig))

%timeit result = mixing_function(sigbig, onsetbig)
%timeit result = mix(sigbig, onsetbig)
%timeit result = mixnumba(sigbig, onsetbig)
%timeit result = signal_adder_with_onset(sigbig, onsetbig)
# Output
114 ms ± 1.97 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
108 ms ± 2.53 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
368 ms ± 8.22 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
13.4 s ± 211 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit result = mixing_function(sigrepeat, onsetrepeat)
%timeit result = mix(sigrepeat, onsetrepeat)
%timeit result = mixnumba(sigrepeat, onsetrepeat)
%timeit result = signal_adder_with_onset(sigrepeat.tolist(), onsetrepeat)
# Output
933 ms ± 6.43 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
803 ms ± 21.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
4.07 s ± 85.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
254 ms ± 11.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

TL.DR。通过使用np.vectorize来获得随机长度的长信号的maxlen,从而实现了性能的边际提升(大约快了10% )。请注意,对于许多小信号,@Paritosh Singh answer比其他答案执行得更快。

票数 2
EN

Stack Overflow用户

发布于 2019-03-29 04:20:58

这里有一个尝试,应该可以做到这一点。

代码语言:javascript
复制
def signal_adder_with_onset(data, onset):
    # Get lengths of each row of data
    lens = np.array([len(i) for i in data])
    #adjust with offset for max possible lengths
    max_size = lens + onset
    # Mask of valid places in each row
    mask = ((np.arange(max_size.max()) >= onset.reshape(-1, 1)) 
            &  (np.arange(max_size.max()) < (lens + onset).reshape(-1, 1)))

    # Setup output array and put elements from data into masked positions
    out = np.zeros(mask.shape, dtype=data.dtype) #could perhaps change dtype here
    out[mask] = np.concatenate(data)
    return out.sum(axis=0)

import numpy as np
signal1 = np.array([1,2,3,4])
signal2 = np.array([5,5,5])
signal3 = np.array([7,7,7,7])
sig = np.array([signal1,signal2,signal3])
onset = np.array((0, 2, 8))
result = signal_adder_with_onset(sig, onset)
print(result)
#[1 2 8 9 5 0 0 0 7 7 7 7]

编辑:矢量化操作只在数据量较大的情况下生效,而在数据量较小的情况下速度较慢。

添加以供比较

代码语言:javascript
复制
import time

def signal_adder_with_onset(data, onset):
    # Get lengths of each row of data
    lens = np.array([len(i) for i in data])
    #adjust with offset for max possible lengths
    max_size = lens + onset
    # Mask of valid places in each row
    mask = ((np.arange(max_size.max()) >= onset.reshape(-1, 1)) 
            &  (np.arange(max_size.max()) < (lens + onset).reshape(-1, 1)))

    # Setup output array and put elements from data into masked positions
    out = np.zeros(mask.shape, dtype=data.dtype) #could perhaps change dtype here
    out[mask] = np.concatenate(data)
    return out.sum(axis=0)

def mixing_function(sig,onset):
    maxlen = np.max([o + len(s) for o, s in zip(onset, sig)])
    result =  np.zeros(maxlen)
    for i in range(len(onset)):
        result[onset[i]:onset[i] + len(sig[i])] += sig[i] 
    return result

import numpy as np
signal1 = np.array([1,2,3,4])
signal2 = np.array([5,5,5])
signal3 = np.array([7,7,7,7])
sig = np.array([signal1,signal2,signal3])
sig = np.repeat(sig, 1000000)
onset = np.array((0, 2, 8))
onset = np.repeat(onset, 1000000)
start1 = time.time()
result = signal_adder_with_onset(sig, onset)
end1 = time.time()
start2 = time.time()
result2 = mixing_function(sig,onset)
end2 = time.time()
print(f"Original function: {end2 - start2} \n Vectorized function: {end1 - start1}")
print(result)
#Output:
Original function: 9.28258752822876 
 Vectorized function: 2.5798118114471436
[1000000 2000000 8000000 9000000 5000000 0 0 0 7000000 7000000 7000000
 7000000]
票数 0
EN

Stack Overflow用户

发布于 2019-03-29 04:29:01

如果对信号进行偏移,然后将它们放入数据框中,则会将NaN添加到列中,以使所有行的长度相同。然后你可以做df.sum()。然而,这将返回一个浮点型而不是整型。

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

https://stackoverflow.com/questions/55405295

复制
相关文章

相似问题

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