2012-09-23 17 views
5

enter image description hereMatlabで一連の分割線をカーブに合わせる方法は?

私は上記のような単純なログログ曲線を持っています。 MATLABには、このカーブをセグメント化された線で囲み、これらの線分の開始点と終了点を示す関数がありますか? MATLABのカーブフィッティングツールボックスを確認しました。彼らは1つの行またはいくつかの関数によってカーブフィッティングを行うように見えます。私は1つの行だけでフィッティングをカーブさせたくありません。

直接の機能がない場合は、同じ目標を達成するための代替手段は私には問題ありません。私の目標は、曲線を分割線でフィットさせ、これらのセグメントの端点の位置を取得することです。

答えて

7

まず、あなたの問題はカーブフィッティングとは呼ばれません。カーブフィッティングとは、データを持っているときで、それを表現する最も良い関数を見つけることができます。一方、関数の区分的線形近似を作成したいとします。セクションに手動で

  1. スプリット:

    は、私は次の戦略を示唆しています。セクションのサイズは、微分、大微分→小セクションに依存する必要があります

  2. セクション間のノードで関数をサンプリングします。
  3. 上記のポイントを通過する線形補間を求めます。

これを行うコードの例を次に示します。少数のセクションにもかかわらず、赤い線(内挿)が元の関数に非常に近いことがわかります。これは、適応セクションサイズのために発生します。

enter image description here

function fitLogLog() 
    x = 2:1000; 
    y = log(log(x)); 

    %# Find section sizes, by using an inverse of the approximation of the derivative 
    numOfSections = 20; 
    indexes = round(linspace(1,numel(y),numOfSections)); 
    derivativeApprox = diff(y(indexes)); 
    inverseDerivative = 1./derivativeApprox; 
    weightOfSection = inverseDerivative/sum(inverseDerivative); 
    totalRange = max(x(:))-min(x(:)); 
    sectionSize = weightOfSection.* totalRange; 

    %# The relevant nodes 
    xNodes = x(1) + [ 0 cumsum(sectionSize)]; 
    yNodes = log(log(xNodes)); 

    figure;plot(x,y); 
    hold on; 
    plot (xNodes,yNodes,'r'); 
    scatter (xNodes,yNodes,'r'); 
    legend('log(log(x))','adaptive linear interpolation'); 
end 
+0

は、説明のためにありがとうございました。線形補間とMatlabのための私の浅い背景のため申し訳ありません。あなたがしたことは素晴らしいことだと思います。しかし、私はそれに応じて自分のコードを変更するのは難しいです。私の元のデータyは、1 * 73行のベクトルで、その分布はcjhの解の正規のプロットに似ています。ログログ軸プロット(ログ(log(x))計算ではなく最終結果を表示するためにコードを修正する方法を指摘できますか?どうもありがとうございました。 – Cassie

5

アンドレイの適応ソリューションは、より正確な全体的なフィット感を提供します。しかし、あなたが望むものが固定長のセグメントであれば、当てはまるすべての値の完全なセットを返すメソッドを使って、ここでうまくいくはずのものがあります。速度が必要な場合はベクトル化することができます。

Nsamp = 1000;  %number of data samples on x-axis 
x = [1:Nsamp]; %this is your x-axis 
Nlines = 5;  %number of lines to fit 

fx = exp(-10*x/Nsamp); %generate something like your current data, f(x) 
gx = NaN(size(fx));  %this will hold your fitted lines, g(x) 

joins = round(linspace(1, Nsamp, Nlines+1)); %define equally spaced breaks along the x-axis 

dx = diff(x(joins)); %x-change 
df = diff(fx(joins)); %f(x)-change 

m = df./dx; %gradient for each section 

for i = 1:Nlines 
    x1 = joins(i); %start point 
    x2 = joins(i+1); %end point 
    gx(x1:x2) = fx(x1) + m(i)*(0:dx(i)); %compute line segment 
end 

subplot(2,1,1) 
h(1,:) = plot(x, fx, 'b', x, gx, 'k', joins, gx(joins), 'ro'); 
title('Normal Plot') 

subplot(2,1,2) 
h(2,:) = loglog(x, fx, 'b', x, gx, 'k', joins, gx(joins), 'ro'); 
title('Log Log Plot') 

for ip = 1:2 
    subplot(2,1,ip) 
    set(h(ip,:), 'LineWidth', 2) 
    legend('Data', 'Piecewise Linear', 'Location', 'NorthEastOutside') 
    legend boxoff 
end 

MATLAB plotted output

+0

+1 - 全体的に良い答えです。ちなみに、私は、関数をサンプリングする代わりに、すべてのエラーの合計を最小化することで、両方の方法をさらに改善できると考えました。たとえば、最初のプロットでは、2番目のノードを関数の値より下に移動して、全体のフィットを上げることができます。 –

+0

+1 - はい、私はちょうど同じことを考えていた:)特に凸型または凹形関数の場合、そのような方法は常に線形補間より優れています。 – cjh

+0

@cjh、ご協力いただきありがとうございます。 「固定長のセグメント」はどういう意味ですか?あなたの解がxを同じ長さに広げることを意味しますか? – Cassie

0

これは、この質問に対する正確な答えはありませんが、私は検索に基づいてここに到着してから、私は(合わない)を作成する方法の関連質問に答えるしたいのですが、A散布図における区間データの平均(または中央値、または他の何らかの他の関数)を表すことを意図した区分的線形関数である。

まず、回帰を使用して、明らかにsome MATLAB code listed on the wikipedia pageを持つ、関連性はあるが洗練された代替案が、Multivariate adaptive regression splinesです。

ここに解決策はちょうど私が長さ0の間隔で便利だったいくつかのペアXとYデータ上の平均を計算するポイント例えば

function [x, y] = intervalAggregate(Xdata, Ydata, aggFun, intStep, intOverlap) 
% intOverlap in [0, 1); 0 for no overlap of intervals, etc. 
% intStep this is the size of the interval being aggregated. 

minX = min(Xdata); 
maxX = max(Xdata); 

minY = min(Ydata); 
maxY = max(Ydata); 

intInc = intOverlap*intStep; %How far we advance each iteraction. 
if intOverlap <= 0 
    intInc = intStep; 
end 
nInt = ceil((maxX-minX)/intInc); %Number of aggregations 

parfor i = 1:nInt 
    xStart = minX + (i-1)*intInc; 
    xEnd = xStart + intStep; 
    intervalIndices = find((Xdata >= xStart) & (Xdata <= xEnd)); 
    x(i) = aggFun(Xdata(intervalIndices)); 
    y(i) = aggFun(Ydata(intervalIndices)); 
end 

を取得するために、重複区間で平均を計算することです。1有し、互いに略1/3の重なり(散乱画像を参照)

Scatter plot example for Xdat and Ydat

[X、Y] = intervalAggregate(XDAT、Ydat、@mean、0.1、0.333)

X =

列8

列9我々が見る1~9

0.9803 0.9750 0.9707 0.9653 0.9598 0.9560 0.9537 

15を介してカラム
0.9992 0.9983 0.9971 0.9955 0.9927 0.9905 0.9876 0.9846 

8を介して15

0.3182 0.3561 0.3875 0.4178 0.4494 0.4671 0.4822 

Y =

カラムを通すことXが増加するにつれて、 yは若干減少する傾向があるy。そこから、ラインセグメントを描画したり、他の種類のスムージングを実行するのは簡単です。

(私はこのソリューションをベクトル化しようとしなかったことに注意してください。XDATAがソートされている場合はるかに高速バージョンを想定することができる)

関連する問題