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

Python如何将不同长度的多个数组添加到一个数组中,python,numpy,Python,Numpy,我正在开发一个程序,需要将音频阵列与给定的起始索引混合在一起。比如说 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) 基于起始,信号2将从索引2添加到信号1,信号3将从索引8添加到混合

我正在开发一个程序,需要将音频阵列与给定的起始索引混合在一起。比如说

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)
基于起始,信号2将从索引2添加到信号1,信号3将从索引8添加到混合,因此混合部分将被零填充。它应返回:

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

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
然而,这可能相当缓慢,特别是当有许多信号以不同的方式混合在一起时。如果有更有效的方法,请提供建议

非常感谢

J



以下是一个可以达到目的的尝试

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]
def信号\u加法器\u与\u开始(数据,开始):
#获取每行数据的长度
镜头=np.阵列([len(i)表示数据中的i])
#调整最大可能长度的偏移量
最大尺寸=镜头+开始
#每行中有效位置的掩码
掩码=((np.arange(max_size.max())>=start.reformate(-1,1))
&(np.arange(max_size.max())<(晶状体+起始)。重塑(-1,1)))
#设置输出数组并将数据中的元素放入屏蔽位置
out=np.zeros(mask.shape,dtype=data.dtype)#可能会在这里更改dtype
out[mask]=np.连接(数据)
返回。总和(轴=0)
将numpy作为np导入
signal1=np.数组([1,2,3,4])
signal2=np.数组([5,5,5])
信号3=np.数组([7,7,7,7])
sig=np.数组([signal1,signal2,signal3])
开始=np.数组((0,2,8))
结果=具有起始信号的信号加法器(sig,起始)
打印(结果)
#[1 2 8 9 5 0 0 0 7 7 7 7]

编辑:矢量化操作只在数据较多时启动,而在数据较少时启动较慢

添加以供比较

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]
导入时间
def信号_加法器_与_开始(数据,开始):
#获取每行数据的长度
镜头=np.阵列([len(i)表示数据中的i])
#调整最大可能长度的偏移量
最大尺寸=镜头+开始
#每行中有效位置的掩码
掩码=((np.arange(max_size.max())>=start.reformate(-1,1))
&(np.arange(max_size.max())<(晶状体+起始)。重塑(-1,1)))
#设置输出数组并将数据中的元素放入屏蔽位置
out=np.zeros(mask.shape,dtype=data.dtype)#可能会在这里更改dtype
out[mask]=np.连接(数据)
返回。总和(轴=0)
def混合_功能(信号,开始):
maxlen=np.max([o+len表示o,s在zip中(起始,sig)])
结果=np.零(最大值)
对于范围内的i(len(开始)):
结果[发病[i]:发病[i]+len(sig[i])]+=sig[i]
返回结果
将numpy作为np导入
signal1=np.数组([1,2,3,4])
signal2=np.数组([5,5,5])
信号3=np.数组([7,7,7,7])
sig=np.数组([signal1,signal2,signal3])
sig=np.重复(sig,1000000)
开始=np.数组((0,2,8))
开始=np.重复(开始,1000000)
start1=time.time()
结果=具有起始信号的信号加法器(sig,起始)
end1=time.time()
start2=time.time()
结果2=混合功能(sig,开始)
end2=time.time()
打印(f“原始函数:{end2-start2}\n矢量化函数:{end1-start1}”)
打印(结果)
#输出:
原始功能:9.28258752876
矢量化函数:2.5798118114471436
[1000000 2000000 8000000 9000000 5000000 0 0 0 7000000 7000000 7000000
7000000]

如果偏移信号,然后将其放入数据帧中,
NaN
将添加到列中,以使所有行的长度相同。然后可以执行
df.sum()
。但是,这将返回一个浮点而不是int。

尝试插入适当信号的等长numpy zero数组,只需执行3个numpy数组加法。应该会大大加快速度

def mixing_function(sig,onset):
    maxlen = np.max([o + len(s) for o, s in zip(onset, sig)])
    sig1 = np.zeros(maxlen)
    sig2 = np.zeros(maxlen)
    sig3 = np.zeros(maxlen)
    sig1[onset[0]:onset[0] + len(sig[0])] = sig[0]
    sig2[onset[1]:onset[1] + len(sig[1])] = sig[1]
    sig3[onset[2]:onset[2] + len(sig[2])] = sig[2]
    result = sig1+sig2+sig3
    print(sig1)
    print(sig2)
    print(sig3)
    print(result)

下面是一些针对该问题的不同解决方案的统计数据。我能够通过矢量化实现来获得maxlen,从而压缩一点性能,但除此之外,我认为您必须尝试cython或其他编程语言

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)
将numpy导入为np
从numba导入jit
从时间导入时间
np.随机种子(42)
def混合_功能(信号,开始):
maxlen=np.max([o+len表示o,s在zip中(起始,sig)])
结果=np.零(最大值)
对于范围内的i(len(开始)):
结果[发病[i]:发病[i]+len(sig[i])]+=sig[i]
返回结果
def混合液(信号,开始):
sigLength=np.矢量化(len)(sig)
最大长度=最大值(起始长度+最大长度)
结果=np.零(最大值)
对于范围内的i(len(sig)):
结果[开始[i]:开始[i]+sig长度[i]+=sig[i]
返回结果
@jit(nopython=True)
def mixnumba(信号,开始):
#maxlen=np.max([start[i]+len(sig[i]),用于范围内的i(len(sig)))
maxlen=-1
对于范围内的i(len(sig)):
maxlen=max(maxlen,sig[i]。大小+起始值[i])
结果=np.零(最大值)
对于范围内的i(len(sig)):
结果[发病[i]:发病[i]+sig[i]。大小]+=sig[i]
返回结果
def信号_加法器_与_开始(数据,开始):
data=np.array(数据)
#获取每行数据的长度
镜头=np.阵列([len(i)表示数据中的i])
#调整最大可能长度的偏移量
最大尺寸=镜头+开始
#每行中有效位置的掩码
掩码=((np.arange(max_size.max())>=start.reformate(-1,1))
&(np.arange(max_size.max())<(晶状体+起始)。重塑(-1,1)))
#设置输出数组并将数据中的元素放入屏蔽位置
out=np.zeros(mask.shape,dtype=data.dtype)#可能会在这里更改dtype
out[mask]=np.连接(数据)
返回。总和(轴=0)
sigbig=[np.random.randn(np.random.randint(100010000))表示范围(10000)]
onsetbig=np.random.randint(0,10000,size=10000)
sigmeat=np.repeat(sig,500000).tolist()
onsetrepeat=np.重复(开始,500000)
断言全部(混合_函数(sigbig,onsetbig)=mix(sigbig,onsetbig))
断言全部(混合_函数(sigbig,onsetbig)=mixnumba(sigbig,onsetbig))
断言全部(混合_函数(sigbig,onsetbig)=信号_