Do not display zeros after decimal point in a matrix - matlab

I'm trying to remove the trailing zeros, after the decimal point, from the first row of the following matrix A.
A1 = [130: -20: 10]
A2 = [1: 11/6: 12]
A3 = [1/2: 1/4: 2]*pi
A = [A1; A2; A3]
Which is displayed as:
A = 130.0000 110.0000 90.0000 70.0000 50.0000 30.0000 10.0000
1.0000 2.8333 4.6667 6.5000 8.3333 10.1667 12.0000
1.5708 2.3562 3.1416 3.9270 4.7124 5.4978 6.2832
The final matrix has to be like this one:
How can I do this?

A1 = [130: -20: 10];
A2 = [1: 11/6: 12];
A3 = [1/2: 1/4: 2]*pi;
format shortG % Where the magic happens
A = [A1; A2; A3]
A =
130 110 90 70 50 30 10
1 2.8333 4.6667 6.5 8.3333 10.167 12
1.5708 2.3562 3.1416 3.927 4.7124 5.4978 6.2832
Just use format shortG. The zeros are there technically only as a numerical accuracy-thing. Check the documentation on format for all display styles.

Related

Linear regression (regress) discrepancy with polynomial fit (polyfit)

I have some data which comes from a linear function (y=mx+c) where m=4, c=1 (so: y=4x+1).
When I try to get back the coefficients using regress, I'm getting an R2<1 and a seemingly random m value:
x = [1 2 3 4]
y = [5 9 13 17]
[m,bint,r,rint,stats] = regress(y',x');
%{
>> R = stats(1) % Coefficient of determination
R =
1
>> m % Linear function coefficients
m =
4.333333333333333
%}
Whereas polyfit does this correctly:
P = polyfit(x,y,1);
%{
>> P(1)
ans =
4.000000000000000
>> P(2)
ans =
1.000000000000000
%}
Why is this happening?
The source of your problem is not following the documentation or regress which states that:
b = regress(y,X) returns a vector b of coefficient estimates for a multiple linear regression of the responses in vector y on the predictors in matrix X. The matrix X must include a column of ones.
If we include a column of ones in the 2nd input, we get the desired result:
x = [1 2 3 4].';
y = [5 9 13 17].';
[m,bint,r,rint,stats] = regress(y,[ones(size(x)) x]);
%{
Results:
m =
1.0000
4.0000
bint =
1.0000 1.0000
4.0000 4.0000
r =
1.0e-14 *
0.1776
0.1776
0.1776
0
rint =
1.0e-13 *
0.0178 0.0178
-0.2190 0.2545
-0.2190 0.2545
-0.2141 0.2141
stats =
1.0e+31 *
0.0000 1.6902 0.0000 0.0000
%}

How to format scientific notation with 1 digit after the decimal place in MATLAB?

I have tried sprintf("%.1e", x) but that gives me 6.3000e-16. How can I cut off the zeros and display just 6.3e-16? I am also displaying the numbers in a table.
EDIT: So now it is correctly display some numbers, but others aren't displayed in scientific notation at all. I am using R2018a.
Here is the code I am using
n = zeros(19,1);
a = zeros(19,1);
b = zeros(19,1);
c = zeros(19,1);
d = zeros(19,1);
format short
for i = 2:20
w = 1/(2000 * i);
x = 1/(1000 * i);
y = 1/(50 * i);
z = 1/(20 * i);
n(i-1) = sprintf("%d", i);
a(i-1) = sprintf("%.1e", w);
b(i-1) = sprintf("%.1e", x);
c(i-1) = sprintf("%.1e", y);
d(i-1) = sprintf("%.1e", z);
end
table( n, a, b, c, d )
and here is the output:
19×5 table
n a b c d
__ _______ _______ ______ ______
2 0.00025 0.0005 0.01 0.025
3 0.00017 0.00033 0.0067 0.017
4 0.00013 0.00025 0.005 0.013
5 0.0001 0.0002 0.004 0.01
6 8.3e-05 0.00017 0.0033 0.0083
7 7.1e-05 0.00014 0.0029 0.0071
8 6.3e-05 0.00013 0.0025 0.0063
9 5.6e-05 0.00011 0.0022 0.0056
10 5e-05 0.0001 0.002 0.005
11 4.5e-05 9.1e-05 0.0018 0.0045
12 4.2e-05 8.3e-05 0.0017 0.0042
13 3.8e-05 7.7e-05 0.0015 0.0038
14 3.6e-05 7.1e-05 0.0014 0.0036
15 3.3e-05 6.7e-05 0.0013 0.0033
16 3.1e-05 6.3e-05 0.0013 0.0031
17 2.9e-05 5.9e-05 0.0012 0.0029
18 2.8e-05 5.6e-05 0.0011 0.0028
19 2.6e-05 5.3e-05 0.0011 0.0026
20 2.5e-05 5e-05 0.001 0.0025
In your code, you are assigning a string to a double-float array. It looks like MATLAB automatically converts the string to a double to store it there. Thus, your formatting gets lost:
>> sprintf("%.1e", 1/1000)
ans =
"1.0e-03"
>> a=0;
>> a(1) = sprintf("%.1e", 1/1000)
a =
1.0000e-03
>> class(a)
ans =
'double'
Instead, use a string array:
a = strings(19,1);
%...
a(i-1) = sprintf("%.1e", w);
I'm not used to the new strings, and this behavior surprises me. Assigning a number to a string converts the number to a string, and assigning the string to a number converts it back to a number. This does not happen with the "old-fashioned" char arrays:
>> a=0;
>> a(1) = sprintf('%.1e', 1/1000);
Unable to perform assignment because the left and right sides have a different number of elements.
When using char arrays, store them in a cell array:
a = cell(19,1);
%...
a{i-1} = sprintf('%.1e', w);
You can use "fprintf":
>> fprintf("%.1f\n", pi)
3.1
To show more or less digits just adjust the number after the dot.

