How to use "predict" to get x value for a given y value?

42 views (last 30 days)
TW
TW on 3 Dec 2024 at 19:33
Commented: Star Strider on 6 Dec 2024 at 12:51
I found predict but it seems to generate y values for a given x value. Is there another way to get the x value for a given y value i.e. when y = 0 what is x.
When I manually examine the data, the x value increases while the y generally trends downwards. However, the y value occassionally spikes and dips below 0, but the general trend is decreasing.
  4 Comments
Walter Roberson
Walter Roberson on 4 Dec 2024 at 9:09
"Scattered X and y values with X increasing." does not match "My data have duplicate x values". Not unless "with X increasing" you mean X is monotonic but not "strictly" monotonic.
TW
TW on 4 Dec 2024 at 9:19
I've edited. But x generally decreases but not have a pattern.
Like
1, 2, 3.4, 4, 4.1, etc.

Sign in to comment.

Answers (3)

John D'Errico
John D'Errico on 3 Dec 2024 at 20:27
Edited: John D'Errico on 3 Dec 2024 at 20:35
Huh? Of course polyfit works. It does NOT require the x values be distinct. I'm not at all sure why you think that is necessary. Perhaps you are thinking of tools like interp1, or an interpolating spline. Regardless, polyfit does not provide an inverse computation. Nor does fit. Nor does predict, or any such tool.
And of course, the solution you want will not be unique. That will be the case for almost any nonlinear function.
What does this mean? It means you need to use a rootfinder. fzero is your best choice in general. But fsolve is an alternative. Again, since multiple solutions are potentially possible, you will need to provide an intelligent starting value to get the solver in the right ballpark for the solution you wish to see found. In the case of fzero, it can work with a single starting value, but a bracket that surrounds the solution can be better, helping the solver to converge more rapidly.
If you wish to solve for some other value than y==0, then just subtract that value from the function as fit. Now you are back at the problem fzero wants to solve, thus finding a zero.
  1 Comment
TW
TW on 4 Dec 2024 at 9:02
Would it work if the y value have spikes and dips i.e. while it trends downward, it's not a smooth descend.

Sign in to comment.


Star Strider
Star Strider on 3 Dec 2024 at 23:57
I generally use the interp1 function to return x-values given y-values.
That generally goes something like this —
x = linspace(0, 10, 250);
y = sin(2*pi*x);
L = numel(x);
y_vals = 1-2*rand(4,1)
y_vals = 4×1
-0.0368 -0.7442 0.0665 -0.4039
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
for k = 1:numel(y_vals)
zxi{k} = find(diff(sign(y - y_vals(k))));
end
zxi
zxi = 1x4 cell array
{1x20 double} {1x20 double} {1x20 double} {1x20 double}
for k1 = 1:numel(zxi)
% zxi{k1}
for k2 = 1:numel(zxi{k1})
idxrng = max(1,zxi{k1}(k2)-1) : min(zxi{k1}(k2)+1,L);
x_vals{k1,k2} = interp1(y(idxrng), x(idxrng), y_vals(k1));
end
end
x_vals
x_vals = 4x20 cell array
Columns 1 through 12 {[0.5059]} {[0.9941]} {[1.5059]} {[1.9941]} {[2.5059]} {[2.9941]} {[3.5059]} {[3.9941]} {[4.5059]} {[4.9941]} {[5.5059]} {[5.9941]} {[0.6345]} {[0.8650]} {[1.6347]} {[1.8650]} {[2.6349]} {[2.8652]} {[3.6350]} {[3.8654]} {[4.6350]} {[4.8657]} {[5.6348]} {[5.8661]} {[0.0107]} {[0.4894]} {[1.0107]} {[1.4894]} {[2.0106]} {[2.4894]} {[3.0106]} {[3.4893]} {[4.0106]} {[4.4893]} {[5.0106]} {[5.4893]} {[0.5664]} {[0.9335]} {[1.5662]} {[1.9336]} {[2.5663]} {[2.9337]} {[3.5665]} {[3.9337]} {[4.5666]} {[4.9335]} {[5.5667]} {[5.9334]} Columns 13 through 20 {[6.5059]} {[6.9942]} {[7.5058]} {[7.9942]} {[8.5058]} {[8.9941]} {[9.5059]} {[9.9941]} {[6.6345]} {[6.8662]} {[7.6341]} {[7.8657]} {[8.6337]} {[8.8653]} {[9.6341]} {[9.8651]} {[6.0106]} {[6.4893]} {[7.0107]} {[7.4893]} {[8.0107]} {[8.4893]} {[9.0107]} {[9.4894]} {[6.5667]} {[6.9333]} {[7.5667]} {[7.9333]} {[8.5667]} {[8.9333]} {[9.5666]} {[9.9334]}
figure
plot(x, y)
hold on
for k = 1:size(x_vals,1)
xv = [x_vals{k,:}];
hp{k} = plot(xv, y_vals(k)*ones(size(xv)), 's', DisplayName="Y = "+y_vals(k));
end
hold off
grid
xlabel('X')
ylabel('Y')
legend([hp{:}], Location='best')
Make appropriate changes to use wiith your data.
.
  4 Comments
