通过重复叠加向量创建矩阵

4
我是一名有用的助手,可以为您翻译文本。

我在MATLAB中编写以下内容时遇到了很大的困难: 假设您有以下向量:

a   
b
c
d
e
f
g
h
...

指定一个(偶数)窗口大小,创建以下尺寸矩阵Ln列(例如,L=4):

a c e ...
b d f ...
c e g ...
d f h ...

更加困难的是,需要处理任意长度的向量,指定窗口数量,并优化(最大化)窗口大小,使得向量末尾被丢弃的值更少。


窗口位置是否总是在列之间移动2个位置?还是基于窗口大小?或者是额外的输入?另外,您能否澄清一下“向量末尾的值被丢弃”是什么意思?谢谢! - Brian L
1
窗口位置向右移动L/2。例如,窗口大小L = 8,则向右移动4。 指定窗口大小L。 例如,如果向量的长度为9,并且L设置为4,则只能重叠三次:{a b c d} {c d e f} {e f g h} {i}(此值i被丢弃,因为无法形成另一个完整的窗口) - janon128
2
提交的任何答案对您有用吗?如果是,请花些时间接受(并可能点赞)最佳(在您看来)答案。这将激励人们在将来帮助您。 - angainor
4个回答

4

创建指向您的向量的索引矩阵。对于L=4(我假设您重叠了L/2),索引为[1,2,3,4; 3,4,5,6; 5,6,7,8]等。让x = 1:L,y = L/2,索引向量是x+0y,x+1y,x+2y等。

% let your initial data be in vector "data"
L = 4
N = floor(length(data)/(L/2))-1 % number of windows, or you specify this
mi = repmat(1:L,[N,1]) + repmat((L/2) * (0:(N-1))',[1,L]) % x + y * 0,1,2...
out = data(mi) % out is N-by-L, transpose to L-by-N if you like

如果您将x和y的定义与问题中的输出格式相匹配,我会更喜欢这个答案。 - Brian L
@BrianL 我倾向于将较长的维度放在第一位。交换输出的维度很容易,只需使用 out = out',或者将最后一行改为 out = data(mi)'。 - engineerC

4

简短回答

bsxfun 在这种情况下非常有用。以下的一行式代码(假设您知道 Lv 是您的向量)可以完成你想要的操作。

v(bsxfun(@plus, [0:L-1]', 1:L/2:numel(v)-L))

解释

为了试用并理解它,让我们再进一步了解一下。首先要创建一个向量来确定窗口在v向量中的起始位置。窗口每隔L/2个条目开始(L是偶数,所以我们可以除以2)。但有多少个窗口适合呢?我们可以依靠MATLAB来解决这个问题,方法如下:

start_offset = 1:L/2:numel(v)-L;

在这里我们只需要指定:

  • 第一个窗口位于索引1
  • 窗口从每L/2个条目开始
  • 最后一个窗口应该在v向量末尾的至少L个条目之前开始。这样最后一个窗口就可以放在那里。

现在,让我们看下面的例子:

v = 'a':'z';
L = 4;

% indices in every output matrix column are contiguous
% and the difference between first and last is `L-1`
id1 = [0:L-1]';

% start_offset determines where in the input vector v every window starts.
% windows start every L/2 entries. The last entry that fits will start
% at some index, from which we can still use L subsequent indices to access v
start_offset = 1:L/2:numel(v)-L;

% calculate how many entries were dropped from v
% from number of elements in v subtract the largest index value used
dropped = numel(v) - (start_offset+L-1);

% window indices are created using bsxfun and singleton expansion.
% Every window's indices are given by [0:L-1] + window start index
idx = bsxfun(@plus, id1, start_offset);

v(x)

ans =

  acegikmoqsu
  bdfhjlnprtv
  cegikmoqsuw
  dfhjlnprtvx

2

以下是实现你想要的一般方式:

1) 计算适当的窗口宽度(和相应的平移)
2) 通过从1开始迭代,以每列移动窗口的数量为单位确定每列的起始索引,直到最终值。 将其作为行向量。
3) 使用bsxfun将其扩展为索引矩阵。
4) 使用这些索引获取原始向量中的值。

vec = 1:17; #% original data vector
num_windows = 3; #% specified number of windows
possible_window_length = 1:length(vec);
window_length = possible_window_length(find(possible_window_length +...
    (num_windows-1) * possible_window_length/2 < length(vec),1,'last'));
window_shift = floor(window_length)/2;
window_length = window_shift * 2; #% calculated window length
max_final_start_index = (length(vec)-window_length+1);
start_indices = 1:window_shift:max_final_start_index;
inds = bsxfun(@plus,start_indices,(0:window_length-1)');
soln = vec(inds); #% get the solution
num_excluded_vals = max_final_start_index - start_indices(end)
disp(soln);
num_excluded_vals =  1
disp(soln);
    1    5    9
    2    6   10
    3    7   11
    4    8   12
    5    9   13
    6   10   14
    7   11   15
    8   12   16

1

在MATLAB中,有许多方法可以通过操作索引、过程化方法、向量化解决方案等来实现。然而,我不禁想到如果MATLAB对函数式编程风格提供了一点支持,某些任务可能会变得更加简单。本着这种精神,我提出以下解决方案。请确保在定义时这些变量中没有任何值。

take=@(mat,n)mat(1:n)
partition=@(mat,L)cell2mat(arrayfun(@(x)take(circshift(mat(:),-x*L/2),L),...
        0:fix((length(mat)-L)/2+1)-1,'UniformOutput',0))

现在使用测试向量来尝试一下:

partition(1:10,4)

 %ans = 
 %    1     3     5     7
 %    2     4     6     8
 %    3     5     7     9
 %    4     6     8    10

上述解决方案在分区后丢弃了向量末尾不符合长度L的最终值。您现在可以在此基础上构建其他安排,并找出最小末端浪费的最佳窗口长度等。

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