python - Python如何将多个不同长度的数组添加到一个数组中
问题描述
我正在开发一个程序,该程序需要将音频数组与给定的起始索引混合在一起。例如
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 添加到混合,因此混合部分将被零填充。它应该返回:
[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
然而,这可能会很慢,尤其是当有许多信号混合在一起时,它们都具有不同的起始点。请告知是否有更有效的方法。
非常感谢
Ĵ
解决方案
以下是针对该问题的不同解决方案的一些统计数据。通过对实现进行矢量化以获得 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)
TL.DR。np.vectorize
通过使用以获得maxlen
随机长度的长信号,可以提高边际性能(快 10% 左右) 。请注意,对于许多小信号,@Paritosh Singh 答案的执行速度比其他信号快。
推荐阅读
- python - 删除 XML 中的容器
- java - 在 android studio 中从 firebase 读取多个孩子
- html - Vue 应用程序,未应用 html 和 body 元素的样式,我使用的是 SCSS
- sql-server - 如何使用 T-SQL XML modify('replace value of ...)' 搜索/替换空白属性
- c# - ImplicitlyExpandDesignTimeFacades 在 csporj 中到底做了什么(C# - Visual Studio 2015)
- c# - Elasticsearch NEST 提升现有查询
- ionic-framework - 如何映射 videogular2 视频列表
- c - 为什么巴塞尔问题总是显示相同的数字?
- c++ - CLion 无法识别 c++17 功能
- ruby-on-rails - 具有不同重定向的多个保存按钮