Create vectors associated with each entry of an array and save them in a new matrix

Say i have a matrix like A = [1 2; 3 4], and that i need to create 4, vectors each one associated to one entrance of the matrix, such that the first one goes from -1..1, and second from -2..2, and so forth. Wath i try was
for j=1:2
for k=1:2
W=linspace(-A(j,k),A(j,k),4)
end
end
the problem with that line is that it not save the data.
Also i need that to create a new matrix, such that every row be one of the vectors that i mentioned.
I know that on octave i can do
W=linspace(-A,A,4)
but in MATLAB it doesn't work
If you want 4 values evenly distributed between A(k) and A(k), then you can use an anonymous function in combination with linspace this way:
fun = #(x) linspace(-A(x), A(x), 4)
b = fun(1:numel(A))
b =
-1.00000 -0.33333 0.33333 1.00000
-3.00000 -1.00000 1.00000 3.00000
-2.00000 -0.66667 0.66667 2.00000
-4.00000 -1.33333 1.33333 4.00000
Assuming you want [-1 0 1], [-2 -1 0 1 2] etc, then I suggest using arrayfun like this:
A = [1 2;3 4];
b = arrayfun(#(n) -A(n):A(n), 1:numel(A), 'UniformOutput',0)
b =
{
[1,1] =
-1 0 1
[1,2] =
-3 -2 -1 0 1 2 3
[1,3] =
-2 -1 0 1 2
[1,4] =
-4 -3 -2 -1 0 1 2 3 4
Your approach didn't work because you're overwriting W everytime you loop. The following works:
V = zeros(numel(A),4);
for k=1:numel(A)
W(k,:) = linspace(-A(k),A(k),4);
end
The reason why I only use one index for A is because you may use linear indexing in MATLAB. Remember to allocate memory before you assign values to a matrix inside a loop. "Growing" matrices are very slow.
You can do it like that
W = zeros(4,4);
a = reshape(A, 1, 4);
for i=1:4
W(i,:) = linspace(-a(i), a(i), 4);
end
and you obtain
W =
-1.0000 -0.3333 0.3333 1.0000
-3.0000 -1.0000 1.0000 3.0000
-2.0000 -0.6667 0.6667 2.0000
-4.0000 -1.3333 1.3333 4.0000
If you want to generate a fixed number of values (say 4) for each entry of A, you can achieve it in one line:
>> bsxfun(#times, linspace(-1,1,4), A(:))
ans =
-1.0000 -0.3333 0.3333 1.0000
-3.0000 -1.0000 1.0000 3.0000
-2.0000 -0.6667 0.6667 2.0000
-4.0000 -1.3333 1.3333 4.0000

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.

Cartesian product in MATLAB

Here is the simplified version of the problem I have. Suppose I have a vector
p=[1 5 10]
and another one
q=[.75 .85 .95]
And I want to come up with the following matrix:
res=[1, .75;
1, .85;
1, .95;
5, .75;
5, .85;
5, .95;
10, .75;
10, .85;
10, .95]
This is also known as the Cartesian Product.
How can I do that?
Here's one way:
[X,Y] = meshgrid(p,q);
result = [X(:) Y(:)];
The output is:
result =
1.0000 0.7500
1.0000 0.8500
1.0000 0.9500
5.0000 0.7500
5.0000 0.8500
5.0000 0.9500
10.0000 0.7500
10.0000 0.8500
10.0000 0.9500
A similar approach as the one described by #nibot can be found in matlab central file-exchange.
It generalizes the solution to any number of input sets. This would be a simplified version of the code:
function C = cartesian(varargin)
args = varargin;
n = nargin;
[F{1:n}] = ndgrid(args{:});
for i=n:-1:1
G(:,i) = F{i}(:);
end
C = unique(G , 'rows');
end
For instance:
cartesian(['c','d','e'],[1,2],[50,70])
ans =
99 1 50
99 1 70
99 2 50
99 2 70
100 1 50
100 1 70
100 2 50
100 2 70
101 1 50
101 1 70
101 2 50
101 2 70
Here's a function, cartesian_product, that can handle any type of input, including string arrays, and returns a table with column names that match the names of the input variables. Inputs that are not variables are given names like var1, var2, etc.
function tbl = cartesian_product(varargin)
names = arrayfun(#inputname, 1:nargin, 'UniformOutput', false);
for i = 1:nargin
if isempty(names{i})
names{i} = ['var' num2str(i)];
end
end
rev_args = flip(varargin);
[A{1:nargin}] = ndgrid(rev_args{:});
B = cellfun(#(x) x(:), A, 'UniformOutput', false);
C = flip(B);
tbl = table(C{:}, 'VariableNames', names);
end
>> x = ["a" "b"];
>> y = 1:3;
>> z = 4:5;
>> cartesian_product(x, y, z)
ans =
12×3 table
x y z
___ _ _
"a" 1 4
"a" 1 5
"a" 2 4
"a" 2 5
"a" 3 4
"a" 3 5
"b" 1 4
"b" 1 5
"b" 2 4
"b" 2 5
"b" 3 4
"b" 3 5
>> cartesian_product(1:2, 3:4)
ans =
4×2 table
var1 var2
____ ____
1 3
1 4
2 3
2 4