5

I am trying to analyse some data using a C# app and need to calculate trend lines. I am aware that there are multiple types of trend line but for now I am trying to calculate exponential growth; I am going to be using it to predict future values. The equation I have been working off is

x(t) = x(0) * ((1+r)^t)

And this is the code that I have written to try and replicate the graph:

public void ExponentialBestFit(List<DateTime> xvalues, List<double> yvalues)

        {
            //Find the first value of y (The start value) and the first value of x (The start date)
            xzero = Convert.ToDouble(xvalues[0].ToOADate());
            yzero = yvalues[0];
            if (yzero == 0)
                yzero += 0.1;

            //For every value of x (exluding the 1st value) find the r value
            //
            //                       |   y   |          Where t = the time sinse the start time (time period)
            //Equation for r = t root|-------| - 1      Where y = the current y value
            //                       |  y[0] |          Where y[0] = the first y value  #IMPROVMENT - Average 1st y value in range
            //
            double r = 0;

            //c is a count of how many r values are added; it is not equal to the count of all the values
            int c = 0;
            for (int i = 1; i < xvalues.Count; i++)
            {
                r += Math.Pow(yvalues[i]/yzero, 1/(Convert.ToDouble(xvalues[i].ToOADate()) - xzero)) - 1;
                c++;
            }

            r = r / c;           
        }

The data I am passing in is over a period of time however the increments in which the time increases are not the same. When I created a chart in excel they use a different formula

x(t) = x(0)*(e^kt)

I think however I have no idea where the k value is being generated from. The two lists that I am passing in are Date and Value and each row in each list corresponds to the same row in the other list. The question is - Is there a better way of creating the equation and variables and are the variables I am getting the most accurate it can be for my data?

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
manicmonkey21421
  • 113
  • 2
  • 12
  • 1
    `e^kt` is the same as `(r+1)^t`, just with a different constant (`r = e^k - 1`) - i.e. I wouldn't worry about Excel having a different form, and you can use that formula to see if you get the same result as Excel does. – Rawling Jan 25 '13 at 14:10
  • @Rawling Ohh ok, thank-you. I tried to replicate the constant k using the rule of 70 where k = ln(2)/T and I get a very similar line although it has slightly more growth. I will try comparing the graphs against each other. Cheers! – manicmonkey21421 Jan 25 '13 at 14:18

3 Answers3

5

This is the c# version of the javascript provided.

    // Calculate Exponential Trendline / Growth
    IEnumerable<double> Growth(IList<double> knownY, IList<double> knownX, IList<double> newX, bool useConst)
    {
        // Credits: Ilmari Karonen

        // Default values for optional parameters:
        if (knownY == null) return null;
        if (knownX == null)
        {
            knownX = new List<double>();
            for (var i  = 0; i<=knownY.Count; i++)
                knownX.Add(i);
        }
        if (newX == null)
        {
            newX = new List<double>();
            for (var i = 0; i <= knownY.Count; i++)
                newX.Add(i);
        }

        int n = knownY.Count;
        double avg_x = 0.0;
        double avg_y = 0.0;
        double avg_xy = 0.0;
        double avg_xx = 0.0;
        double beta = 0.0;
        double alpha = 0.0;
        for (var i = 0; i < n; i++)
        {
            var x = knownX[i];
            var y = Math.Log(knownY[i]);
            avg_x += x;
            avg_y += y;
            avg_xy += x * y;
            avg_xx += x * x;
        }
        avg_x /= n;
        avg_y /= n;
        avg_xy /= n;
        avg_xx /= n;

        // Compute linear regression coefficients:
        if (useConst)
        {
            beta = (avg_xy - avg_x * avg_y) / (avg_xx - avg_x * avg_x);
            alpha = avg_y - beta * avg_x;
        }
        else
        {
            beta = avg_xy / avg_xx;
            alpha = 0.0;
        }

        // Compute and return result array:
        return newX.Select(t => Math.Exp(alpha + beta*t)).ToList();

    }
Vitox
  • 3,852
  • 29
  • 30
TYY
  • 2,702
  • 1
  • 13
  • 14
  • Thank-you very much, I have had some success in using the previously provided JAVA and comparing it against my original function and they seem pretty similar, however I shall try using your converted code and see what the graph looks like. Cheers – manicmonkey21421 Jan 29 '13 at 07:56
  • 1
    Just want to point that the places in the code where ".Add(i++);" is used should be changed to ".Add(i);" or you'll double increment your indices resulting in smaller collections. Tried to edit the answer to reflect that but the edits have to be at least 6 character changes. :) – ASeale Apr 21 '15 at 16:03
  • @ASeale just did the edit. Now the code is correct. – Vitox Oct 24 '22 at 12:40
1

The following JavaScript code should help. I used it to implement Excel's GROWTH function. It's written in JavaScript, but porting it to C# should be very easy. Please note that most of it was written by someone else (credits in the code).

function GROWTH(known_y, known_x, new_x, use_const) {
  // Credits: Ilmari Karonen

  // Default values for optional parameters:
  if (typeof(known_x) == 'undefined') {
    known_x = [];
    for (var i = 1; i <= known_y.length; i++) known_x.push(i);
  }
  if (typeof(new_x) == 'undefined') {
    new_x = [];
    for (var i = 1; i <= known_y.length; i++) new_x.push(i);
  }
  if (typeof(use_const) == 'undefined') use_const = true;

  // Calculate sums over the data:
  var n = known_y.length;
  var avg_x = 0;
  var avg_y = 0;
  var avg_xy = 0;
  var avg_xx = 0; 
  for (var i = 0; i < n; i++) {
    var x = known_x[i];
    var y = Math.log(known_y[i]);
    avg_x += x;
    avg_y += y;
    avg_xy += x*y;
    avg_xx += x*x;
  }
  avg_x /= n;
  avg_y /= n;
  avg_xy /= n;
  avg_xx /= n;

  // Compute linear regression coefficients:
  if (use_const) {
    var beta = (avg_xy - avg_x*avg_y) / (avg_xx - avg_x*avg_x);
    var alpha = avg_y - beta*avg_x;
  } else {
    var beta = avg_xy / avg_xx;
    var alpha = 0;
  }

  // Compute and return result array:
  var new_y = [];
  for (var i = 0; i < new_x.length; i++) {
    new_y.push(Math.exp(alpha + beta * new_x[i]));
  }
  return new_y;
}
Ismael Ghalimi
  • 3,515
  • 2
  • 22
  • 25
0

Since x(t)=x(0)*e^{kt}, we can take logarithms to get ln x(t)=ln x(0) + kt. This means that to find ln x(0) and k, you can find the least squares fit for the data {(t,ln x(t))}. This will tell you that ln x(t) = b + at, so that k=a and x(0)=e^b.

Teepeemm
  • 4,331
  • 5
  • 35
  • 58