C# parallel return value - c#

I use the following code to attempt to do a few calculations using values from two separate arrays. I've been trying to aggregate a list of values as a final step but every time I run the program it only has one set of values in the list. abcXLoopVars is a custom class to store the different variables which I aggregate later.
Parallel.For<abcXLoopVars>(0, colX.Count(),
() => { return new abcXLoopVars(); },
(i, pls, state) =>
{
state = new abcXLoopVars();
double x = Math.Abs(colX[i]);
double y = Math.Abs(colY[i]);
double lnx = Math.Log(x);
double lny = Math.Log(y);
double xminxbarsq = Math.Pow(colX[i] - xbar, 2);
double xminxbarcub = Math.Pow(colX[i] - xbar, 4);
state.sumxminxbarsq = xminxbarsq;
state.sumxminxbarcub = xminxbarcub;
state.sumlnxxminxbarsq = lnx * xminxbarsq;
state.sumlnxlny = lnx * lny;
state.sumlnxsq = Math.Pow(lnx, 2);
state.sumlnx = sumlnx + lnx;
state.sumlnyxminxbarsq = lny * xminxbarsq;
state.sumlny = lny;
state.posneg = colY[i] / colX[i];
return state;
},
(state) => { lock (lockMe) abxList.Add(state);}
);

I suggest you to rewrite it as PLINQ:
colX.Zip(colY, (x, y) =>
{
var state = new abcXLoopVars();
double lnx = Math.Log(x);
double lny = Math.Log(y);
double xminxbarsq = Math.Pow(x - xbar, 2);
double xminxbarcub = Math.Pow(x - xbar, 4);
state.sumxminxbarsq = xminxbarsq;
state.sumxminxbarcub = xminxbarcub;
state.sumlnxxminxbarsq = lnx * xminxbarsq;
state.sumlnxlny = lnx * lny;
state.sumlnxsq = Math.Pow(lnx, 2);
state.sumlnx = sumlnx + lnx;
state.sumlnyxminxbarsq = lny * xminxbarsq;
state.sumlny = lny;
state.posneg = y / x;
return state;
}).AsParallel().ToList();

Related

Average of List<objects> in c#

I have a list of object.
class Student
{
int age;
int height;
int weight;
int marksInMath;
int marksInScience;
.
.
.
.
.
.
int marksIn...;
}
List<Student> lst = new List<Student>();
I want to calculate median and average of this List.
I am aware of
lst.Average(x=>x.Age);
lst.Average(x=>x.height);
.
.
Similarly for Median I can sort and then get median
lst.OrderBy(x=>x.Age);
//median logic on lst
But I don't want to repeat this code for every field(age, height, weight, marks, etc) in the object. Is there a way to do this in a loop or any other way so I don't have to get average for each field individually?
Here's the one pass way to compute averages:
var averages =
lst
.Aggregate(
new
{
N = 0,
Age = 0,
Height = 0,
Weight = 0,
MarksInMath = 0,
MarksInScience = 0
},
(a, x) =>
new
{
N = a.N + 1,
Age = a.Age + x.Age,
Height = a.Height + x.Height,
Weight = a.Weight + x.Weight,
MarksInMath = a.MarksInMath + x.MarksInMath,
MarksInScience = a.MarksInScience + x.MarksInScience,
},
a =>
new
{
Age = (double)a.Age / a.N,
Height = (double)a.Height / a.N,
Weight = (double)a.Weight / a.N,
MarksInMath = (double)a.MarksInMath / a.N,
MarksInScience = (double)a.MarksInScience / a.N,
});
If you're after sums, stddev, etc, it's done the same way.
However, you're not going to be able compute the median without doing so on each property, one at a time.
I am at work so haven't been able to run this to see if it works. But if you can retrieve the values of each field using Student.fieldName then should be good. Not 100% on the studentStats.Add, whether that's how to add it or not. Just know I've done it before without needing the Tuple.
public List<(decimal avg, decimal med)> StudentScores(List<Student> students)
{
var fieldNames = typeof(Student).GetFields().Select(field=>field.Name).ToList();
var studentStats = new List<(decimal avg, decimal med)>();
foreach(var field in fieldNames)
{
var average = 0;
var count = 0;
List<decimal> fieldMedian = new List<decimal>();
foreach(var student in students)
{
count++
totalScore = average + student.field;
fieldMedian.Add(student.field);
}
average = totalScore / count;
var sorted = fieldMedian.Sort();
if(count%2 = 0)
{
var middle1 = count/2;
var middle2 = (count/2)+1;
var median = (sorted[middle1] + sorted[middle2]) / 2;
studentStats.Add(average, median);
}
else
{
var middle = (count+1)/2;
var median = sorted[middle];
studentStats.Add(average, median);
}
}
return studentStats;
}

