2011-09-15 4 views
3

私はスプレッドシートを模倣する.netページを構築しています。シートは、誰かがTREND()のC#の同等を提供することができ、この式C#でTREND()を呼び出すExcel式を再作成するにはどうすればよいですか?

=ROUND(TREND(AA7:AE7,AA$4:AE$4,AF$4),1) 

が含まれていますか?あるいは誰かがそれの周りにショートカットを提供することもできます。私は、簡単な方法があるかどうかを知るために数学に十分に精通していません。

ここにいくつかのサンプル番号があります。

AA7:AE7 6 8 10 12 14

または 10.2 13.6 17.5 20.4 23.8

AA $ 4:$ AE 4 600 800 1000 1200 1400

AF $ 4 650

編集:ここに私が思いついたのは、私のスプレッドシートと同じ数字を生み出しているようだ。

public static partial class Math2 
{ 
    public static double[] Trend(double[] known_y, double[] known_x, params double[] new_x) 
    { 
     // return array of new y values 
     double m, b; 
     Math2.LeastSquaresFitLinear(known_y, known_x, out m, out b); 

     List<double> new_y = new List<double>(); 
     for (int j = 0; j < new_x.Length; j++) 
     { 
      double y = (m * new_x[j]) + b; 
      new_y.Add(y); 
     } 

     return new_y.ToArray(); 
    } 

    // found at http://stackoverflow.com/questions/7437660/how-do-i-recreate-an-excel-formula-which-calls-trend-in-c 
    // with a few modifications 
    public static void LeastSquaresFitLinear(double[] known_y, double[] known_x, out double M, out double B) 
    { 
     if (known_y.Length != known_x.Length) 
     { 
      throw new ArgumentException("arrays are unequal lengths"); 
     } 

     int numPoints = known_y.Length; 

     //Gives best fit of data to line Y = MC + B 
     double x1, y1, xy, x2, J; 

     x1 = y1 = xy = x2 = 0.0; 
     for (int i = 0; i < numPoints; i++) 
     { 
      x1 = x1 + known_x[i]; 
      y1 = y1 + known_y[i]; 
      xy = xy + known_x[i] * known_y[i]; 
      x2 = x2 + known_x[i] * known_x[i]; 
     } 

     M = B = 0; 
     J = ((double)numPoints * x2) - (x1 * x1); 

     if (J != 0.0) 
     { 
      M = (((double)numPoints * xy) - (x1 * y1))/J; 
      //M = Math.Floor(1.0E3 * M + 0.5)/1.0E3; // TODO this is disabled as it seems to product results different than excel 
      B = ((y1 * x2) - (x1 * xy))/J; 
      // B = Math.Floor(1.0E3 * B + 0.5)/1.0E3; // TODO assuming this is the same as above 
     } 
    } 

} 

答えて

4

TRENDは、Excel関数LINESTに基づいています。 このリンクに従うと、https://support.office.com/en-us/article/LINEST-function-84d7d0d9-6e50-4101-977a-fa7abf772b6d、LINESTの背後にある機能について説明します。

さらに、使用する基本式が見つかります。

First Formula

Second formulat

+0

私は、{x、y}の集合をとり、MとBを返して、最小平方フィット関数を見つけました。次に、x値の新しいセットでMとBを使用して、y値を生成して、 。それはすべて正しいですか? – lincolnk

+0

正直言って、私はLINESTやTRENDの機能に慣れていません。これらは、これらを使用するときに多く行われています。ドキュメントからは、信頼性の低いもの(ごみが出ているごみ)があるようです。私はあなたがExcelの機能が何を理解し、単にC#で結果を試して再現する必要があると思います。私が言うことができるから、簡単な仕事はありません。 –

+0

リンクは無効です – Rocklan

4

我々はC#でこれを再作成するために必要なてきたように、この記事は非常に参考にされています。ポイントは、その値を定義する整数を使用しているので

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Drawing; 

public static class MathHelper 
{ 
    /// <summary> 
    /// Gets the value at a given X using the line of best fit (Least Square Method) to determine the equation 
    /// </summary> 
    /// <param name="points">Points to calculate the value from</param> 
    /// <param name="x">Function input</param> 
    /// <returns>Value at X in the given points</returns> 
    public static float LeastSquaresValueAtX(List<PointF> points, float x) 
    { 
     float slope = SlopeOfPoints(points); 
     float yIntercept = YInterceptOfPoints(points, slope); 

     return (slope * x) + yIntercept; 
    } 

    /// <summary> 
    /// Gets the slope for a set of points using the formula: 
    /// m = ∑ (x-AVG(x)(y-AVG(y))/∑ (x-AVG(x))² 
    /// </summary> 
    /// <param name="points">Points to calculate the Slope from</param> 
    /// <returns>SlopeOfPoints</returns> 
    private static float SlopeOfPoints(List<PointF> points) 
    { 
     float xBar = points.Average(p => p.X); 
     float yBar = points.Average(p => p.Y); 

     float dividend = points.Sum(p => (p.X - xBar) * (p.Y - yBar)); 
     float divisor = (float)points.Sum(p => Math.Pow(p.X - xBar, 2)); 

     return dividend/divisor;    
    } 

    /// <summary> 
    /// Gets the Y-Intercept for a set of points using the formula: 
    /// b = AVG(y) - m(AVG(x)) 
    /// </summary> 
    /// <param name="points">Points to calculate the intercept from</param> 
    /// <returns>Y-Intercept</returns> 
    private static float YInterceptOfPoints(List<PointF> points, float slope) 
    { 
     float xBar = points.Average(p => p.X); 
     float yBar = points.Average(p => p.Y); 

     return yBar - (slope * xBar);   
    }  
} 

私たちのアプリケーションでは、小数点以下の桁数が存在することができるので、PointFを使用することを選択しました:私は、次を使用して式ということを再作成しました上でジェフの答えに感謝します。このようなアルゴリズムを開発するよりもコードを書いて時間を費やしているので、私は誰かが私に正しい言葉を間違えてもらうのが大好きだと思っています。

これは、Excel Interopがワークブックのトレンドメソッドを使用するためにバックグラウンドで読み込まれるのを待つよりも確かに高速です。

+0

ありがとう、素晴らしいコードです。 – Rocklan

関連する問題