可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm having great difficulty coding the following in MATLAB:
Suppose you have the following vector:
a
b
c
d
e
f
g
h
...
Specifying an (even) window size, create the following matrix of dimensions L
rows by n
columns (example, L = 4
):
a c e ...
b d f ...
c e g ...
d f h ...
Even more difficult is taking a vector of arbitrary length, specifying the number of windows, and optimizing (maximizing) the window size so less values at the end of the vector are dumped.
回答1:
Create the matrix of indices into your vector. For L=4 (I assume you are overlapping by L/2), the indices are [1,2,3,4;3,4,5,6;5,6,7,8] etc. Let x = 1:L, y = L/2, the vector of indices is x+0y,x+1y,x+2y, and so on.
% 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
回答2:
Short answer
bsxfun
is your friend in this case. The following one-liner (assuming you know L
and v
is your vector) does what you want
v(bsxfun(@plus, [0:L-1]', 1:L/2:numel(v)-L))
Explanation
To try it out and understand it, lets have a further look. The idea is to first create a vector that determines, where the windows start in the v
vector. Windows start every L/2
entries (L
is even, so we can divide). But how many windows fit? We can rely on MATLAB to figure this out by saying:
start_offset = 1:L/2:numel(v)-L;
Here we just only need to specify that
- first window is at at index 1
- windows start every
L/2
entries
- the last window should start at least L entries before the end of the v vector. So that the last window fist in there.
Now, the rest of the example:
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
回答3:
Here's a general way to do what you want:
1) Calculate the appropriate window width (and corresponding shift)
2) Determine the start indices of each column by iterating from 1 by the amount you want to shift the window each column, up to the final value. Make this a row vector.
3) Use bsxfun
to expand this to a matrix of indices.
4) Use the indices to get the values from the original vector.
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
回答4:
There are many ways to do this in MATLAB by manipulating indices, procedural approaches, vectorized solutions, etc. Yet, I can't help but think of how simple some tasks might be, if MATLAB had a wee bit of support for functional style of programming. In that spirit, I present the following solution. Ensure that you don't already have any values in those variables at definition time.
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))
Now try it with a test vector:
partition(1:10,4)
%ans =
% 1 3 5 7
% 2 4 6 8
% 3 5 7 9
% 4 6 8 10
The above solution discards the final values at the end of the vector that don't fit a length L
after partition. You can now build up on this to handle other arrangements and figure out optimal window lengths for minimal end wastage, etc.