TW
TW on 6 Dec 2024 at 12:17
Just curious, would the data not work if you have more than one points in the region? What do you mean by that?
Star Strider
Star Strider on 6 Dec 2024 at 12:51
The interp1 function will throw a ‘Sample points must be unnique’ error, if you try to get more than one independent variable for each dependent variiable in a region. Finding the regions of the values that correspond to the desired value and interpolating only in that region prevents this, since in that region the values are unique.
There should be only one point corresponding to a desired value of the dependent variable in a specific region. If there are closely-related ponts, then it would be neceessary to run ‘zxi’ for each of them and do the interpolations separately.
x = linspace(0, pi);
y = sin(x);
L = numel(x)
L = 100
zxi = find(diff(sign(y - 0.5)))
zxi = 1×2
17 83
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
for k = 1:numel(zxi)
idxrng = max(1,zxi(k)-1) : min(zxi(k)+1,L)
get_x1(k) = interp1(y(idxrng), x(idxrng), 0.5);
end
idxrng = 1×3
16 17 18
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
idxrng = 1×3
82 83 84
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
get_x1
get_x1 = 1×2
0.5237 2.6179
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
figure
plot(x, y, DisplayName='Data')
hold on
plot(get_x1, ones(size(get_x1))*0.5, 'rs', DisplayName='Desired Values')
hold off
grid
xlabel('X')
ylabel('Y')
title('Plot Demonstrating ‘Exact’ Intersections')
legend(Location='S')
get_x2 = interp1(y, x, 0.5) % Interpolating Both Points In A Single ‘interp1’ Call Fails
Error using matlab.internal.math.interp1
Sample points must be unique.

Error in interp1 (line 188)
VqLite = matlab.internal.math.interp1(X,V,method,method,Xqcol);

Sign in to comment.


Walter Roberson
Walter Roberson on 4 Dec 2024 at 9:26
Scattered X and y values with X increasing.
Suppose you had the input
X Y
1 1
1 0.5
1 -0.1
2 2
2 1
2 0.5
and you ask when y = 0
You would logically need to pair the (1,-0.1) with each of the X == 2 values and run interpolations on each of them:
(2,2)->(1,-0.1) ==> 22/11
(2,1)->(1,-0.1) ==> 12/11
(2,0.5)->(1,-0.1) ==> 7/6
and you would have to repeat this for any other locations where X = 1 was paired with a negative number.
Now if you extend the data with (3,0.1) then you also need to interpolate (1,-0.1) versus (3,0.1) . After all, the data is scattered, which implies that there might be missing entries for X == 2, so you need to consider the X = 1 to X = 3 pairs as well.
You can do this kind of calculation, but it is not exactly viable... unless you also list the X Y pairs that were taken into account in finding any particular crossing.

Categories

Find more on Interpolation in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!