matlab:将向量划分为固定大小的重叠块
Posted
技术标签:
【中文标题】matlab:将向量划分为固定大小的重叠块【英文标题】:matlab: dividing vector into overlapping chunks of fixed size 【发布时间】:2014-01-03 18:30:47 【问题描述】:我有一个向量,我想将其拆分为大小为cs
的重叠子向量,以sh
为单位。想象一下输入向量是:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
给定 chunksize
为 4 (cs=4
) 和 shift 为 2 (sh=2
),结果应如下所示:
[1 2 3 4]
[3 4 5 6]
[5 6 7 8]
[7 8 9 10]
[9 10 11 12]
请注意,输入向量不一定能被chunksize
整除,因此会丢弃一些子向量。有没有什么快速的方法来计算它,而不需要使用例如for
循环?
在相关的post 中,我发现了如何做到这一点,但在考虑非重叠子向量时。
【问题讨论】:
【参考方案1】:这个呢?首先,我根据cs
和sh
生成起始索引,用于从全长向量中切出单个向量,然后删除所有idx+cs
超过向量长度的索引,然后我正在切片通过arrayfun
取出单个子向量,然后将它们转换为矩阵:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
cs=4;
sh=2;
idx = 1:(cs-sh):length(v);
idx = idx(idx+cs-1 <= length(v))
A = arrayfun(@(i) v(i:(i+cs-1)), idx, 'UniformOutput', false);
cell2mat(A')
例如对于cs=5; sh=3;
,这将给出:
idx =
1 3 5 7
ans =
1 2 3 4 5
3 4 5 6 7
5 6 7 8 9
7 8 9 10 11
根据值cs; sh
的来源,您可能需要引入一个简单的错误检查,以便cs > 0;
和sh < cs
。 sh < 0
如果您想在两者之间保留一些值,理论上是可能的。
编辑:修复了一个非常小的错误,现在应该针对 sh 和 cs 的不同组合运行。
【讨论】:
我为什么要这样做?它也适用于不同的数字。idx
只应该给我子向量的起始索引,因此我定义。需要 cs-sh 作为步骤 - 编辑:我尝试使用不同的向量和不同数量的 cs
和 sh
并且效果很好。
对于cs=5; sh=3
,我假设起始索引是1 4 7
,而不是1 3 5 7
。如果是这种情况,可以使用idx=1:sh:length(v)
。
抱歉,我得告诉你,这是错误的。只是重新考虑一下。 1 3 5 7
是正确的索引 - 只需看看我的输出矩阵,它显然是正确的(您可以清楚地看到长度为 5(即 5 列),即 chunksize cs=5)和三个重叠条目(最后三个条目每行是下一行的前三个条目)【参考方案2】:
我想最简单的方法实际上是使用循环。 矢量化解决方案可以更快,但如果结果被正确预分配,循环也应该表现得不错。
v = 1:13
cs = 4;
sh = 2;
myMat = NaN(floor((numel(v) - cs) / sh) + 1,cs);
count = 0;
for t = cs:sh:numel(v)
count = count+1;
myMat(count,:) = v(t-cs+1:t);
end
【讨论】:
我不明白为什么这是必要的,尤其是当 Tin 要求没有for
-loop 的解决方案时。
@bjoern:我同意丹尼斯的观点,他的解决方案更简单。 Arrayfun 基本上也是一个 for 循环,在这种情况下甚至更慢。
丹尼斯,我认为你的代码仍然有错误 -> v(t-3:t);
这应该是什么?我的意思是其中缺少关于 cs
的内容,现在您总是获取 3 个错误的条目
这也是我第一次更改以纠正它,但它仍然有问题,cs = 5; sh = 2;
给了我矩阵中的三个重叠条目,而不是 2
@DennisJaheruddin:我认为您计算块数的方式不正确,请参阅我的答案。您仅根据sh
计算要为myMat
预分配的行数,同时还应包括cs
。对于cs = 10
和sh = 2
,它应该只产生 2 行,而在你的情况下它预分配 5 行。【参考方案3】:
您可以通过以下方式使用函数bsxfun
:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
cs=4;
sh=2;
A = v(bsxfun(@plus,(1:cs),(0:sh:length(v)-cs)'));
这是它的工作原理。 bsxfun
在 2 个数组上应用一些基本功能,如果输入的大小不合适,则执行一些类似 repmat
的功能。在这种情况下,我生成第一个块的索引,并添加每个块的偏移量。由于一个输入是行向量,另一个是列向量,因此结果是一个矩阵。最后,当使用矩阵索引向量时,结果是一个矩阵,这正是您所期望的。
而且它是单行的,(几乎)总是很有趣:)。
【讨论】:
用cs = 5;sh = 2;
试试,会给你三个而不是两个(两个是正确的,因为 sh=2)重叠条目
@bjoern 正如我在对您的问题的评论中提到的,您的解决方案确实给出了不同的结果。但是,这并不一定意味着它是正确的。
好的,现在我明白你指的是什么了。我 100% 确定 sh
描述了重叠条目的数量,但现在我看到你们都将其称为另一种衡量标准。对不起,我的错,真的一定错过了哦,我现在才看到描述不是唯一的,因为发布的例子是模棱两可的
one-liner bsxfun
(几乎)总是值得 +1!【参考方案4】:
您有信号处理工具箱吗?那么命令是buffer
。先看一下裸输出:
buffer(v, 4, 2)
ans =
0 1 3 5 7 9 11
0 2 4 6 8 10 12
1 3 5 7 9 11 13
2 4 6 8 10 12 0
这显然是正确的想法,只需稍作调整即可为您提供所需的输出:
[y z] = buffer(v, 4, 2, 'nodelay');
y.'
ans =
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 11 12
也就是说,请考虑按列保留向量,因为这样可以更好地匹配大多数用例。例如,每个窗口的平均值只是矩阵的mean
,因为默认是按列排列的。
【讨论】:
我喜欢使用这些没有人知道它已经在工具箱中的小宝石。问题是它可能会在最后一帧中留下部分数据,但这取决于您想要实现的目标。【参考方案5】:您可以通过ndgrid
完成此操作:
>> v=1:13; cs=4; sh=2;
>> [Y,X]=ndgrid(1:(cs-sh):(numel(v)-cs+1),0:cs-1)
>> chunks = X+Y
chunks =
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 11 12
second syntax of the colon
operator (j:i:k
) 的好处是,如果您打算丢弃额外的条目,则不必精确计算 k
(例如,1:2:6
给出 [1 3 5]
),如这个问题。它会自动转到j+m*i
,其中m = fix((k-j)/i)
;
不同的测试:
>> v=1:14; cs=5; sh=2; % or v=1:15 or v=1:16
>> [Y,X]=ndgrid(1:(cs-sh):(numel(v)-cs+1),0:cs-1); chunks = X+Y
chunks =
1 2 3 4 5
4 5 6 7 8
7 8 9 10 11
10 11 12 13 14
然后将形成一个带有v=1:17
的新行。这会根据需要处理所有情况吗?
【讨论】:
以上是关于matlab:将向量划分为固定大小的重叠块的主要内容,如果未能解决你的问题,请参考以下文章