How to calculate endPoint using initial point, distance and azimuth?

I need to find the endpoint using the start point, distance and azimuth. Here are the values of each one:
latitude: 37.624942,
longitude": -7.896333,
azimute: 233.0
distance : 20.0
Here is my function:
private List<double> findEndPoint(string latitudeStart, string longitudeStart, string azimute,double distancia)
{
List<double> endPoint = new List<double>();
double latitudeStartDouble = Convert.ToDouble(latitudeStart, System.Globalization.CultureInfo.InvariantCulture);
double longitudeStartDouble = Convert.ToDouble(longitudeStart, System.Globalization.CultureInfo.InvariantCulture);
double azimuteDouble = Convert.ToDouble(azimute, System.Globalization.CultureInfo.InvariantCulture);
double azimuteRadians = ConvertToRadians(azimuteDouble);
double R = 6371.0; // Raio da Terra em km
double latitudeEnd = Math.Asin(Math.Sin(latitudeStartDouble) * Math.Cos(distancia / R) +
Math.Cos(latitudeStartDouble) * Math.Sin(distancia / R) * Math.Cos(azimuteRadians));
endPoint.Add(latitudeEnd);
double longitudeEnd = longitudeStartDouble + Math.Atan2(
Math.Sin(azimuteRadians) * Math.Sin(distancia / R) * Math.Cos(latitudeStartDouble),
Math.Cos(distancia / R) - Math.Sin(latitudeStartDouble) * Math.Sin(latitudeEnd));
endPoint.Add(longitudeEnd);
return endPoint;
}
It returns:
latitude: -0.0760588400705975
longitude:-7.8988473639987093
The latitude must be wrong, but I don't know why is it giving me that value.
You forgot to add latitudeStartDouble. You just calculate the delta. So latitudeEnd = latitudeStartDouble + ...etc...
I need to be working with radians and then converting it back to degrees:
private List<double> findEndPoint(string latitudeStart, string longitudeStart, string azimute,double distancia)
{
List<double> endPoint = new List<double>();
double latitudeStartDouble = Convert.ToDouble(latitudeStart, System.Globalization.CultureInfo.InvariantCulture);
latitudeStartDouble = ConvertToRadians(latitudeStartDouble);
double longitudeStartDouble = Convert.ToDouble(longitudeStart, System.Globalization.CultureInfo.InvariantCulture);
longitudeStartDouble = ConvertToRadians(longitudeStartDouble);
double azimuteDouble = Convert.ToDouble(azimute, System.Globalization.CultureInfo.InvariantCulture);
double azimuteRadians = ConvertToRadians(azimuteDouble);
double R = 6371; // Raio da Terra em km
double latitudeEnd = Math.Asin(Math.Sin(latitudeStartDouble) * Math.Cos(distancia / R) +
Math.Cos(latitudeStartDouble) * Math.Sin(distancia / R) * Math.Cos(azimuteRadians));
latitudeEnd = ConvertToDegrees(latitudeEnd);
endPoint.Add(latitudeEnd);
double longitudeEnd = longitudeStartDouble + Math.Atan2(Math.Sin(azimuteRadians) * Math.Sin(distancia / R) * Math.Cos(latitudeStartDouble),
Math.Cos(distancia / R) - Math.Sin(latitudeStartDouble) * Math.Sin(latitudeEnd));
longitudeEnd = ConvertToDegrees(longitudeEnd);
endPoint.Add(longitudeEnd);
return endPoint;
}

Replicate Excel Power Trendline values with c#

