Inserting a struct into a vector? - matlab

I have a 175x1 vector of probabilities, v, and a struct with a vector in it, called data.x, which is 8156x1 and has numbers from 0-400.
In code provided to me, they do the following:
v(data.x);
and out comes a vector of 8156x1. I have no idea what it does to the data, and have not been able to recreate the result.
Any help is appreciated.

Looks like your data.x is a vector of indexes for your v vector. I am surprised that data.x has values between 0-400, it will result in error for any value greater than 175 (length of the vector v).
For example this:
v = [0.4 0.2 0.1 0.44 0.25 0.9 0.91]';
data.x = [1 3 2 5 2]';
v(data.x)
ans =
0.4000
0.1000
0.2000
0.2500
0.2000

Related

Ranking (ordering value) of an observation in a matrix

I am trying to get the rank of an observation in a matrix, taking into account NaN's and values that can repeat themselfs.
E.g. if we have
A = [0.1 0.15 0.3; 0.5 0.15 0.1; NaN 0.2 0.4];
A =
0.1000 0.1500 0.3000
0.5000 0.1500 0.1000
NaN 0.2000 0.4000
Then I want to get the following output:
B =
1 2 4
6 2 1
NaN 3 5
Thus 0.1 is the lowest value (rank=1), whereas 0.5 is the highest value (rank = 6).
Ideally an efficient solution without loops.
You can use unique. This sorts data by default, and you can get the index of the sorted unique values. This would replicate your tie behaviour, since identical values will have the same index. You can omit NaN values with logical indexing.
r = A; % or NaN(size(A))
nanIdx = isnan(A); % Get indices of NaNs in A to ignore
[~, ~, r(~nanIdx)] = unique(A(~nanIdx)) % Assign non-NaN values to their 'unique' index
>> r =
[ 1 2 4
6 2 1
NaN 3 5 ]
If you have the stats toolbox you can use tiedrank function for a similar result.
r = reshape(tiedrank(A(:)), size(A)) % Have to use reshape or rank will be per-column
>> r =
[ 1.5, 3.5, 6.0
8.0, 3.5, 1.5
NaN, 5.0, 7.0 ]
This is not your desired result (as per your example). You can see that tiedrank actually uses a more conventional ranking system than yours, where a tie gives each result the average rank. For example a tied 1st and 2nd gives each rank 1.5, and the next rank is 3.

Averaging replicate data in Matlab, multiple variables

