MATLAB: Remove n last rows from matrix without loop - matlab

I have a problem with removing surplus rows in the end of the matrix. In general, I need to remove rows that contain a specific elements in a specific column, without using a loop. It seems easy but I still keep on getting some weird outcomes.
For simple example, let's have a 10x10 matrix A:
A=[1:10; 901:910; 201:210; 301:310; 701:710; 401:410; 601:610; 501:510; 801:810; 101:110];
And I want to remove (for better illustration just replace with ones) that rows from fourth to the last, whose third columns contain value higher than 600. Result should look like that:
| 1 2 3 4 5 6 7 8 9 10|
|901 902 903 904 905 906 907 908 909 910|
|201 202 203 204 205 206 207 208 209 210|
|301 302 303 304 305 306 307 308 309 310|
| 1 1 1 1 1 1 1 1 1 1|
|401 402 403 404 405 406 407 408 409 410|
| 1 1 1 1 1 1 1 1 1 1|
|501 502 503 504 505 506 507 508 509 510|
| 1 1 1 1 1 1 1 1 1 1|
|101 102 103 104 105 106 107 108 109 110|
My idea looks like that:
A(A(4:end,3)>600,:)=[1];
But the outcome is some nonsense matrix.
Thanks for your help!

A([false(3,1);A(4:end,3)>600],:)=1;
and as #yoda said, to remove the rows do:
A([false(3,1);A(4:end,3)>600],:)=[];