I need to replicate this Excel graph in code
Given a list of [x, y] values, how can I obtain a new list of values to graph the power trendline?
I've found people referring to this http://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html formula. But don't know how to generate a new list of values from this.
Follow the formula from the link:
function getFittedPoints(data) {
var log = Math.log,
pow = Math.pow,
sums = [
0, // sum of the logarithms of x ( sum(log(x)) )
0, // sum of the logarithms of y ( sum(log(y)) )
0, // sum of the logarithms of the products of x and y ( sum(log(x) * log(y)) )
0 // sum of the powers of the logarithms of x ( sum((log(x))^2 )
],
fittedPoints = [], // return fitted points
a, // a coefficient
b, // b coefficient
dataLen = data.length,
i,
logX,
logY;
for (i = 0; i < dataLen; i++) {
sums[0] += logX = log(data[i][0]);
sums[1] += logY = log(data[i][1]);
sums[2] += logX * logY;
sums[3] += pow(logX, 2);
}
b = (i * sums[2] - sums[0] * sums[1]) / (i * sums[3] - pow(sums[0], 2));
a = pow(Math.E, (sums[1] - b * sums[0]) / i);
for (i = 0; i < dataLen; i++) {
fittedPoints.push([
data[i][0],
a * pow(data[i][0], b)
]);
}
return fittedPoints;
}
And then apply the function to the data.
example: http://jsfiddle.net/fa3m4Lvf/
Of course if your data are not clean then you can improve the function with handling null values,etc.
And for those like me who are looking for the C# version of morganfree's answer above, here it is translated:
public static IEnumerable<double> GetPowerTrendline(IList<double> knownY, IList<double> knownX, IList<double> newX)
{
var sums = new double[4];
var trendlinePoints = new List<double>();
var dataLen = knownX.Count;
for (var i = 0; i < dataLen; i++)
{
var logX = Math.Log(knownX[i]);
var logY = Math.Log(knownY[i]);
sums[0] += logX;
sums[1] += logY;
sums[2] += logX * logY;
sums[3] += Math.Pow(logX, 2);
}
var b = (dataLen * sums[2] - sums[0] * sums[1]) / (dataLen * sums[3] - Math.Pow(sums[0], 2));
var a = Math.Pow(Math.E, (sums[1] - b * sums[0]) / dataLen);
foreach (var x in newX)
{
var pointY = a * Math.Pow(x, b);
trendlinePoints.Add(pointY);
}
return trendlinePoints;
}
Note that it is modified so that it takes a list of desired x points instead of using the provided ones.
I followed the example calculation based on this: http://www.statisticshowto.com/how-to-find-a-linear-regression-equation/
Modified Adams example based on this and came upp with this solution for C#. This is assumes you have all the existing scatter plots. The result is a number of arraylists with the all the x and y values for the trendline that you can directly insert into highcharts.
public static List<ArrayList> GetPowerTrendline(List<KeyValuePair<int,double>> xyValues)
{
var trendlinePoints = new List<ArrayList>();
var dataLen = xyValues.Count;
var xSum = xyValues.Sum(h => h.Key);
var ySum = xyValues.Sum(h => h.Value);
var XYSum = xyValues.Sum(h => h.Key * h.Value);
var xp2Sum = xyValues.Sum(x => Math.Pow(x.Key, 2));
var a = (ySum * xp2Sum - xSum * XYSum) / (dataLen * xp2Sum - Math.Pow(xSum, 2));
var b = ((dataLen * XYSum) - (xSum * ySum)) / (dataLen * xp2Sum - Math.Pow(xSum,2));
foreach (var x in xyValues.OrderBy(h => h.Key))
{
var pointY = a + b * x.Key;
var rounded = Math.Round(pointY, 2);
trendlinePoints.Add(new ArrayList { x.Key, rounded });
}
return trendlinePoints;
}
And in my HighCharts method like this:
series: [
{
type: 'line',
name: 'Trendlinje',
data: data.RegressionLine,
color: '#444444',
marker: {
enabled: false
},
states: {
hover: {
lineWidth: 0
}
},
enableMouseTracking: false
},

Given an input float, round another float so it has the same numbers after the decimal separator as the first

The problem:
Given an input float (value), round another float (anotherValue) so it has the same significant figures as the first float (value).
What I have tried so far:
private static void Test()
{
var value = 0.12345f;
// ?? Strategy suggested by this post: http://stackoverflow.com/questions/3683718/is-there-a-way-to-get-the-significant-figures-of-a-decimal
var significantFigures = decimal.GetBits((decimal)value);
var anotherValue = 3.987654321;
// ERROR: Argument 2: cannot convert from int[] to int
var resultValue = (float) SetSignificantFigures((double)anotherValue, significantFigures.Length);
// Desired result: resultValue = 3.988
}
This is the definition of SetSignificantFigures:
// Function suggested by this post: http://stackoverflow.com/questions/374316/round-a-double-to-x-significant-figures
public static double SetSignificantFigures(double d, int digits)
{
double scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(d))) + 1);
return scale * Math.Round(d / scale, digits);
}
Blocking point: since decimal.GetBits returns int[], I don't know how to proceed (or if it is the correct strategy).
If you just want the number of digits why don't you parse the string equivalent of the number
var value = 12.123f;
var str = value.ToString().Split('.');
int decimalCount = 0;
if (str.Count() == 2)
{
decimalCount = str[1].Length; // this will give you 3.
}
Replace this
var resultValue = SetSignificantDigits(anotherValue, significantDigits);
with this
var resultValue = SetSignificantDigits(anotherValue, significantDigits.Length);
Or try this
var significantDigits = value.ToString().Split('.')[1].Length; //perhaps replace '.' with ','
And in the SetSignificantDigits-Function replace this
return scale * Math.Round(d / scale, digits);
with this
return Math.Round(scale * (d / scale), digits);
Then it looks like this:
var value = 0.12345f;
var significantDigits = value.ToString().Split(',')[1].Length;
var anotherValue = 3.987654321;
var resultValue = SetSignificantDigits(anotherValue, significantDigits);
public static double SetSignificantDigits(double d, int digits)
{
double scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(d))) + 1);
return Math.Round(scale * (d / scale), digits);
}
And the result is 3.98765