I'm trying to average replicate data in MATLAB and running into some difficulty. The variables are depth, Var1, Var2. Sometimes there is a replicate in Var1, sometimes there is a replicate in Var2, sometimes there is a replicate for both Var1 and Var2 for a given depth. So the matrix might look something like this:
1 0.2 1,
2 0.5 3,
2 0.7 NaN,
3 0.1 5,
3 0.7 6,
4 0.3 4,
...
depth is the unique identifier so I would like to create a matrix with [depth, Var1, Var2] that looks like this:
1 0.2 1,
2 0.6 3,
3 0.4 5.5,
4 0.3 4,
...
The function accumarray would work if I had an n-by-2 matrix, but this is n-by-3. Any recommendations on how to proceed?
This should work
a=[1 0.2 1; 2 0.5 3; 2 0.7 NaN; 3 0.1 5; 3 0.7 6; 4 0.3 4];
depths = unique(a(:,1));
b=nan(length(depths),3);
for ct = 1:length(depths)
b(ct,:)=mean(a(a(:,1)==depths(ct),:),1,'omitnan');
end
result
b =
1.0000 0.2000 1.0000
2.0000 0.6000 3.0000
3.0000 0.4000 5.5000
4.0000 0.3000 4.0000
A bit naive implementation with accumarray which loops over the variables.
A = [1 0.2 1
2 0.5 3
2 0.7 NaN
3 0.1 5
3 0.7 6
4 0.3 4];
result = zeros([numel(unique(A(:,1))) size(A,2)]);
result(:,1) = unique(A(:,1));
for ii = 2:size(A,2)
result(:,ii) = accumarray(A(:,1),A(:,ii),[],#mean);
end

How to Replace Values Exceeding Threshold with Random Number Sampled from a Given Dataset?

I have a 3-dimensional vector called 'simulatedReturnsEVT3'. In that vector, I would like to replace all values that are higher than 'MaxAcceptableVal' or lower than 'MinAcceptableVal'. Such values that are beyond either of these two thresholds should be replaced by a random number that is drawn from the 3-dimensional vector 'data2'. For drawing that random number, I use the matlab function 'datasample'.
I have written the below code, which replaces the values that are beyond either of the thresholds with a random number sampled from 'data2'. However, it seems (when plotting the data in a histogram) that the replacement happens with the same value along dimension 'j'. This is not what I want to do. For every threshold exceedance, I want a new random number to be drawn for replacement from 'data2'.
nIndices = 19
nTrials = 10000
% data2 has dimensions 782 x 19 x 10000
% simulatedReturnsEVT3 has dimensions 312 x 19 x 10000
% MaxAcceptableVal has dimensions 1 x 19
% MinAcceptableVal has dimensions 1 x 19
% Cut off Outliers
for i=1:nIndices
for j=1:nTrials
sliceEVT = simulatedReturnsEVT3(:,i,j);
sliceEVT(sliceEVT < MinAcceptableVal(i))=datasample (data2(:,i,j), 1,1,'Replace',false);
sliceEVT(sliceEVT > MaxAcceptableVal(i))=datasample (data2(:,i,j), 1,1,'Replace',false);
simulatedReturnsEVT3(:,i,j) = sliceEVT;
end
end
The same problem can be illustrated on a smaller scale by creating the following matrices.
% Set Maximum Acceptable Levels for Positive and Negative Returns
MaxAcceptableVal = [0.5 0.3]
MinAcceptableVal = [-0.5 -0.3]
simulatedReturnsEVT3 = [0.6 0.3; 0.3 0.3; 0.3 0.3; 0.3 0.4]
simulatedReturnsEVT3 = repmat(simulatedReturnsEVT3,[1 1 2])
data2 = [0.25 0.15; 0.25 0.15; 0.2 0.1]
data2 = repmat(data2,[1 1 2])
% Cut off Outliers
for i=1:2
for j=1:2
sliceEVT = simulatedReturnsEVT3(:,i,j);
sliceEVT(sliceEVT < MinAcceptableVal(i))=datasample (data2(:,i,j), 1,1,'Replace',false);
sliceEVT(sliceEVT > MaxAcceptableVal(i))=datasample (data2(:,i,j), 1,1,'Replace',false);
simulatedReturnsEVT3(:,i,j) = sliceEVT;
end
end
Can anybody help?
If I've understood the problem, it seems it is related to the usage of datasample.
In your code you use:
datasample (data2(:,i,j), 1,1,'Replace',false);
in this call, the first "1" defines the number of sample to be extracted that is "1".
In case more than one values have to be replaced in the simulatedReturnsEVT3 matrix, all of them wil be replaced by the same, unique number extracted using datasample
Again, if I've understood the problem, you should call datasample by specifying the number "n" of values are needed to replace the "out of the bound" values in simulatedReturnsEVT3
datasample (data2(:,i,:), n,1,'Replace',false)
To test this solution I've modified the definition of MaxAcceptableVal in order to have "more" values "out of the bound" in simulatedReturnsEVT3:
MaxAcceptableVal = [0.5 0.2]
These are the values of simulatedReturnsEVT3 before the replacement:
val(:,:,1) =
0.6000 0.3000
0.3000 0.3000
0.3000 0.3000
0.3000 0.4000
val(:,:,2) =
0.6000 0.3000
0.3000 0.3000
0.3000 0.3000
0.3000 0.4000
These are the values after the replacement:
val(:,:,1) =
0.2500 0.1500
0.3000 0.1000
0.3000 0.1500
0.3000 0.1000
val(:,:,2) =
0.2000 0.1000
0.3000 0.1500
0.3000 0.1500
0.3000 0.1000
This is the updated code:
% Set Maximum Acceptable Levels for Positive and Negative Returns
% MaxAcceptableVal = [0.5 0.3]
MaxAcceptableVal = [0.5 0.2]
MinAcceptableVal = [-0.5 -0.3]
simulatedReturnsEVT3 = [0.6 0.3; 0.3 0.3; 0.3 0.3; 0.3 0.4]
simulatedReturnsEVT3 = repmat(simulatedReturnsEVT3,[1 1 2])
data2 = [0.2 0.1; 0.25 0.15; 0.25 0.15; 0.2 0.1]
data2 = repmat(data2,[1 1 2])
% Cut off Outliers
for i=1:2
for j=1:2
sliceEVT = simulatedReturnsEVT3(:,i,j)
% Identify the index of the values to be replaced
idx=find(sliceEVT < MinAcceptableVal(i))
% Evaluate how many values have to be replaced
n=length(idx)
% Extract and assign the number from "data2"
sliceEVT(idx)=datasample (data2(:,i,j), n,1,'Replace',false)
% Identify the index of the values to be replaced
idx=find(sliceEVT > MaxAcceptableVal(i))
% Evaluate how many values have to be replaced
n=length(idx)
% Extract and assign the number from "data2"
sliceEVT(idx)=datasample (data2(:,i,j), n,1,'Replace',false)
simulatedReturnsEVT3(:,i,j) = sliceEVT
end
end
Hope this helps.

using matlab surf functions with x size 11 and y size 6

I am trying to use matlab for calculating the approximation of a function using the composite trapezoidal rule, and then displaying the function and approximation using a surf function and a bar3 function. the thing is is that when I try plot the function surf(x,y,Z) I receive and error saying dimension's mismatch.
my question is how would I get the surf function to plot the 3D graph when my x,y and z arrays differ in size.
I've tried to create zeros functions of the the x and y array's of the same size and then adding my values to each, then NaN'ing the extra 0's, but as u see each of my arrays start with 0's therefore NaN'ing where i find a zero in my arrays will effect my graph plot. and plus i still get the same error "dimensions mismatch" so i supposed thats because my Z array is bigger than my x and y.
Any help would be appreciated.
code for my x and y are:
`
x = linspace(a,b,h); %h being 11 and breaks up the difference because datapoints a and b into h number of sub intervals
y = linspace(c,d,k); %k being 6 and breaks up the difference because data points c and d into k number of sub intervals
Z = zeros(h,k);
for i = 1:1:h
for j = 1:1:k
Z(i,j) = f(x(i),y(j));
end
end
surf(x,y,Z);
`
x
0 0.3000 0.6000 0.9000 1.2000 1.5000 1.8000 2.1000 2.4000 2.7000 3.0000
y
0 0.6286 1.2571 1.8857 2.5143 3.1429
Z
0 0 0 0 0 0
0 0.1764 0.2854 0.2852 0.1761 -0.0004
0 0.3528 0.5707 0.5705 0.3522 -0.0008
0 0.5292 0.8561 0.8557 0.5283 -0.0011
0 0.7056 1.1415 1.1410 0.7044 -0.0015
0 0.8820 1.4268 1.4262 0.8804 -0.0019
0 1.0584 1.7122 1.7115 1.0565 -0.0023
0 1.2348 1.9975 1.9967 1.2326 -0.0027
0 1.4112 2.2829 2.2820 1.4087 -0.0030
0 1.5876 2.5683 2.5672 1.5848 -0.0034
0 1.7640 2.8536 2.8525 1.7609 -0.0038
Error using surf (line 75)
Data dimensions must agree.
Error in CompositeTrapazoidal>btnSolve_Callback (line 167)
surf(x,y,Z);
Try surf(x,y,Z'); (because x's length should match the Z's column count)

Filling the pixels with values of another matrix

Say you have two matrices as follows:
A = [1 0.2 1; 0.4 0.4 1; 1 0.6 1; 0.9 0.7 1];
B = [33 75 250; 6 34 98; 55 3 4; 153 66 30];
Say we want to create a new matrix C that contains the values of B where A=1.
I think in matlab we can do the following for this:
C = B(A==1);
But, how can I fill the other cells with the original values of A, as I think in our case, we will just get a vector with the B elements which their corresponding value in A=1? And, I want C to have the same dimensions of B but with the original values of A that are not equal to 1 instead of having 0 values.
Yes, you can do it like this:
C= A.*(A~=1)+B.*(A==1)
Which gives:
C =
33.0000 0.2000 250.0000
0.4000 0.4000 98.0000
55.0000 0.6000 4.0000
0.9000 0.7000 30.0000
C will have to be initialized anyways, so let's initialize it to A as in C = A;. Then, MATLAB allows you to index the left-hand side as in C(A==1) = B(A==1); to replace all elements in C by those in B for which A == 1. All other elements will stay the same.