Excel > TREND() > C#実装の参考 (ビルドはできなかった) > C#実装した

```txt:動作確認
Excel 2013 on Windows 8.1 pro (64bit)
C# Online Snippet Compiler
```

Excelの関数を見ていく中、Trend()なるものを見つけた。

https://support.office.com/ja-JP/article/TREND-%E9%96%A2%E6%95%B0-E2F135F0-8827-4096-9873-9A7CF7B51EF1
> 回帰直線による予測値を返します。 R-2 乗値のメソッドを使って、直線を既知の y と既知の x の配列に当てはめます。 その直線上で、指定した新しい x の配列に対応する y の値が返されます。

サンプルとなるデータ例と、C#での実装は以下で記載されている。
http://stackoverflow.com/questions/7437660/how-do-i-recreate-an-excel-formula-which-calls-trend-in-c

answered May 23 '13 at 18:40
Mohgeroth
によるコードはC# Online Snippet Compilerで実行しようとしたらPointF型が見つからないエラーとなった。

考え方だけ参考にしておこう。

上記リンクに記載データでExcel上で計算した例。

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/319a6467-5bc9-107f-0277-1095bb595bac.png)

650に対して6.1が得られた。

## code v0.2 > C#実装

協力者のおかげでC#実装できました。

http://www.volatileread.com/utilitylibrary/snippetcompiler?id=74837

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
			
public class Program
{
    /// <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);        
    }         
  public static void Main()
  {
    var P = new PointF[]
    {
      new PointF { X = 600, Y = 6},
        new PointF { X = 800, Y = 7},
        new PointF { X = 1000, Y = 10},
        new PointF { X = 1200, Y = 12},
        new PointF { X = 1400, Y = 14},
    };
    
    var lst = new List<PointF>();
    foreach(var element in P) {
      lst.Add(element);
    }
    
    var res = LeastSquaresValueAtX(lst, 650);
    
    Console.WriteLine(res);
  }
}
```

```txt:結果
6.125
```

Excelの結果と整合した。

PointFの初期値リストを与えてforeachでAddするのは、もっと別にいい方法があるかもしれない。


## code v0.3 

http://www.volatileread.com/utilitylibrary/snippetcompiler?id=74861

@ozwk さんの[コメント](http://qiita.com/7of9/items/c1e67a19efcfa7eed500#comment-ff7e3b22c1256a08133e)を参考にコードを以下のようにしました。
情報感謝です。

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
			
public class Program
{
    /// <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);        
    }         

    public static void Main()
    {
        var lst = new List<PointF>{
    	      new PointF(600, 6), // X,Y 
            new PointF(800, 7),
            new PointF(1000, 10),
            new PointF(1200, 12),
            new PointF(1400, 14),     
        };
    
        var res = LeastSquaresValueAtX(lst, 650);
    
        Console.WriteLine(res);
    }
}
```

```txt:結果
6.125
```