Firstly your problem is that entering a matrix inside a matrix means use the values of the matrix as indices. since your matrix only has zeros and ones (as a result of the "<" operator) you got a weird result.
To answer your question, you need to replace the matrix with a smaller matrix. something like:
A = new_matrix
new_matrix is generated out of A by taking only the rows you want.
new_matrix = A(row_indices, :)
Where row_indices is the vector of indices you want to keep. To build that you can start with a zeros-ones vector and apply find (which will yield the indices with ones). So we want:
row_indices = find([1,1,1, A(4:end,3).'<600])
The first 3 ones are because you always want the first 3 lines.
So putting everything together gives
A = A(find([1,1,1,A(4:end,3).'<600]),:)
Running this on your example values :
>> A=[1:10; 901:910; 201:210; 301:310; 701:710; 401:410; 601:610; 501:510; 801:810; 101:110];
>> A(find([1,1,1,A(4:end,3).'<600]),:)
ans =
1 2 3 4 5 6 7 8 9 10
901 902 903 904 905 906 907 908 909 910
201 202 203 204 205 206 207 208 209 210
301 302 303 304 305 306 307 308 309 310
401 402 403 404 405 406 407 408 409 410
501 502 503 504 505 506 507 508 509 510
101 102 103 104 105 106 107 108 109 110
BTW, changing these rows to ones is just as easy:
A(find([0,0,0,A(4:end,3).'>600]),:) = 1

Related

error reading a text file in octave

I have a text file named xMat.txt which has 200 space separated elements in one line and some 767 lines.
This is how xMat.txt looks.
386.0 386.0 388.0 394.0 402.0 413.0 ... .0 800.0 799.0 796
801.0 799.0 799.0 802.0 802.0 80 ... 399.0 397.0 394.0 391
.
.
.
When I try to read the file in octave using X = dlmread('xMat.txt',' ') I get a matrix of size 767 X 610. I am expecting a matrix of size 767 X 200 since there are 200 elements in one row. How can I solve this problem?
Edit - This is my file
Your uploaded file https://bpaste.net/raw/96cf21aa21b8 has incosistent number of columns per row.
$ awk "{print NF}" tmp | sort | uniq -c
2 200
754 201
1 206
1 217
1 223
1 234
1 237
1 238
1 269
1 273
1 390
1 420
1 610
So the most rows have 201 columns but one has 420 columns and one even has 610 columns. This is the reason you get a 767x610 matrix from dlmread.
Lets look which lines have more than 201 columns:
$ awk "{if (NF>201) print NR, NF}" tmp
68 217
580 206
613 390
615 234
657 273
676 610
679 237
720 269
722 238
743 223
762 420
The first coloumn shows the line number, the second number of columns.
So your line with 610 columns is line number 676. I aslo printed line 676:
so you see it really contains data, no multiple spaces which are filles with zeros.

MATLAB accessing conditional values and performing operation in single column

Just started MATLAB 2 days ago and I can't figure out a non-loop method (since I read they were slow/inefficient and MATLAB has better alternatives) to perform a simple task.
I have a matrix of 5 columns and 270 rows. What I want to do is:
if the value of an element in column 5 of matrix goodM is below 90, I want to take that element and and subtract it from 90.
So far I tried:
test = goodM(:,5) <= 90;
goodM(test) = 999;
It changes all goodM values within column 1 not 5 into 999, in addition this method doesn't allow me to perform operations on the elements below 90 in column 5. Any elegant solution to doing this?
edit:: goodM(:,5)(test) = 999; doesn't seem to work either so I have no idea to specify the target column.
I am assuming you are looking to operate on elements that have values below 90 as your text in the question reads, rather than 'below or equal to' as represented by '<=' as used in your code. So try this -
ind = find(goodM(:,5) < 90) %// Find indices in column 5 that have values less than 90
goodM(ind,5) = 90 - goodM(ind,5) %// Operate on those elements using indices obtained from previous step
Try this code:
b=90-a(a(:,5)<90,5);
For example:
a =
265 104 479 13 176
26 110 447 208 144
379 163 179 366 464
301 48 274 391 26
429 374 174 184 297
495 375 312 373 82
465 272 399 447 420
205 170 373 122 84
1 417 63 65 252
271 277 412 113 500
then,
b=90-a(a(:,5)<90,5);
b =
64
8
6

How two reshape two columns into multiple columns in matlab

Does anyone know how I can reshape these two columns:
1 1
1 1
1 1
379 346
352 363
330 371
309 379
291 391
271 402
268 403
1 1
1 1
406 318
379 334
351 351
329 359
307 367
287 378
267 390
264 391
into these four columns:
1 1 1 1
1 1 1 1
1 1 406 318
379 346 379 304
352 363 351 351
330 371 329 359
309 379 307 367
291 391 287 378
271 402 267 390
268 403 264 391
That is, how to reshape a matrix that is the size of Nx2 into a size 10xM in matlab?
One solution using mat2cell, splitting every 10 rows. Probably easier to understand, because no 3d-matrices are used:
cell2mat(mat2cell(x,repmat(10,size(x,1)/10,1),size(x,2))')
Second solution using reshape and permute, should be faster but I did not try it.:
reshape(permute(reshape(x,10,[],size(x,2)),[1,3,2]),10,[])

Multidimensional scaling matrix error

I'm trying to use multidimensional scaling in Matlab. The goal is to convert a similarity matrix to scatter plot (in order to use k-means).
I've got the following test set:
London Stockholm Lisboa Madrid Paris Amsterdam Berlin Prague Rome Dublin
0 569 667 530 141 140 357 396 570 190
569 0 1212 1043 617 446 325 423 787 648
667 1212 0 201 596 768 923 882 714 714
530 1043 201 0 431 608 740 690 516 622
141 617 596 431 0 177 340 337 436 320
140 446 768 608 177 0 218 272 519 302
357 325 923 740 340 218 0 114 472 514
396 423 882 690 337 272 114 0 364 573
569 787 714 516 436 519 472 364 0 755
190 648 714 622 320 302 514 573 755 0
I got this dataset from the book Modern Multidimensional Scaling (Borg & Groenen, 2005). Tested it in SPSS using the PROXSCAL MDS method and I get the same result as stated in the book.
But I need to use MDS in Matlab in order to speed up the process. The tutorial on the site: http://www.mathworks.nl/help/stats/multidimensional-scaling.html#briu08r-4 looks the same as what I'm using above. When I change the data set as what is displayed above and run the code I get the following error: "Not a valid dissimilarity or distance matrix.".
I'm not sure what I'm doing wrong, and if classical MDS is the right choice. I also miss the possibility to say that I want the result in three dimensions (this will be needed in a later stage).
Your matrix is not symetric, check the indices (9,1) and (1,9). To quickly find asymetric indices use [x,y]=find(~(D'==D))

Shifting rows of matrix in matlab

I have to shift certain rows in matlab. Like let say I have a matrix of size 50x50. And I have to shift certain rows lets say 15,18,45.. to the top and the remaining rows at the bottom. How can I accomplish this in matlab?
Have you tried the circshift function? Something like this could help:
A = [1:8; 11:18; 21:28; 31:38; 41:48]
A =
1 2 3 4 5 6 7 8
11 12 13 14 15 16 17 18
21 22 23 24 25 26 27 28
31 32 33 34 35 36 37 38
41 42 43 44 45 46 47 48
B = circshift(A, [3, 0])
B =
21 22 23 24 25 26 27 28
31 32 33 34 35 36 37 38
41 42 43 44 45 46 47 48
1 2 3 4 5 6 7 8
11 12 13 14 15 16 17 18
This is a problem that can be quite easily solved with the help of some simple indexing:
Matrix = [ 1 101 201 301
2 102 202 302
3 103 203 303
4 104 204 304
5 105 205 305
6 106 206 306
7 107 207 307
8 108 208 308
9 109 209 309
10 110 210 310];
rowsOnTop = [1 8 4];
rowsBelow = true(size(Matrix,1),1);
rowsBelow(rowsOnTop) = false;
Modified = [Matrix(rowsOnTop,:); Matrix(rowsBelow,:)]
Modified =
1 101 201 301
8 108 208 308
4 104 204 304
2 102 202 302
3 103 203 303
5 105 205 305
6 106 206 306
7 107 207 307
9 109 209 309
10 110 210 310
I understood that you want to move certain rows of matrix to the top and keep the rest on its place. For that you can use this:
Example matrix:
Matrix = [ 1:10; 101:110; 201:210; 301:310 ]';
Matrix =
1 101 201 301
2 102 202 302
3 103 203 303
4 104 204 304
5 105 205 305
6 106 206 306
7 107 207 307
8 108 208 308
9 109 209 309
10 110 210 310
Here's the code:
RowsVector = [ 3, 5, 8 ];
Edit: new better solution (presented here first because it's better).
NewMatrix = Matrix(cell2mat(arrayfun(#(x) x:size(Matrix,1):prod(size(Matrix)), [ RowsVector, setdiff(1:size(Matrix, 1), RowsVector) ]', 'UniformOutput', false)));
NewMatrix =
3 103 203 303
5 105 205 305
8 108 208 308
1 101 201 301
2 102 202 302
4 104 204 304
6 106 206 306
7 107 207 307
9 109 209 309
10 110 210 310
Edit: the rest of the answer is related to a [limited] older solution.
% RowsVector must be sorted, otherwise the reordering will fail.
Edit: fixed a bug with unordered RowsVector input.
RowsVector = sort(RowsVector);
for RowIndex = 1:size(RowsVector, 2)
row = RowsVector(RowIndex);
Matrix = vertcat(Matrix(row,:), Matrix);
Matrix(row+1,:) = [];
end
This is the result:
Matrix =
8 108 208 308
5 105 205 305
3 103 203 303
1 101 201 301
2 102 202 302
4 104 204 304
6 106 206 306
7 107 207 307
9 109 209 309
10 110 210 310
I'd solve this by defining a row permutation matrix to produce the desired result. If Matlab has a built-in function for this it escapes me, so I wrote one:
function P = rowpermat(vec)
P = zeros(length(vec));
for i = 1:length(vec)
P(i,vec(i)) = 1;
end
If vec is a permutation of 1:n this function will return a matrix which permutes the rows of an nxn matrix 1->vec(1), 2->vec(2), ... Note the absence of error checking and the like so use this in production code at your own risk.
In this case, if A is the matrix to permute, you might write:
rowpermat([15, 18, 45, 1:14,16:17,19:44,46:50])*A