How do I calculate a trendline for a graph?

Google is not being my friend - it's been a long time since my stats class in college...I need to calculate the start and end points for a trendline on a graph - is there an easy way to do this? (working in C# but whatever language works for you)
Thanks to all for your help - I was off this issue for a couple of days and just came back to it - was able to cobble this together - not the most elegant code, but it works for my purposes - thought I'd share if anyone else encounters this issue:
public class Statistics
{
public Trendline CalculateLinearRegression(int[] values)
{
var yAxisValues = new List<int>();
var xAxisValues = new List<int>();
for (int i = 0; i < values.Length; i++)
{
yAxisValues.Add(values[i]);
xAxisValues.Add(i + 1);
}
return new Trendline(yAxisValues, xAxisValues);
}
}
public class Trendline
{
private readonly IList<int> xAxisValues;
private readonly IList<int> yAxisValues;
private int count;
private int xAxisValuesSum;
private int xxSum;
private int xySum;
private int yAxisValuesSum;
public Trendline(IList<int> yAxisValues, IList<int> xAxisValues)
{
this.yAxisValues = yAxisValues;
this.xAxisValues = xAxisValues;
this.Initialize();
}
public int Slope { get; private set; }
public int Intercept { get; private set; }
public int Start { get; private set; }
public int End { get; private set; }
private void Initialize()
{
this.count = this.yAxisValues.Count;
this.yAxisValuesSum = this.yAxisValues.Sum();
this.xAxisValuesSum = this.xAxisValues.Sum();
this.xxSum = 0;
this.xySum = 0;
for (int i = 0; i < this.count; i++)
{
this.xySum += (this.xAxisValues[i]*this.yAxisValues[i]);
this.xxSum += (this.xAxisValues[i]*this.xAxisValues[i]);
}
this.Slope = this.CalculateSlope();
this.Intercept = this.CalculateIntercept();
this.Start = this.CalculateStart();
this.End = this.CalculateEnd();
}
private int CalculateSlope()
{
try
{
return ((this.count*this.xySum) - (this.xAxisValuesSum*this.yAxisValuesSum))/((this.count*this.xxSum) - (this.xAxisValuesSum*this.xAxisValuesSum));
}
catch (DivideByZeroException)
{
return 0;
}
}
private int CalculateIntercept()
{
return (this.yAxisValuesSum - (this.Slope*this.xAxisValuesSum))/this.count;
}
private int CalculateStart()
{
return (this.Slope*this.xAxisValues.First()) + this.Intercept;
}
private int CalculateEnd()
{
return (this.Slope*this.xAxisValues.Last()) + this.Intercept;
}
}
OK, here's my best pseudo math:
The equation for your line is:
Y = a + bX
Where:
b = (sum(x*y) - sum(x)sum(y)/n) / (sum(x^2) - sum(x)^2/n)
a = sum(y)/n - b(sum(x)/n)
Where sum(xy) is the sum of all x*y etc. Not particularly clear I concede, but it's the best I can do without a sigma symbol :)
... and now with added Sigma
b = (Σ(xy) - (ΣxΣy)/n) / (Σ(x^2) - (Σx)^2/n)
a = (Σy)/n - b((Σx)/n)
Where Σ(xy) is the sum of all x*y etc. and n is the number of points
Given that the trendline is straight, find the slope by choosing any two points and calculating:
(A) slope = (y1-y2)/(x1-x2)
Then you need to find the offset for the line. The line is specified by the equation:
(B) y = offset + slope*x
So you need to solve for offset. Pick any point on the line, and solve for offset:
(C) offset = y - (slope*x)
Now you can plug slope and offset into the line equation (B) and have the equation that defines your line. If your line has noise you'll have to decide on an averaging algorithm, or use curve fitting of some sort.
If your line isn't straight then you'll need to look into Curve fitting, or Least Squares Fitting - non trivial, but do-able. You'll see the various types of curve fitting at the bottom of the least squares fitting webpage (exponential, polynomial, etc) if you know what kind of fit you'd like.
Also, if this is a one-off, use Excel.
Here is a very quick (and semi-dirty) implementation of Bedwyr Humphreys's answer. The interface should be compatible with #matt's answer as well, but uses decimal instead of int and uses more IEnumerable concepts to hopefully make it easier to use and read.
Slope is b, Intercept is a
public class Trendline
{
public Trendline(IList<decimal> yAxisValues, IList<decimal> xAxisValues)
: this(yAxisValues.Select((t, i) => new Tuple<decimal, decimal>(xAxisValues[i], t)))
{ }
public Trendline(IEnumerable<Tuple<Decimal, Decimal>> data)
{
var cachedData = data.ToList();
var n = cachedData.Count;
var sumX = cachedData.Sum(x => x.Item1);
var sumX2 = cachedData.Sum(x => x.Item1 * x.Item1);
var sumY = cachedData.Sum(x => x.Item2);
var sumXY = cachedData.Sum(x => x.Item1 * x.Item2);
//b = (sum(x*y) - sum(x)sum(y)/n)
// / (sum(x^2) - sum(x)^2/n)
Slope = (sumXY - ((sumX * sumY) / n))
/ (sumX2 - (sumX * sumX / n));
//a = sum(y)/n - b(sum(x)/n)
Intercept = (sumY / n) - (Slope * (sumX / n));
Start = GetYValue(cachedData.Min(a => a.Item1));
End = GetYValue(cachedData.Max(a => a.Item1));
}
public decimal Slope { get; private set; }
public decimal Intercept { get; private set; }
public decimal Start { get; private set; }
public decimal End { get; private set; }
public decimal GetYValue(decimal xValue)
{
return Intercept + Slope * xValue;
}
}
Regarding a previous answer
if (B) y = offset + slope*x
then (C) offset = y/(slope*x) is wrong
(C) should be:
offset = y-(slope*x)
See:
http://zedgraph.org/wiki/index.php?title=Trend
If you have access to Excel, look in the "Statistical Functions" section of the Function Reference within Help. For straight-line best-fit, you need SLOPE and INTERCEPT and the equations are right there.
Oh, hang on, they're also defined online here: http://office.microsoft.com/en-us/excel/HP052092641033.aspx for SLOPE, and there's a link to INTERCEPT. OF course, that assumes MS don't move the page, in which case try Googling for something like "SLOPE INTERCEPT EQUATION Excel site:microsoft.com" - the link given turned out third just now.
I converted Matt's code to Java so I could use it in Android with the MPAndroidChart library. Also used double values instead of integer values:
ArrayList<Entry> yValues2 = new ArrayList<>();
ArrayList<Double > xAxisValues = new ArrayList<Double>();
ArrayList<Double> yAxisValues = new ArrayList<Double>();
for (int i = 0; i < readings.size(); i++)
{
r = readings.get(i);
yAxisValues.add(r.value);
xAxisValues.add((double)i + 1);
}
TrendLine tl = new TrendLine(yAxisValues, xAxisValues);
//Create the y values for the trend line
double currY = tl.Start;
for (int i = 0; i < readings.size(); ++ i) {
yValues2.add(new Entry(i, (float) currY));
currY = currY + tl.Slope;
}
...
public class TrendLine
{
private ArrayList<Double> xAxisValues = new ArrayList<Double>();
private ArrayList<Double> yAxisValues = new ArrayList<Double>();
private int count;
private double xAxisValuesSum;
private double xxSum;
private double xySum;
private double yAxisValuesSum;
public TrendLine(ArrayList<Double> yAxisValues, ArrayList<Double> xAxisValues)
{
this.yAxisValues = yAxisValues;
this.xAxisValues = xAxisValues;
this.Initialize();
}
public double Slope;
public double Intercept;
public double Start;
public double End;
private double getArraySum(ArrayList<Double> arr) {
double sum = 0;
for (int i = 0; i < arr.size(); ++i) {
sum = sum + arr.get(i);
}
return sum;
}
private void Initialize()
{
this.count = this.yAxisValues.size();
this.yAxisValuesSum = getArraySum(this.yAxisValues);
this.xAxisValuesSum = getArraySum(this.xAxisValues);
this.xxSum = 0;
this.xySum = 0;
for (int i = 0; i < this.count; i++)
{
this.xySum += (this.xAxisValues.get(i)*this.yAxisValues.get(i));
this.xxSum += (this.xAxisValues.get(i)*this.xAxisValues.get(i));
}
this.Slope = this.CalculateSlope();
this.Intercept = this.CalculateIntercept();
this.Start = this.CalculateStart();
this.End = this.CalculateEnd();
}
private double CalculateSlope()
{
try
{
return ((this.count*this.xySum) - (this.xAxisValuesSum*this.yAxisValuesSum))/((this.count*this.xxSum) - (this.xAxisValuesSum*this.xAxisValuesSum));
}
catch (Exception e)
{
return 0;
}
}
private double CalculateIntercept()
{
return (this.yAxisValuesSum - (this.Slope*this.xAxisValuesSum))/this.count;
}
private double CalculateStart()
{
return (this.Slope*this.xAxisValues.get(0)) + this.Intercept;
}
private double CalculateEnd()
{
return (this.Slope*this.xAxisValues.get(this.xAxisValues.size()-1)) + this.Intercept;
}
}
This is the way i calculated the slope:
Source: http://classroom.synonym.com/calculate-trendline-2709.html
class Program
{
public double CalculateTrendlineSlope(List<Point> graph)
{
int n = graph.Count;
double a = 0;
double b = 0;
double bx = 0;
double by = 0;
double c = 0;
double d = 0;
double slope = 0;
foreach (Point point in graph)
{
a += point.x * point.y;
bx = point.x;
by = point.y;
c += Math.Pow(point.x, 2);
d += point.x;
}
a *= n;
b = bx * by;
c *= n;
d = Math.Pow(d, 2);
slope = (a - b) / (c - d);
return slope;
}
}
class Point
{
public double x;
public double y;
}
Here's what I ended up using.
public class DataPoint<T1,T2>
{
public DataPoint(T1 x, T2 y)
{
X = x;
Y = y;
}
[JsonProperty("x")]
public T1 X { get; }
[JsonProperty("y")]
public T2 Y { get; }
}
public class Trendline
{
public Trendline(IEnumerable<DataPoint<long, decimal>> dataPoints)
{
int count = 0;
long sumX = 0;
long sumX2 = 0;
decimal sumY = 0;
decimal sumXY = 0;
foreach (var dataPoint in dataPoints)
{
count++;
sumX += dataPoint.X;
sumX2 += dataPoint.X * dataPoint.X;
sumY += dataPoint.Y;
sumXY += dataPoint.X * dataPoint.Y;
}
Slope = (sumXY - ((sumX * sumY) / count)) / (sumX2 - ((sumX * sumX) / count));
Intercept = (sumY / count) - (Slope * (sumX / count));
}
public decimal Slope { get; private set; }
public decimal Intercept { get; private set; }
public decimal Start { get; private set; }
public decimal End { get; private set; }
public decimal GetYValue(decimal xValue)
{
return Slope * xValue + Intercept;
}
}
My data set is using a Unix timestamp for the x-axis and a decimal for the y. Change those datatypes to fit your need. I do all the sum calculations in one iteration for the best possible performance.
Thank You so much for the solution, I was scratching my head.
Here's how I applied the solution in Excel.
I successfully used the two functions given by MUHD in Excel:
a = (sum(x*y) - sum(x)sum(y)/n) / (sum(x^2) - sum(x)^2/n)
b = sum(y)/n - b(sum(x)/n)
(careful my a and b are the b and a in MUHD's solution).
- Made 4 columns, for example:
NB: my values y values are in B3:B17, so I have n=15;
my x values are 1,2,3,4...15.
1. Column B: Known x's
2. Column C: Known y's
3. Column D: The computed trend line
4. Column E: B values * C values (E3=B3*C3, E4=B4*C4, ..., E17=B17*C17)
5. Column F: x squared values
I then sum the columns B,C and E, the sums go in line 18 for me, so I have B18 as sum of Xs, C18 as sum of Ys, E18 as sum of X*Y, and F18 as sum of squares.
To compute a, enter the followin formula in any cell (F35 for me):
F35=(E18-(B18*C18)/15)/(F18-(B18*B18)/15)
To compute b (in F36 for me):
F36=C18/15-F35*(B18/15)
Column D values, computing the trend line according to the y = ax + b:
D3=$F$35*B3+$F$36, D4=$F$35*B4+$F$36 and so on (until D17 for me).
Select the column datas (C2:D17) to make the graph.
HTH.
If anyone needs the JS code for calculating the trendline of many points on a graph, here's what worked for us in the end:
/**#typedef {{
* x: Number;
* y:Number;
* }} Point
* #param {Point[]} data
* #returns {Function} */
function _getTrendlineEq(data) {
const xySum = data.reduce((acc, item) => {
const xy = item.x * item.y
acc += xy
return acc
}, 0)
const xSum = data.reduce((acc, item) => {
acc += item.x
return acc
}, 0)
const ySum = data.reduce((acc, item) => {
acc += item.y
return acc
}, 0)
const aTop = (data.length * xySum) - (xSum * ySum)
const xSquaredSum = data.reduce((acc, item) => {
const xSquared = item.x * item.x
acc += xSquared
return acc
}, 0)
const aBottom = (data.length * xSquaredSum) - (xSum * xSum)
const a = aTop / aBottom
const bTop = ySum - (a * xSum)
const b = bTop / data.length
return function trendline(x) {
return a * x + b
}
}
It takes an array of (x,y) points and returns the function of a y given a certain x
Have fun :)
Here's a working example in golang. I searched around and found this page and converted this over to what I needed. Hope someone else can find it useful.
// https://classroom.synonym.com/calculate-trendline-2709.html
package main
import (
"fmt"
"math"
)
func main() {
graph := [][]float64{
{1, 3},
{2, 5},
{3, 6.5},
}
n := len(graph)
// get the slope
var a float64
var b float64
var bx float64
var by float64
var c float64
var d float64
var slope float64
for _, point := range graph {
a += point[0] * point[1]
bx += point[0]
by += point[1]
c += math.Pow(point[0], 2)
d += point[0]
}
a *= float64(n) // 97.5
b = bx * by // 87
c *= float64(n) // 42
d = math.Pow(d, 2) // 36
slope = (a - b) / (c - d) // 1.75
// calculating the y-intercept (b) of the Trendline
var e float64
var f float64
e = by // 14.5
f = slope * bx // 10.5
intercept := (e - f) / float64(n) // (14.5 - 10.5) / 3 = 1.3
// output
fmt.Println(slope)
fmt.Println(intercept)
}

Categories