I have a 2x100 matrix. It contains 100 elements from 2 different classes. So each element consists of the value itself and the label with the class it belongs to(1 or 2). I want to mix this data into another 2x100 matrix, where the values stay still connected to their labels.
An example with a 2x5 matrix would be:
A=[1 2 3 4 5;
1 2 2 2 1]
After mixing:
A=[2 3 5 1 4;
2 2 1 1 2]
How can I do this? Thanks!
You can index the entire columns (and randomly change the order using randperm)
Amix = A( :, randperm(size(A,2)) );
See an example at ideone.
Related
I want to have the nanmean of two matrixes element per element. I don't seem to be able to do it using the function nanmean, since that doesn't sum element per element.
Simplified example:
A= [1 1 1
1 1 1
1 nan 1];
B=[3 3 3
3 3 3
3 3 3];
Result I want :
C= [2 2 2
2 2 2
2 3 2];
So the nan is ignored.
One way to sum element per element I found on https://nl.mathworks.com/matlabcentral/answers/366304-how-to-sum-up-multiple-matrices-element-by-element
A(:,:,1)=randi([1 3],100,100);
A(:,:,2)=randi([1 3],100,100);
A(:,:,3)=randi([1 3],100,100);
A(:,:,4)=randi([1 3],100,100);
B=zeros(size(A,1),size(A,2));
for i=1:size(A,3)
B=B+A(1:size(A,1),1:size(A,2),i);
end
disp(B)
BUT this isn't the nansum. How can I do this not taking into account the nans?
You can concatenate the matrices along the 3rd dimension, then apply nanmean along that dimension:
C = cat(3,A,B);
C = nanmean(C,3);
(Of course you can write these two statements as a single one, I wrote it like this for clarity.)
I am aware of MATLAB's datasample which allows to select k times from a certain population. Suppose population=[1,2,3,4] and I want to uniformly sample, with replacement, k=5 times from it. Then:
datasample(population,k)
ans =
1 3 2 4 1
Now, I want to repeat the above experiment N=10000 times without using a for loop. I tried doing:
datasample(repmat(population,N,1),5,2)
But the output I get is (just a short excerpt below):
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
Every row (result of an experiment) is the same! But obviously they should be different... It's as though some random seed is not updating between rows. How can I fix this? Or some other method I could use that avoids a for loop? Thanks!
You seem to be confusing the way datasample works. If you read the documentation on the function, if you specify a matrix, it will generate a data sampling from a selection of rows in the matrix. Therefore, if you simply repeat the population vector 10000 times, and when you specify the second parameter of the function - which in this case is how many rows of the matrix to extract, even though the actual row locations themselves are different, the actual rows over all of the matrix is going to be the same which is why you are getting that "error".
As such, I wouldn't use datasample here if it is your intention to avoid looping. You can use datasample, but you'd have to loop over each call and you explicitly said that this is not what you want.
What I would recommend you do is first create your population vector to have whatever you desire in it, then generate a random index matrix where each value is between 1 up to as many elements as there are in population. This matrix is in such a way where the number of columns is the number of samples and the number of rows is the number of trials. Once you create this matrix, simply use this to index into your vector to achieve the desired sampling matrix. To generate this random index matrix, randi is a fine choice.
Something like this comes to mind:
N = 10000; %// Number of trials
M = 5; %// Number of samples per trial
population = 1:4; %// Population vector
%// Generate random indices
ind = randi(numel(population), N, M);
%// Get the stuff
out = population(ind);
Here's the first 10 rows of the output:
>> out(1:10,:)
ans =
4 3 1 4 2
4 4 1 3 4
3 2 2 2 3
1 4 2 2 2
1 2 3 4 2
2 2 3 2 1
4 1 3 2 4
1 4 1 3 1
1 1 2 4 4
1 2 4 2 1
I think the above does what you want. Also keep in mind that the above code generalizes to any population vector you want. You simply have to change the vector and it will work as advertised.
datasample interprets each column of your data as one element of your population, sampling among all columns.
To fix this you could call datasample N times in a loop, instead I would use randi
population(randi(numel(population),N,5))
assuming your population is always 1:p, you could simplify to:
randi(p,N,5)
Ok so both of the current answers both say don't use datasample and use randi instead. However, I have a solution for you with datasample and arrayfun.
>> population = [1 2 3 4];
>> k = 5; % Number of samples
>> n = 1000; % Number of times to execute datasample(population, k)
>> s = arrayfun(#(k) datasample(population, k), n*ones(k, 1), 'UniformOutput', false);
>> s = cell2mat(s);
s =
1 4 1 4 4
4 1 2 2 4
2 4 1 2 1
1 4 3 3 1
4 3 2 3 2
We need to make sure to use 'UniformOutput', false with arrayfun as there is more than one output. The cell2mat call is needed as the result of arrayfun is a cell array.
I have a testfile.txt, which is a 4 x 4 matrix and tab delimited
1 1 3 4
2 2 3 4
3 1 3 4
4 2 3 4
The output i want is like so:
If it detects that the second column has a 1, insert a new column on the right side, and the new column should contains something like x=[1 1 0 3]
If it detects that the second column has a 2, insert a new column on the right side, and the new column should contains something like y=[2 3 4 5]
This is how the output should look like:
1 1 x=[1 1 0 3] 3 4
2 2 y=[2 3 4 5] 3 4
3 1 x=[1 1 0 3] 3 4
4 2 y=[2 3 4 5] 3 4
Ultimately, in MATLAB this is the output I want to get:
1 1 1 1 0 3 3 4
2 2 2 3 4 5 3 4
3 1 1 1 0 3 3 4
4 2 2 3 4 5 3 4
What I've tried is:
test=dlmread('testfile.txt','\t');
m=length(test);
for i=1:m
if find(test(:,2)==1)>0
x=[1 1 0 3];
test=[test(:,1) x test(:,3:4)];
elseif find(test(:,2)==2)>0
y=[2 3 4 5];
test=[test(:,1) y test(:,3:4)];
dlmwrite('testfile.txt',test,'delimiter','\t','precision','%.4f');
end
end
The error I get is the following:
Dimensions of matrices being concatenated are not consistent.
The error is from the following statement:
Error in : test=[test(:,1) x test(:,3:4)]
I'll be really appreciative if someone can help me, since i'm quite new in MATLAB.
Thanks in advance!
Here is a completely vectorized solution for you. Let's go through this one step at a time. You obviously are reading in the text data right, so let's keep that code the same.
test = dlmread('testfile.txt','\t');
What I'm going to do is create a 2D array where the first row corresponds to your x that you want to insert, while the second row corresponds to the y that you want to insert. In other words, create a variable called insertData such that:
insertData = [1 1 0 3; 2 3 4 5];
Next, you simply have to use the second column to figure out which row of data from insertData you want to insert into your final matrix. You can then use this to create your final matrix, which we will store in testOut. In other words:
testOut = [test(:,1:2) insertData(test(:,2),:) test(:,3:4)]
The output I get is:
testOut =
1 1 1 1 0 3 3 4
2 2 2 3 4 5 3 4
3 1 1 1 0 3 3 4
4 2 2 3 4 5 3 4
Let's walk through the above code slowly. The first two columns of your data stored in test and the last two columns in your data stored in test are the same. You want to insert the data right in the middle. As such, you create a new matrix called testOut where the first two columns are the same, and then in the middle is where it gets interesting. Every time the second column has a 1, we access the first row of insertData, and we place our data in the corresponding row. Every time the second column has a 2, we access the second row of insertData, and we place our data in the corresponding row. To finish everything off, the last two columns should be the same.
Minor Note
If you want to understand why your code isn't working, it's because you are not concatenating the rows properly. In addition, in your for loop, you are using : to access all of the rows for a particular column when you should be accessing one row at a time... at least that's how I'm interpreting your for loop. This change must also be done in your if statements. Also, you are adding onto the test variable, when you need to declare a NEW variable. Also, you need to move the dlmwrite method so that it is called AFTER the for loop has finished and you have finished creating the new matrix. The combination of all of these things is ultimately why you are getting errors in your code.
Basically, what you need to do, if you want to use your code, is do this:
test=dlmread('testfile.txt','\t');
m=length(test);
testOut = []; %// Must declare NEW variable
for i=1:m
if find(test(i,2)==1)>0 %// Change
x=[1 1 0 3];
testOut=[testOut; test(i,1) x test(i,3:4)]; %// NEW
elseif find(test(i,2)==2)>0 %// Change
y=[2 3 4 5];
testOut=[testOut; test(i,1) y test(i,3:4)]; %// NEW
end
end
%// Move this out!
dlmwrite('testfile.txt',testOut,'delimiter','\t','precision','%.4f');
Take a look at how testOut is being concatenated in the for loop. You are going to take the current state of testOut, move to the next row using ; then add your new data in.
This code should now work, but you can easily achieve what you want to do in just two lines.
Hope this helped!
My problem is this: I've a matrix, as example
1 2 3
4 2 6
6 1 8
4 5 4
7 1 5
8 2 0
I wish to extract selected values from the matrix, as example, a vector like this
B = [3 6 0]
selecting third column values when the value in the second column is 2.
I tried in different ways, but no one of these works.
Use this -
B = A(A(:,2)==2,3)' %// Assuming A is your input matrix
If M is your Matrix, you can select the second column using
M(:,2)
Compare it to two to get the lines which contain a 2
M(:,2)==2
And use this logical vector to select your elements from the third column.
M(M(:,2)==2,3)
A little more generally: if you want to select based on a set of values, use ismember to generate the logical index:
>> A(ismember(A(:,2), [2 5]) , 3) %// [2 5]: values you want to find in 2nd col
ans =
3
4
6
0
I have a 100 by 2 matrix. And I'm trying to figure out how to divide all terms in the second column by a constant.
For example, let's say I have this matrix.
[1 2;
3 4;
5 6]
I want to divide the 2nd column by 2.
[1 2/2;
3 4/2;
5 6/2]
So my final matrix will be.
[1 1;
3 2;
5 3]
Thank you.
If your matrix is M then:
M(:,2)=M(:,2)./2;
will divide all terms in the second column by a constant (2). By the way, because the value you divide with is a constant you can also write / instead of ./
If you'd like to assemble a new matrix and not overwrite the first one just write something like this:
A=[M(:,1) M(:,2)./2]
I'm not sure how natan 's equations should be read, but I'd multiply the first matrix
1 2
3 4
5 6
by the matrix
1 0
0 .5
The resulting matrix is
1 1
3 2
5 3