I draw a bunch of line graphs using LiveCharts and WPF, where the contents and the number of line charts are determined at run time. So I don't know in advance how many LineSeries will be there, and what their values will be. However, I know the good range for each LineSeries. For example, one series, let's call it S1 has a good range of 2+/-1. So anything between 1 and 3 are considered to be good. Similarly there can be another, say S2 where range is 30+/-2, so anything between 28 and 32 is good.
I would like to draw the line graph so that sections that are within range are drawn as a solid line, but if a section is outside the range, it would be a dotted/dash line. Since I have multiple LineSeries in one, I have plotted each in its own Y-axis. My XAML and code looks like this:
<Grid>
<lvc:CartesianChart Name="MyChart" Margin="4"
Series="{Binding SeriesCollection}"/>
</Grid>
Code behind:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public SeriesCollection SeriesCollection { get; set; }
public MainWindow()
{
InitializeComponent();
PlotGraph();
}
private void PlotGraph()
{
SeriesCollection = new SeriesCollection();
var lineSeries1 = new LineSeries
{
Title = "S1",
Values = new ChartValues<double>() { 2.3, 2.0, 3.1, 1.3, 0.5, 3.8, 7.3, 2.4, 1.2, 0.1 },
DataLabels = true,
Stroke = Brushes.Green,
Fill = Brushes.Transparent,
ScalesYAt = 0
};
var lineSeries2 = new LineSeries
{
Title = "S2",
Values = new ChartValues<double>() { 32.5, 34.5, 29.5, 26.0, 25.8, 30.5, 32.1, 36.5, 32.4, 24.5 },
DataLabels = true,
Stroke = Brushes.HotPink,
Fill = Brushes.Transparent,
ScalesYAt = 1
};
SeriesCollection.Add(lineSeries1);
SeriesCollection.Add(lineSeries2);
MyChart.AxisY.Add(new Axis());
MyChart.AxisY.Add(new Axis());
DataContext = this;
}
}
I found an example here that the PointState is colored based on values, but it doesn't work for me because I draw multiple series in one. Also, my graph has thousands of points so I have disabled PointGeometry since if I enable them they will be very hard to see anyway.
Is what I want possible at all?
i have found a solution, in fact 2: either you customize livechart to your problem or you recalculate the differents points like i do below:
its just a way, an idea to answer to your question, all things are possible, but need some line of codes....
the plotgraph method
private void PlotGraph()
{
var points = new List<Point>() { new Point(0, 2.3), new Point(1, 2.0),
new Point(2, 3.1), new Point(3, 1.3),
new Point(4, 0.5), new Point(5, 3.8),
new Point(6, 7.3), new Point(7, 2.4),
new Point(8, 1.2), new Point(9, 0.1)};
var range1 = new double[] { 1d, 3d };
var otherpoints = CurvesMath.GetInterpolatedCubicSplinedCurve(points);
var pointscurve = otherpoints.Select(p => p.Y).ToArray();
SeriesCollection = new SeriesCollection();
var lineSeries1 = new LineSeries
{
Title = "S1",
Values = new ChartValues<double>(pointscurve),
DataLabels = false,
Stroke = Brushes.Transparent,
Fill = Brushes.Transparent,
ScalesYAt = 0,
PointGeometrySize = 2,
Configuration = Mappers.Xy<double>()
.X((value, index) => index)
.Y((value, index) => value)
.Stroke((value, index) => value <= range1[0] || value >= range1[1] ? Brushes.Red : Brushes.Blue)
.Fill((value, index) => value <= range1[0] || value >= range1[1] ? Brushes.Red : Brushes.Blue)
};
points = new List<Point>() { new Point(0, 32.5), new Point(1, 34.5),
new Point(2, 29.5), new Point(3, 26.0),
new Point(4, 25.8), new Point(5, 30.5),
new Point(6, 32.1), new Point(7, 36.5),
new Point(8, 32.4), new Point(9, 24.5)};
var range2 = new double[] { 28d, 32d };
otherpoints = CurvesMath.GetInterpolatedCubicSplinedCurve(points);
pointscurve = otherpoints.Select(p => p.Y).ToArray();
var lineSeries2 = new LineSeries
{
Title = "S2",
Values = new ChartValues<double>(pointscurve),
DataLabels = false,
Stroke = Brushes.Transparent,
Fill = Brushes.Transparent,
ScalesYAt = 1,
PointGeometrySize = 2,
Configuration = Mappers.Xy<double>()
.X((value, index) => index)
.Y((value, index) => value)
.Stroke((value, index) => value <= range2[0] || value >= range2[1] ? Brushes.Red : Brushes.Green)
.Fill((value, index) => value <= range2[0] || value >= range2[1] ? Brushes.Red : Brushes.Green)
};
SeriesCollection.Add(lineSeries1);
SeriesCollection.Add(lineSeries2);
MyChart.AxisY.Add(new Axis());
MyChart.AxisY.Add(new Axis());
DataContext = this;
}
the xaml file:
<Grid>
<lvc:CartesianChart Name="MyChart" Margin="4"
Series="{Binding SeriesCollection}" >
</lvc:CartesianChart>
</Grid>
the interpolation cubic spline (or bezier)
using System.Collections.Generic;
using System.Linq;
using System.Windows;
namespace WpfApp2
{
public static class CurvesMath
{
private const int precision = 80;
public static List<Point> GetInterpolatedCubicSplinedCurve(IList<Point> points)
{
var output = new List<Point>();
int np = points.Count; // number of points
double[] yCoords = new double[np]; // Newton form coefficients
double[] xCoords = new double[np]; // x-coordinates of nodes
double y;
double x;
if (np > 0)
{
for (int i = 0; i < np; i++)
{
var p = points[i];
xCoords[i] = p.X;
yCoords[i] = p.Y;
}
if (np > 1)
{
double[] a = new double[np];
double x1;
double x2;
double[] h = new double[np];
for (int i = 1; i <= np - 1; i++)
{
h[i] = xCoords[i] - xCoords[i - 1];
}
if (np > 2)
{
double[] sub = new double[np - 1];
double[] diag = new double[np - 1];
double[] sup = new double[np - 1];
for (int i = 1; i <= np - 2; i++)
{
diag[i] = (h[i] + h[i + 1]) / 3;
sup[i] = h[i + 1] / 6;
sub[i] = h[i] / 6;
a[i] = (yCoords[i + 1] - yCoords[i]) / h[i + 1] - (yCoords[i] - yCoords[i - 1]) / h[i];
}
SolveTridiag(sub, diag, sup, ref a, np - 2);
}
output.Add(points.First());
for (int i = 1; i <= np - 1; i++)
{
// loop over intervals between nodes
for (int j = 1; j <= precision; j++)
{
x1 = (h[i] * j) / precision;
x2 = h[i] - x1;
y = ((-a[i - 1] / 6 * (x2 + h[i]) * x1 + yCoords[i - 1]) * x2 +
(-a[i] / 6 * (x1 + h[i]) * x2 + yCoords[i]) * x1) / h[i];
x = xCoords[i - 1] + x1;
output.Add(new Point(x, y));
}
}
}
}
return output;
}
public static double SolveCubicSpline(IList<Point> knownSamples, double z)
{
int np = knownSamples.Count;
if (np > 1)
{
if (knownSamples[0].X == z) return knownSamples[0].Y;
double[] a = new double[np];
double x1;
double x2;
double y;
double[] h = new double[np];
for (int i = 1; i <= np - 1; i++)
{
h[i] = knownSamples[i].X - knownSamples[i - 1].X;
}
if (np > 2)
{
double[] sub = new double[np - 1];
double[] diag = new double[np - 1];
double[] sup = new double[np - 1];
for (int i = 1; i <= np - 2; i++)
{
diag[i] = (h[i] + h[i + 1]) / 3;
sup[i] = h[i + 1] / 6;
sub[i] = h[i] / 6;
a[i] = (knownSamples[i + 1].Y - knownSamples[i].Y) / h[i + 1] -
(knownSamples[i].Y - knownSamples[i - 1].Y) / h[i];
}
// SolveTridiag is a support function, see Marco Roello's original code
// for more information at
// http://www.codeproject.com/useritems/SplineInterpolation.asp
SolveTridiag(sub, diag, sup, ref a, np - 2);
}
int gap = 0;
double previous = double.MinValue;
// At the end of this iteration, "gap" will contain the index of the interval
// between two known values, which contains the unknown z, and "previous" will
// contain the biggest z value among the known samples, left of the unknown z
for (int i = 0; i < knownSamples.Count; i++)
{
if (knownSamples[i].X < z && knownSamples[i].X > previous)
{
previous = knownSamples[i].X;
gap = i + 1;
}
}
x1 = z - previous;
if (gap > h.Length - 1)
return z;
x2 = h[gap] - x1;
if (gap == 0)
return 0.0;
y = ((-a[gap - 1] / 6 * (x2 + h[gap]) * x1 + knownSamples[gap - 1].Y) * x2 +
(-a[gap] / 6 * (x1 + h[gap]) * x2 + knownSamples[gap].Y) * x1) / h[gap];
return y;
}
return 0;
}
private static void SolveTridiag(double[] sub, double[] diag, double[] sup, ref double[] b, int n)
{
/* solve linear system with tridiagonal n by n matrix a
using Gaussian elimination *without* pivoting
where a(i,i-1) = sub[i] for 2<=i<=n
a(i,i) = diag[i] for 1<=i<=n
a(i,i+1) = sup[i] for 1<=i<=n-1
(the values sub[1], sup[n] are ignored)
right hand side vector b[1:n] is overwritten with solution
NOTE: 1...n is used in all arrays, 0 is unused */
int i;
/* factorization and forward substitution */
for (i = 2; i <= n; i++)
{
sub[i] = sub[i] / diag[i - 1];
diag[i] = diag[i] - sub[i] * sup[i - 1];
b[i] = b[i] - sub[i] * b[i - 1];
}
b[n] = b[n] / diag[n];
for (i = n - 1; i >= 1; i--)
{
b[i] = (b[i] - sup[i] * b[i + 1]) / diag[i];
}
}
}
}
in the result you see all bad parts with the color RED
Related
Well i've been doing some work with AI and object detection and have recently encounter somewhat of a problem with a model that i exported from CustomVision.
For the ones who know what i'm talking about, when you export a model from CustomVision you get a .cs file included that represents the class with everything you need to use the model.
And there starts all my problems.. first and most important one is that in one of the methods, specifically in the "ExtractBoxes" method receives a TensorFloat object and a float array of anchors.
Anyways.. inside this method there's 4 variables called "channels", "height" and "width" that come from a list inside of the TensorFloat object called "shape".
Given all this.. my question resides in the TensorFloat object, more specifically in how can i get the values for the variables "channels", "height" and "width" without having a TensorFloat object.
Below im going to include the code from the .cs file that im talking about.
Thanks in advance!
public async Task<IList<PredictionModel>> PredictImageAsync(VideoFrame image)
{
var imageWidth = image.SoftwareBitmap.PixelWidth;
var imageHeight = image.SoftwareBitmap.PixelHeight;
double ratio = Math.Sqrt((double)imageInputSize / (double)imageWidth / (double)imageHeight);
int targetWidth = 32 * (int)Math.Round(imageWidth * ratio / 32);
int targetHeight = 32 * (int)Math.Round(imageHeight * ratio / 32);
using (var resizedBitmap = await ResizeBitmap(image.SoftwareBitmap, targetWidth, targetHeight))
using (VideoFrame resizedVideoFrame = VideoFrame.CreateWithSoftwareBitmap(resizedBitmap))
{
var imageFeature = ImageFeatureValue.CreateFromVideoFrame(resizedVideoFrame);
var bindings = new LearningModelBinding(this.session);
bindings.Bind("input", imageFeature);
var result = await this.session.EvaluateAsync(bindings, "");
return Postprocess(result.Outputs["output"] as TensorFloat);
}
}
private List<PredictionModel> Postprocess(TensorFloat predictionOutputs)
{
var extractedBoxes = this.ExtractBoxes(predictionOutputs, ObjectDetection.Anchors);
return this.SuppressNonMaximum(extractedBoxes);
}
private ExtractedBoxes ExtractBoxes(TensorFloat predictionOutput, float[] anchors)
{
var shape = predictionOutput.Shape;
Debug.Assert(shape.Count == 4, "The model output has unexpected shape");
Debug.Assert(shape[0] == 1, "The batch size must be 1");
IReadOnlyList<float> outputs = predictionOutput.GetAsVectorView();
var numAnchor = anchors.Length / 2;
var channels = shape[1];
var height = shape[2];
var width = shape[3];
Debug.Assert(channels % numAnchor == 0);
var numClass = (channels / numAnchor) - 5;
Debug.Assert(numClass == this.labels.Count);
var boxes = new List<BoundingBox>();
var probs = new List<float[]>();
for (int gridY = 0; gridY < height; gridY++)
{
for (int gridX = 0; gridX < width; gridX++)
{
int offset = 0;
int stride = (int)(height * width);
int baseOffset = gridX + gridY * (int)width;
for (int i = 0; i < numAnchor; i++)
{
var x = (Logistic(outputs[baseOffset + (offset++ * stride)]) + gridX) / width;
var y = (Logistic(outputs[baseOffset + (offset++ * stride)]) + gridY) / height;
var w = (float)Math.Exp(outputs[baseOffset + (offset++ * stride)]) * anchors[i * 2] / width;
var h = (float)Math.Exp(outputs[baseOffset + (offset++ * stride)]) * anchors[i * 2 + 1] / height;
x = x - (w / 2);
y = y - (h / 2);
var objectness = Logistic(outputs[baseOffset + (offset++ * stride)]);
var classProbabilities = new float[numClass];
for (int j = 0; j < numClass; j++)
{
classProbabilities[j] = outputs[baseOffset + (offset++ * stride)];
}
var max = classProbabilities.Max();
for (int j = 0; j < numClass; j++)
{
classProbabilities[j] = (float)Math.Exp(classProbabilities[j] - max);
}
var sum = classProbabilities.Sum();
for (int j = 0; j < numClass; j++)
{
classProbabilities[j] *= objectness / sum;
}
if (classProbabilities.Max() > this.probabilityThreshold)
{
boxes.Add(new BoundingBox(x, y, w, h));
probs.Add(classProbabilities);
}
}
Debug.Assert(offset == channels);
}
}
Debug.Assert(boxes.Count == probs.Count);
return new ExtractedBoxes(boxes, probs);
}
I'm trying to create a simple edge detection filter. And as I said it works with only one image. I'm trying to create this filter with 2 steps.
Blurring image (with meanfilter)
Calculate ( Original image-Blurring image)
The first step works well. And code of second one is simple like first one. But I see an error message:
System.ArgumentOutOfRangeException: 'Parameter must be positive and < Height.
Parameter name: y'
Working image:https://i.hizliresim.com/dLXkbn.png
My code:
public void edgedetectionfilter( )
{
Bitmap InputPicture,BlurredPicture, OutputPicture;
InputPicture = new Bitmap(pBox_SOURCE.Image);
BlurredPicture = new Bitmap(pBox_PROCESSED.Image);
int PicWidth = InputPicture.Width;
int PicHeight= InputPicture.Height;
OutputPicture = new Bitmap(PicWidth, PicHeight);
OutputPicture = InputPicture;
int x, y, difR, difG, difB;
Color OrgPicColoValue,BluredPicColorValue;
for (x = 0; x < PicWidth; x++)
{
for (y = 0; y < PicWidth; y++)
{
BluredPicColorValue = BlurredPicture.GetPixel(x, y);
OrgPicColoValue = InputPicture.GetPixel(x, y); //ERROR LINE
difR = Convert.ToInt16(OrgPicColoValue.R -BluredPicColorValue.R);
difG = Convert.ToInt16(OrgPicColoValue.G- BluredPicColorValue.G );
difB = Convert.ToInt16(OrgPicColoValue.B- BluredPicColorValue.B);
if (difR > 255) difR = 255;
if (difG > 255) difG = 255;
if (difB > 255) difB = 255;
if (difR < 0) difR = 0;
if (difG < 0) difG = 0;
if (difB < 0) difB = 0;
OutputPicture.SetPixel(x, y, Color.FromArgb(difR, difG, difB));
}
}
pBoxMedian.Image = OutputPicture;
}
public void meanfilter(int p)
//KERNELSIZE=P
{
if (sliderKernel.Value % 2 == 0)
{
MessageBox.Show("Enter an odd number");
return;
}
Color ColorValue;
Bitmap InputPicture, OutputPicture;
InputPicture = new Bitmap(pBox_SOURCE.Image);
int PicWidth = InputPicture.Width;
int PicHeight= InputPicture.Height;
OutputPicture = new Bitmap(PicWidth, PicHeight);
OutputPicture = InputPicture;
int x, y, i, j, sumR, sumG, sumB, avgR, avgG, avgB;
for (x = (KernelSize - 1) / 2; x < PicWidth - (KernelSize - 1) / 2; x++)
{
for (y = (KernelSize - 1) / 2; y < PicHeight - (KernelSize- 1) / 2; y++)
{
toplamR = 0;
toplamG = 0;
toplamB = 0;
for (i = -((KernelSize - 1) / 2); i <= (KernelSize - 1) / 2; i++)
{
for (j = -((KernelSize - 1) / 2); j <= (KernelSize - 1) / 2; j++)
{
ColorValue= InputPicture.GetPixel(x + i, y + j);
sumR = sumR + ColorValue.R;
sumG = sumG + ColorValue.G;
sumB = sumB + ColorValue.B;
}
}
avgR = sumR / (KernelSize * KernelSize );
avgG = sumG / (KernelSize *KernelSize );
avgB = sumB / (KernelSize * KernelSize );
OutputPicture.SetPixel(x, y, Color.FromArgb(avgR, avgG, avgB));
}
}
pBox_PROCESSED.Image = OutputPicture;
}
You compare y < PicWidth, whereas you probably want y < PicHeight. Is the image it worked on square, by chance?
I have two Line Segments, represented by a 3D point at their beginning/end points.
Line:
class Line
{
public string Name { get; set; }
public Point3D Start { get; set; } = new Point3D();
public Point3D End { get; set; } = new Point3D();
}
The 3D points are just 3 doubles for coordinates X,Y and Z.
3DPoint:
class Point3D
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
}
The Question:
Can I find the distance between two 'Lines' and the endpoints of that distance 'Line'. [1
What I have:
Currently, I can successfully get the distance between the two lines with this code (Adapted From Here Using the Segment To Segment Section):
public double lineNearLine(Line l1, Line l2)
{
Vector3D uS = new Vector3D { X = l1.Start.X, Y = l1.Start.Y, Z = l1.Start.Z };
Vector3D uE = new Vector3D { X = l1.End.X, Y = l1.End.Y, Z = l1.End.Z };
Vector3D vS = new Vector3D { X = l2.Start.X, Y = l2.Start.Y, Z = l2.Start.Z };
Vector3D vE = new Vector3D { X = l2.End.X, Y = l2.End.Y, Z = l2.End.Z };
Vector3D w1 = new Vector3D { X = l1.Start.X, Y = l1.Start.Y, Z = l1.Start.Z };
Vector3D w2 = new Vector3D { X = l2.Start.X, Y = l2.Start.Y, Z = l2.Start.Z };
Vector3D u = uE - uS;
Vector3D v = vE - vS;
Vector3D w = w1 - w2;
double a = Vector3D.DotProduct(u, u);
double b = Vector3D.DotProduct(u, v);
double c = Vector3D.DotProduct(v, v);
double d = Vector3D.DotProduct(u, w);
double e = Vector3D.DotProduct(v, w);
double D = a * c - b * b;
double sc, sN, sD = D;
double tc, tN, tD = D;
if (D < 0.01)
{
sN = 0;
sD = 1;
tN = e;
tD = c;
}
else
{
sN = (b * e - c * d);
tN = (a * e - b * d);
if (sN < 0)
{
sN = 0;
tN = e;
tD = c;
}
else if (sN > sD)
{
sN = sD;
tN = e + b;
tD = c;
}
}
if (tN < 0)
{
tN = 0;
if (-d < 0)
{
sN = 0;
}
else if (-d > a)
{
sN = sD;
}
else
{
sN = -d;
sD = a;
}
}
else if (tN > tD)
{
tN = tD;
if ((-d + b) < 0)
{
sN = 0;
}
else if ((-d + b) > a)
{
sN = sD;
}
else
{
sN = (-d + b);
sD = a;
}
}
if (Math.Abs(sN) < 0.01)
{
sc = 0;
}
else
{
sc = sN / sD;
}
if (Math.Abs(tN) < 0.01)
{
tc = 0;
}
else
{
tc = tN / tD;
}
Vector3D dP = w + (sc * u) - (tc * v);
double distance1 = Math.Sqrt(Vector3D.DotProduct(dP, dP));
return distance1;
}
What I Need:
Is there any way to determine the endpoints of the displacement vector 'dP' from the code above? If not, can anyone suggest a better method for finding minimum distance and the endpoints of that distance?
Thank you for Reading, and Thanks in advance for any suggestions!
An Enormous Thank You to #Isaac van Bakel for the theory behind this Solution
Here is my code complete: Shortest distance between two lines represented by the line that connects them at that shortest distance.
Classes:
Sharp3D.Math : I use this reference for Vector3D, but really any 3D vector class will work. On top of that, the vectors aren't even required if you do the subtraction element by element.
Point3D : My Personal Point3D class. Feel free to use as much or little as you want.
class Point3D
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public Vector3D getVector()
{
return new Vector3D { X = this.X, Y = this.Y, Z = this.Z };
}
}
Line : My Personal Line class. Feel free to use as much or little as you want.
class Line
{
public string Name { get; set; }
public Point3D Start { get; set; } = new Point3D();
public Point3D End { get; set; } = new Point3D();
public double Length
{
get
{
return Math.Sqrt(Math.Pow((End.X - Start.X), 2) + Math.Pow((End.Y - Start.Y), 2));
}
}
}
Functions:
ClampPointToLine : Clamping function I wrote to clamp a point to a line.
public Point3D ClampPointToLine(Point3D pointToClamp, Line lineToClampTo)
{
Point3D clampedPoint = new Point3D();
double minX, minY, minZ, maxX, maxY, maxZ;
if(lineToClampTo.Start.X <= lineToClampTo.End.X)
{
minX = lineToClampTo.Start.X;
maxX = lineToClampTo.End.X;
}
else
{
minX = lineToClampTo.End.X;
maxX = lineToClampTo.Start.X;
}
if (lineToClampTo.Start.Y <= lineToClampTo.End.Y)
{
minY = lineToClampTo.Start.Y;
maxY = lineToClampTo.End.Y;
}
else
{
minY = lineToClampTo.End.Y;
maxY = lineToClampTo.Start.Y;
}
if (lineToClampTo.Start.Z <= lineToClampTo.End.Z)
{
minZ = lineToClampTo.Start.Z;
maxZ = lineToClampTo.End.Z;
}
else
{
minZ = lineToClampTo.End.Z;
maxZ = lineToClampTo.Start.Z;
}
clampedPoint.X = (pointToClamp.X < minX) ? minX : (pointToClamp.X > maxX) ? maxX : pointToClamp.X;
clampedPoint.Y = (pointToClamp.Y < minY) ? minY : (pointToClamp.Y > maxY) ? maxY : pointToClamp.Y;
clampedPoint.Z = (pointToClamp.Z < minZ) ? minZ : (pointToClamp.Z > maxZ) ? maxZ : pointToClamp.Z;
return clampedPoint;
}
distanceBetweenLines : The function that returns the line that represents the shortest distance between two lines. Returns null if unsolvable.
public Line distBetweenLines(Line l1, Line l2)
{
Vector3D p1, p2, p3, p4, d1, d2;
p1 = l1.Start.getVector();
p2 = l1.End.getVector();
p3 = l2.Start.getVector();
p4 = l2.End.getVector();
d1 = p2 - p1;
d2 = p4 - p3;
double eq1nCoeff = (d1.X * d2.X) + (d1.Y * d2.Y) + (d1.Z * d2.Z);
double eq1mCoeff = (-(Math.Pow(d1.X, 2)) - (Math.Pow(d1.Y, 2)) - (Math.Pow(d1.Z, 2)));
double eq1Const = ((d1.X * p3.X) - (d1.X * p1.X) + (d1.Y * p3.Y) - (d1.Y * p1.Y) + (d1.Z * p3.Z) - (d1.Z * p1.Z));
double eq2nCoeff = ((Math.Pow(d2.X, 2)) + (Math.Pow(d2.Y, 2)) + (Math.Pow(d2.Z, 2)));
double eq2mCoeff = -(d1.X * d2.X) - (d1.Y * d2.Y) - (d1.Z * d2.Z);
double eq2Const = ((d2.X * p3.X) - (d2.X * p1.X) + (d2.Y * p3.Y) - (d2.Y * p2.Y) + (d2.Z * p3.Z) - (d2.Z * p1.Z));
double[,] M = new double[,] { { eq1nCoeff, eq1mCoeff, -eq1Const }, { eq2nCoeff, eq2mCoeff, -eq2Const } };
int rowCount = M.GetUpperBound(0) + 1;
// pivoting
for (int col = 0; col + 1 < rowCount; col++) if (M[col, col] == 0)
// check for zero coefficients
{
// find non-zero coefficient
int swapRow = col + 1;
for (; swapRow < rowCount; swapRow++) if (M[swapRow, col] != 0) break;
if (M[swapRow, col] != 0) // found a non-zero coefficient?
{
// yes, then swap it with the above
double[] tmp = new double[rowCount + 1];
for (int i = 0; i < rowCount + 1; i++)
{ tmp[i] = M[swapRow, i]; M[swapRow, i] = M[col, i]; M[col, i] = tmp[i]; }
}
else return null; // no, then the matrix has no unique solution
}
// elimination
for (int sourceRow = 0; sourceRow + 1 < rowCount; sourceRow++)
{
for (int destRow = sourceRow + 1; destRow < rowCount; destRow++)
{
double df = M[sourceRow, sourceRow];
double sf = M[destRow, sourceRow];
for (int i = 0; i < rowCount + 1; i++)
M[destRow, i] = M[destRow, i] * df - M[sourceRow, i] * sf;
}
}
// back-insertion
for (int row = rowCount - 1; row >= 0; row--)
{
double f = M[row, row];
if (f == 0) return null;
for (int i = 0; i < rowCount + 1; i++) M[row, i] /= f;
for (int destRow = 0; destRow < row; destRow++)
{ M[destRow, rowCount] -= M[destRow, row] * M[row, rowCount]; M[destRow, row] = 0; }
}
double n = M[0, 2];
double m = M[1, 2];
Point3D i1 = new Point3D { X = p1.X + (m * d1.X), Y = p1.Y + (m * d1.Y), Z = p1.Z + (m * d1.Z) };
Point3D i2 = new Point3D { X = p3.X + (n * d2.X), Y = p3.Y + (n * d2.Y), Z = p3.Z + (n * d2.Z) };
Point3D i1Clamped = ClampPointToLine(i1, l1);
Point3D i2Clamped = ClampPointToLine(i2, l2);
return new Line { Start = i1Clamped, End = i2Clamped };
}
Implementation:
Line shortestDistanceLine = distBetweenLines(l1, l2);
Results:
So far this has been accurate in my testing. Returns null if passed two identical lines. I appreciate any feedback!
The shortest distance between two skew lines (lines which don't intersect) is the distance of the line which is perpendicular to both of them.
If we have a line l1 with known points p1 and p2, and a line l2 with known points p3 and p4:
The direction vector of l1 is p2-p1, or d1.
The direction vector of l2 is p4-p3, or d2.
We therefore know that the vector we are looking for, v, is perpendicular to both of these direction vectors:
d1.v = 0 & d2.v = 0
Or, if you prefer:
d1x*vx + d1y*vy + d1z*vz = 0
And the same for d2.
Let's take the point on the lines l1, l2 where v is actually perpendicular to the direction. We'll call these two points i1 and i2 respectively.
Since i1 lies on l1, we can say that i1 = p1 + m*d1, where m is some number.
Similarly, i2 = p3 + n*d2, where n is another number.
Since v is the vector between i1 and i2 (by definition) we get that v = i2 - i1.
This gives the substitutions for the x,y,z vectors of v:
vx = i2x - i1x = (p3x + n*d2x) - (p1x + m*d1x)
and so on.
Which you can now substitute back into your dot product equation:
d1x * ( (p3x + n*d2x) - (p1x + m*d1x) ) + ... = 0
This has reduced our number of equations to 2 (the two dot product equations) with two unknowns (m and n), so you can now solve them!
Once you have m and n, you can find the coordinates by going back to the original calculation of i1 and i2.
If you only wanted the shortest distance for points on the segment between p1-p2 and p3-p4, you can clamp i1 and i2 between these ranges of coordinates, since the shortest distance will always be as close to the perpendicular as possible.
The code above return a wrong value so I take the idea from Python code (Shortest distance between two line segments) and I converted for C#. It necessary to use Numpy lib for C#:
public static Tuple<NDarray, NDarray, NDarray> closestDistanceBetweenLines(
NDarray a0,
NDarray a1,
NDarray b0,
NDarray b1,
bool clampAll = false,
bool clampA0 = false,
bool clampA1 = false,
bool clampB0 = false,
bool clampB1 = false)
{
// If clampAll=True, set all clamps to True
if (clampAll)
{
clampA0 = true;
clampA1 = true;
clampB0 = true;
clampB1 = true;
}
// Calculate denomitator
NDarray A = a1 - a0;
NDarray B = b1 - b0;
NDarray magA = np.linalg.norm(A);
NDarray magB = np.linalg.norm(B);
NDarray _A = A / magA;
NDarray _B = B / magB;
NDarray cross = np.cross(_A, _B);
double denom = Math.Pow((float)np.linalg.norm(cross), 2);
// If lines are parallel (denom=0) test if lines overlap.
// If they don't overlap then there is a closest point solution.
// If they do overlap, there are infinite closest positions, but there is a closest distance
if (denom == 0)
{
NDarray d0 = np.dot(_A, b0 - a0);
// Overlap only possible with clamping
if (clampA0 || clampA1 || clampB0 || clampB1)
{
NDarray d1 = np.dot(_A, b1 - a0);
// Is segment B before A?
if ((float)d0 <= 0F || (float)d0 >= (float)d1)
{
if (clampA0 && clampB1)
{
if ( (float)np.absolute(d0) < (float)np.absolute(d1) )
{
return Tuple.Create(a0, b0, np.linalg.norm(a0 - b0));
}
return Tuple.Create(a0, b1, np.linalg.norm(a0 - b1));
}
}
else if ((float)d0 >= (float)magA || (float)d0 <= (float)d1)
{
// Is segment B after A?
if (clampA1 && clampB0)
{
if ((float)np.absolute(d0) < (float)np.absolute(d1))
{
return Tuple.Create(a1, b0, np.linalg.norm(a1 - b0));
}
return Tuple.Create(a1, b1, np.linalg.norm(a1 - b1));
}
}
}
// Segments overlap, return distance between parallel segments;
NDarray vuoto1 = np.array(new[] { 0 });
return Tuple.Create(vuoto1, vuoto1, np.linalg.norm(d0 * _A + a0 - b0));
}
// Lines criss-cross: Calculate the projected closest points
NDarray t = b0 - a0;
var ArrFordetA = np.array(new float[,] { { (float)t[0], (float)t[1], (float)t[2] },
{ (float)_B[0], (float)_B[1], (float)_B[2] },
{ (float)cross[0], (float)cross[1], (float)cross[2] } });
NDarray detA = np.linalg.det(ArrFordetA);
var ArrFordetB = np.array(new float[,] { { (float)t[0], (float)t[1], (float)t[2] },
{ (float)_A[0], (float)_A[1], (float)_A[2] },
{ (float)cross[0], (float)cross[1], (float)cross[2] } });
NDarray detB = np.linalg.det(ArrFordetB);
var t0 = detA / denom;
var t1 = detB / denom;
var pA = a0 + _A * t0; // Projected closest point on segment A
var pB = b0 + _B * t1; // Projected closest point on segment B
// Clamp projections
if (clampA0 || clampA1 || clampB0 || clampB1)
{
if (clampA0 && (float)t0 < 0)
{
pA = a0;
}
else if (clampA1 && (float)t0 > (float)magA)
{
pA = a1;
}
if (clampB0 && (float)t1 < 0)
{
pB = b0;
}
else if (clampB1 && (float)t1 > (float)magB)
{
pB = b1;
}
// Clamp projection A
if (clampA0 && (float)t0 < 0 || clampA1 && (float)t0 > (float)magA)
{
NDarray dot = np.dot(_B, pA - b0);
if ( clampB0 && (float)dot < 0)
{
dot = (NDarray)0;
}
else if (clampB1 && (float)dot > (float)magB)
{
dot = magB;
}
pB = b0 + _B * dot;
}
// Clamp projection B
if ( clampB0 && (float)t1 < 0 || clampB1 && (float)t1 > (float)magB)
{
NDarray dot = np.dot(_A, pB - a0);
if (clampA0 && (float)dot < 0)
{
dot = (NDarray)0;
}
else if (clampA1 && (float)dot > (float)magA)
{
dot = magA;
}
pA = a0 + _A * dot;
}
}
return Tuple.Create(pA, pB, np.linalg.norm(pA - pB));
}
to call this function use:
private void button1_Click(object sender, EventArgs e)
{
NDarray a1 = np.array(new[] { 13.43, 21.77, 46.81 });
NDarray a0 = np.array(new[] { 27.83, 31.74, -26.60 });
NDarray b0 = np.array(new[] { 77.54, 7.53, 6.22 });
NDarray b1 = np.array(new[] { 26.99, 12.39, 11.18 });
Debug.WriteLine("----------------- True: -----------------");
Debug.WriteLine(closestDistanceBetweenLines(a0, a1, b0, b1, true));
Debug.WriteLine("---------------------------------------------");
Debug.WriteLine("");
Debug.WriteLine("----------------- False: -----------------");
Debug.WriteLine(closestDistanceBetweenLines(a0, a1, b0, b1, false));
Debug.WriteLine("---------------------------------------------");
Tuple<NDarray, NDarray, NDarray> RisultatoTrue = closestDistanceBetweenLines(a0, a1, b0, b1, true);
var Pa = np.array(RisultatoTrue.Item1);
Debug.WriteLine("Start point X:" + Pa[0].ToString());
Debug.WriteLine("Start point Y:" + Pa[1].ToString());
Debug.WriteLine("Start point Z:" + Pa[2].ToString());
var Pb = np.array(RisultatoTrue.Item2);
Debug.WriteLine("End point X:" + Pb[0].ToString());
Debug.WriteLine("End point Y:" + Pb[1].ToString());
Debug.WriteLine("End point Z:" + Pb[2].ToString());
var dist = np.array(RisultatoTrue.Item3);
Debug.WriteLine("Distance:" + dist.ToString());
}
I am trying to calculate a 3D linear regression LINE using the Singular Value Decomposition method (SVD).
This works fine. Now, I'd like to generalise the method for weighted regression.
how to calculate the optimale beta with SVD? Below is my C# code which uses the CSML package. The LinearRegression() function works just fine. WeightedLinearRegression() does not and I assume this is because I cannot just simply define
weighted_mult_mat = M_tr * W * M;
CODE:
public static Vector3D WeightedLinearRegression(List<Point3D> pts, List<double> weights) {
// normalisation
double sum = weights.Sum();
if (sum != weights.Count) {
for (int i = 0; i < weights.Count; i++ ) {
weights[i] = weights[i] / sum;
}
}
Point3D avg = pts.average();
// populate Matrix M
CSML.Matrix M = new CSML.Matrix(pts.Count, 3); // init
// populate matrix M
for (int i = 1; i < pts.Count + 1; i++) {
M[i, 1] = new Complex(pts[i - 1].X - avg.X);
M[i, 2] = new Complex(pts[i - 1].Y - avg.Y);
M[i, 3] = new Complex(pts[i - 1].Z - avg.Z);
}
CSML.Matrix M_tr = M.Transpose();
// populate weights matrix
CSML.Matrix W = new CSML.Matrix(pts.Count, pts.Count); // init
for (int i = 1; i < pts.Count + 1; i++) {
W[i, i] = new Complex(weights[i-1]);
}
// compute matrix
CSML.Matrix weighted_mult_mat = new CSML.Matrix();
weighted_mult_mat = M_tr * W;
weighted_mult_mat = weighted_mult_mat * M;
var weighted_dense_mat = new DenseMatrix(3, 3);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
weighted_dense_mat[i, j] = weighted_mult_mat[i + 1, j + 1].Re;
}
}
var weighted_svd = weighted_dense_mat.Svd(true);
var weighted_vt = weighted_svd.VT;
Vector3D weighted_dirVect = new Vector3D(weighted_vt[0, 0], weighted_vt[0, 1], weighted_vt[0, 2]);
weighted_dirVect.Normalize();
return weighted_dirVect;
}
public static Vector3D LinearRegression(List<Point3D> pts) {
Point3D avg = pts.average();
// populate Matrix M
CSML.Matrix M = new CSML.Matrix(pts.Count, 3); // init
// populate matrix M
for (int i = 1; i < pts.Count + 1; i++) {
M[i, 1] = new Complex(pts[i - 1].X - avg.X);
M[i, 2] = new Complex(pts[i - 1].Y - avg.Y);
M[i, 3] = new Complex(pts[i - 1].Z - avg.Z);
}
CSML.Matrix M_tr = M.Transpose();
CSML.Matrix mult_mat = new CSML.Matrix();
mult_mat = M_tr * M;
var dense_mat = new DenseMatrix(3, 3);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
dense_mat[i, j] = mult_mat[i + 1, j + 1].Re ;
}
}
var svd = dense_mat.Svd(true);
var vt = svd.VT;
Vector3D dirVect = new Vector3D(vt[0, 0], vt[0, 1], vt[0, 2]);
dirVect.Normalize();
return dirVect;
}
Having two arrays of double values, I want to compute correlation coefficient (single double value, just like the CORREL function in MS Excel). Is there some simple one-line solution in C#?
I already discovered math lib called Meta Numerics. According to this SO question, it should do the job. Here is docs for Meta Numerics correlation method, which I don't get.
Could pls somebody provide me with simple code snippet or example how to use the library?
Note: At the end, I was forced to use one of custom implementations.
But if someone reading this question knows good, well documented C#
math library/framework to do this, please don't hesitate and post a link in
answer.
You can have the values in separate lists at the same index and use a simple Zip.
var fitResult = new FitResult();
var values1 = new List<int>();
var values2 = new List<int>();
var correls = values1.Zip(values2, (v1, v2) =>
fitResult.CorrelationCoefficient(v1, v2));
A second way is to write your own custom implementation (mine isn't optimized for speed):
public double ComputeCoeff(double[] values1, double[] values2)
{
if(values1.Length != values2.Length)
throw new ArgumentException("values must be the same length");
var avg1 = values1.Average();
var avg2 = values2.Average();
var sum1 = values1.Zip(values2, (x1, y1) => (x1 - avg1) * (y1 - avg2)).Sum();
var sumSqr1 = values1.Sum(x => Math.Pow((x - avg1), 2.0));
var sumSqr2 = values2.Sum(y => Math.Pow((y - avg2), 2.0));
var result = sum1 / Math.Sqrt(sumSqr1 * sumSqr2);
return result;
}
Usage:
var values1 = new List<double> { 3, 2, 4, 5 ,6 };
var values2 = new List<double> { 9, 7, 12 ,15, 17 };
var result = ComputeCoeff(values1.ToArray(), values2.ToArray());
// 0.997054485501581
Debug.Assert(result.ToString("F6") == "0.997054");
Another way is to use the Excel function directly:
var values1 = new List<double> { 3, 2, 4, 5 ,6 };
var values2 = new List<double> { 9, 7, 12 ,15, 17 };
// Make sure to add a reference to Microsoft.Office.Interop.Excel.dll
// and use the namespace
var application = new Application();
var worksheetFunction = application.WorksheetFunction;
var result = worksheetFunction.Correl(values1.ToArray(), values2.ToArray());
Console.Write(result); // 0.997054485501581
Math.NET Numerics is a well-documented math library that contains a Correlation class. It calculates Pearson and Spearman ranked correlations: http://numerics.mathdotnet.com/api/MathNet.Numerics.Statistics/Correlation.htm
The library is available under the very liberal MIT/X11 license. Using it to calculate a correlation coefficient is as easy as follows:
using MathNet.Numerics.Statistics;
...
correlation = Correlation.Pearson(arrayOfValues1, arrayOfValues2);
Good luck!
In order to calculate Pearson product-moment correlation coefficient
http://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient
You can use this simple code:
public static Double Correlation(Double[] Xs, Double[] Ys) {
Double sumX = 0;
Double sumX2 = 0;
Double sumY = 0;
Double sumY2 = 0;
Double sumXY = 0;
int n = Xs.Length < Ys.Length ? Xs.Length : Ys.Length;
for (int i = 0; i < n; ++i) {
Double x = Xs[i];
Double y = Ys[i];
sumX += x;
sumX2 += x * x;
sumY += y;
sumY2 += y * y;
sumXY += x * y;
}
Double stdX = Math.Sqrt(sumX2 / n - sumX * sumX / n / n);
Double stdY = Math.Sqrt(sumY2 / n - sumY * sumY / n / n);
Double covariance = (sumXY / n - sumX * sumY / n / n);
return covariance / stdX / stdY;
}
If you don't want to use a third party library, you can use the method from this post (posting code here for backup).
public double Correlation(double[] array1, double[] array2)
{
double[] array_xy = new double[array1.Length];
double[] array_xp2 = new double[array1.Length];
double[] array_yp2 = new double[array1.Length];
for (int i = 0; i < array1.Length; i++)
array_xy[i] = array1[i] * array2[i];
for (int i = 0; i < array1.Length; i++)
array_xp2[i] = Math.Pow(array1[i], 2.0);
for (int i = 0; i < array1.Length; i++)
array_yp2[i] = Math.Pow(array2[i], 2.0);
double sum_x = 0;
double sum_y = 0;
foreach (double n in array1)
sum_x += n;
foreach (double n in array2)
sum_y += n;
double sum_xy = 0;
foreach (double n in array_xy)
sum_xy += n;
double sum_xpow2 = 0;
foreach (double n in array_xp2)
sum_xpow2 += n;
double sum_ypow2 = 0;
foreach (double n in array_yp2)
sum_ypow2 += n;
double Ex2 = Math.Pow(sum_x, 2.00);
double Ey2 = Math.Pow(sum_y, 2.00);
return (array1.Length * sum_xy - sum_x * sum_y) /
Math.Sqrt((array1.Length * sum_xpow2 - Ex2) * (array1.Length * sum_ypow2 - Ey2));
}
In my tests, both #Dmitry Bychenko's and #keyboardP's code postings above resulted in generally the same correlations as Microsoft Excel over a handful of manual tests I did, and did not need any external libraries.
e.g. Running this once (data for this run listed at the bottom):
#Dmitry Bychenko: -0.00418479432051121
#keyboardP:______-0.00418479432051131
MS Excel:_________-0.004184794
Here is a test harness:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestCorrel {
class Program {
static void Main(string[] args) {
Random rand = new Random(DateTime.Now.Millisecond);
List<double> x = new List<double>();
List<double> y = new List<double>();
for (int i = 0; i < 100; i++) {
x.Add(rand.Next(1000) * rand.NextDouble());
y.Add(rand.Next(1000) * rand.NextDouble());
Console.WriteLine(x[i] + "," + y[i]);
}
Console.WriteLine("Correl1: " + Correl1(x, y));
Console.WriteLine("Correl2: " + Correl2(x, y));
}
public static double Correl1(List<double> x, List<double> y) {
//https://stackoverflow.com/questions/17447817/correlation-of-two-arrays-in-c-sharp
if (x.Count != y.Count)
return (double.NaN); //throw new ArgumentException("values must be the same length");
double sumX = 0;
double sumX2 = 0;
double sumY = 0;
double sumY2 = 0;
double sumXY = 0;
int n = x.Count < y.Count ? x.Count : y.Count;
for (int i = 0; i < n; ++i) {
Double xval = x[i];
Double yval = y[i];
sumX += xval;
sumX2 += xval * xval;
sumY += yval;
sumY2 += yval * yval;
sumXY += xval * yval;
}
Double stdX = Math.Sqrt(sumX2 / n - sumX * sumX / n / n);
Double stdY = Math.Sqrt(sumY2 / n - sumY * sumY / n / n);
Double covariance = (sumXY / n - sumX * sumY / n / n);
return covariance / stdX / stdY;
}
public static double Correl2(List<double> x, List<double> y) {
double[] array_xy = new double[x.Count];
double[] array_xp2 = new double[x.Count];
double[] array_yp2 = new double[x.Count];
for (int i = 0; i < x.Count; i++)
array_xy[i] = x[i] * y[i];
for (int i = 0; i < x.Count; i++)
array_xp2[i] = Math.Pow(x[i], 2.0);
for (int i = 0; i < x.Count; i++)
array_yp2[i] = Math.Pow(y[i], 2.0);
double sum_x = 0;
double sum_y = 0;
foreach (double n in x)
sum_x += n;
foreach (double n in y)
sum_y += n;
double sum_xy = 0;
foreach (double n in array_xy)
sum_xy += n;
double sum_xpow2 = 0;
foreach (double n in array_xp2)
sum_xpow2 += n;
double sum_ypow2 = 0;
foreach (double n in array_yp2)
sum_ypow2 += n;
double Ex2 = Math.Pow(sum_x, 2.00);
double Ey2 = Math.Pow(sum_y, 2.00);
double Correl =
(x.Count * sum_xy - sum_x * sum_y) /
Math.Sqrt((x.Count * sum_xpow2 - Ex2) * (x.Count * sum_ypow2 - Ey2));
return (Correl);
}
}
}
Data for the example numbers above:
287.688269702572,225.610842817282
618.9313498167,177.955550192835
25.7778882802361,27.6549569366756
140.847984766051,714.618547504125
438.618761728806,533.48764902702
481.347431274758,214.381256273194
21.6406916848573,393.559209519792
135.30397563209,158.419851317732
334.314685154853,814.275162949821
764.614904770914,50.1435267264692
42.8179292282173,47.8631582287434
237.216836650491,370.488416981179
388.849658539449,134.961087643151
305.903013161804,441.926902444068
10.6625048679591,369.567569480076
36.9316453891488,24.8947204607049
2.10067253471383,491.941975629861
7.94887068492774,573.037801189831
341.738006353722,653.497146697015
98.8424873439793,475.215988045193
272.248712629196,36.1088809138671
122.336823399801,169.158256422336
9.32281673202422,631.076001565473
201.118425176068,803.724831627554
415.514343714115,64.248651454341
227.791637123,230.512133914284
25.3438658925443,396.854282886188
596.238994411304,72.543763144195
230.239735877253,933.983901697669
796.060099040186,689.952468971234
9.30882684202344,269.22063744125
16.5005430148451,8.96549091859045
536.324005148524,358.829873788557
519.694526420764,17.3212184707267
552.628357889423,12.5541588051962
210.516099897454,388.57537739937
141.341571405689,268.082028986924
503.880356335491,753.447006912645
515.494990213539,444.451280259737
973.8670776076,168.922799013985
85.7111146094795,36.3784999169309
37.2147129193017,108.040356312432
504.590177939548,50.3934166889607
482.821039277511,888.984586256083
5.52549206350255,156.717087003271
405.833169031345,394.099059180868
459.249365587835,11.68776424494
429.421127440604,314.216759666901
126.908422469584,331.907062556551
62.1416232716952,3.19765723645578
4.16058817699579,604.04046284223
484.262182311277,220.177370167886
58.6774453314382,339.09660232677
463.482149892246,199.181594849183
344.128297473829,268.531428258182
0.883430369609702,209.346384477963
77.9462970131758,255.221325168955
583.629439312792,235.557751925922
358.409186083083,376.046612200349
81.2148325150902,10.7696774717279
53.7315618049966,274.171515094196
111.284646992239,130.174321939319
317.280491961763,338.077288461885
177.454564264722,7.53587801919127
69.2239431670047,233.693477620228
823.419546454875,0.111916855029723
23.7174749401014,200.989081544331
44.9598299125022,102.633862571155
74.1602278468945,292.485449988155
130.11182449251,23.4682153367755
243.088760058903,335.807090202722
13.3974915991526,436.983231269281
73.3900805168739,252.352352472186
592.144630201228,92.3395205570103
57.7306153447044,47.1416798900541
522.649018382024,584.427794722108
15.3662010204821,60.1693953262499
16.8335716728277,851.401980430541
33.9869734449251,0.930781653584345
116.66608504982,146.126050951949
92.8896130355492,711.765618208687
317.91980889529,322.186540377413
44.8574470732629,209.275617858058
751.201537871362,37.935519233316
161.817758424588,2.83156183493862
531.64078452142,79.1750782491523
114.803219681048,283.106988439852
123.472725123853,154.125248027558
89.9276725453919,63.4626924192825
105.623296753328,111.234188702067
435.72981759707,23.7058234576629
259.324810619152,69.3535200857341
719.885234421531,381.086239833891
24.2674900099018,198.408173349876
57.7761600361095,146.52277489124
77.4594609157459,710.746080866431
636.671781979814,538.894185951396
56.6035279932448,58.2563265684323
485.16099039333,427.849954283261
91.9552873247095,576.92944263617
Public Function Correlation(ByRef array1() As Double, ByRef array2() As Double) As Double
'siehe https://stackoverflow.com/questions/17447817/correlation-of-two-arrays-in-c-sharp
'der hier errechnete "Pearson correlation coefficient" muss noch quadriert werden, um R-Squared zu erhalten, siehe
'https://en.wikipedia.org/wiki/Coefficient_of_determination
Dim array_xy(array1.Length - 1) As Double
Dim array_xp2(array1.Length - 1) As Double
Dim array_yp2(array1.Length - 1) As Double
Dim i As Integer
For i = 0 To array1.Length - 1
array_xy(i) = array1(i) * array2(i)
Next i
For i = 0 To array1.Length - 1
array_xp2(i) = Math.Pow(array1(i), 2.0)
Next i
For i = 0 To array1.Length - 1
array_yp2(i) = Math.Pow(array2(i), 2.0)
Next i
Dim sum_x As Double = 0
Dim sum_y As Double = 0
Dim EinDouble As Double
For Each EinDouble In array1
sum_x += EinDouble
Next
For Each EinDouble In array2
sum_y += EinDouble
Next
Dim sum_xy As Double = 0
For Each EinDouble In array_xy
sum_xy += EinDouble
Next
Dim sum_xpow2 As Double = 0
For Each EinDouble In array_xp2
sum_xpow2 += EinDouble
Next
Dim sum_ypow2 As Double = 0
For Each EinDouble In array_yp2
sum_ypow2 += EinDouble
Next
Dim Ex2 As Double = Math.Pow(sum_x, 2.0)
Dim Ey2 As Double = Math.Pow(sum_y, 2.0)
Dim ReturnWert As Double
ReturnWert = (array1.Length * sum_xy - sum_x * sum_y) / Math.Sqrt((array1.Length * sum_xpow2 - Ex2) * (array1.Length * sum_ypow2 - Ey2))
Correlation = ReturnWert
End Function