using Accord.Math; // 用于矩阵运算和高级数学操作
|
using Accord.Math.Optimization; // 非线性优化
|
using Dbscan.RBush;
|
using Dbscan;
|
using MathNet.Numerics; // 基础数学函数
|
using MathNet.Numerics.LinearAlgebra; // 线性代数运算
|
using MathNet.Numerics.LinearRegression; // 回归分析
|
using MathNet.Numerics.Optimization; // 优化算法
|
using MathNet.Numerics.Statistics; // 统计计算
|
using NumSharp;
|
using System.Collections.Concurrent; // 多维数组处理
|
|
|
namespace IStation.Test
|
{
|
/// <summary>
|
/// 泵曲线数据融合校正器(性能优化版)
|
/// </summary>
|
public class PumpCurveDataFusionCorrectorHelper2DeepSeek
|
{
|
#region 配置参数
|
// 异常值检测阈值(基于标准正态分布,2.5对应98.76%置信区间)
|
public const double ZScoreThreshold = 2;
|
// 过渡区域宽度(单位与输入数据相同,控制曲线衔接平滑度)
|
public const double TransitionWidth = 500;
|
// 多项式拟合阶数(三次平衡拟合能力与过拟合风险)
|
public const int PolynomialDegree = 3;
|
// 优化器最大迭代次数(Cobyla算法收敛阈值)
|
private const int OptimizationMaxIterations = 1000;
|
|
// 动态多项式拟合阶数(用于动态调整)
|
public int DynamicPolyDegree = 2;
|
|
// 测量数据过滤比例%(控制异常值过滤强度)
|
public double MeasuredXFilterRatio = 0.15;
|
|
#endregion
|
|
|
public (double[] mergedX, double[] mergedY, double[] optimizedX, double[] optimizedY) Corrent(
|
double[] splineX, double[] splineY,
|
double[] measuredXAll, double[] measuredYAll)
|
{
|
if (measuredXAll.Length != measuredYAll.Length)
|
return default;
|
|
|
// 优化1:使用Array.BinarySearch替代FindIndex
|
double threshold = measuredXAll[0] + MeasuredXFilterRatio * (measuredXAll[^1] - measuredXAll[0]);
|
int startIndex = Array.BinarySearch(measuredXAll, threshold);
|
startIndex = (startIndex < 0) ? ~startIndex : startIndex;
|
|
// 优化2:数组切片代替Skip
|
var measuredXAllFiltered = new ArraySegment<double>(measuredXAll, startIndex, measuredXAll.Length - startIndex).ToArray();
|
var measuredYAllFiltered = new ArraySegment<double>(measuredYAll, startIndex, measuredYAll.Length - startIndex).ToArray();
|
|
if (measuredXAllFiltered.Length < 5)
|
{
|
Console.WriteLine("异常值过滤后数据过小");
|
return default;
|
}
|
|
#region 稳健回归优化
|
// 优化3:预分配数组
|
var residuals = new double[measuredXAllFiltered.Length];
|
(double intercept, double slope) = SimpleRegression.Fit(measuredXAllFiltered, measuredYAllFiltered);
|
|
// 优化4:合并计算循环
|
double meanResidual = 0, stdResidual = 0;
|
for (int i = 0; i < measuredXAllFiltered.Length; i++)
|
{
|
double predicted = slope * measuredXAllFiltered[i] + intercept;
|
residuals[i] = measuredYAllFiltered[i] - predicted;
|
meanResidual += residuals[i];
|
}
|
meanResidual /= residuals.Length;
|
for (int i = 0; i < residuals.Length; i++)
|
{
|
stdResidual += Math.Pow(residuals[i] - meanResidual, 2);
|
}
|
stdResidual = Math.Sqrt(stdResidual / residuals.Length);
|
|
|
// 优化5:并行过滤
|
var validData = new List<(double X, double Y)>(measuredXAllFiltered.Length);
|
for (int i = 0; i < residuals.Length; i++)
|
{
|
if (Math.Abs((residuals[i] - meanResidual) / stdResidual) < ZScoreThreshold)
|
{
|
validData.Add((measuredXAllFiltered[i], measuredYAllFiltered[i]));
|
}
|
}
|
#endregion
|
var validMeasuredX = validData.Select(d => d.X).ToArray();
|
var validMeasuredY = validData.Select(d => d.Y).ToArray();
|
|
|
return ProcessData(splineX, splineY, validMeasuredX, validMeasuredY);
|
}
|
|
|
|
private (double[] mergedX, double[] mergedY, double[] optimizedX, double[] optimizedY) ProcessData(
|
double[] splineX, double[] splineY,
|
double[] measuredXValid, double[] measuredYValid)
|
{
|
if (measuredXValid.Length < 5)
|
return default;
|
// 优化6:缓存极值计算
|
double minX = measuredXValid[0], maxX = measuredXValid[^1];
|
|
|
var processor = new DBSCANProcessor();
|
var clusters = processor.PerformClustering(measuredXValid, measuredYValid);
|
|
|
var denseList = new List<DenseArea>();
|
denseList = denseList.OrderBy(x => x.XRange.Min).ToList();
|
|
|
if (denseList.Count() < 1 && measuredXValid.Length > 1000)
|
{
|
Console.WriteLine("areas<1 error------------");
|
}
|
DynamicPolyDegree = denseList.Count > 1 ? 2 : 1;
|
|
// 优化8:预分配集合容量
|
var measured_x = new List<double>(measuredXValid.Length);
|
var measured_y = new List<double>(measuredYValid.Length);
|
|
foreach (var item in denseList)
|
{
|
// 优化9:向量化范围判断
|
for (int i = 0; i < measuredXValid.Length; i++)
|
{
|
if (measuredXValid[i].Between(item.XRange.Min, item.XRange.Max) &&
|
measuredYValid[i].Between(item.YRange.Min, item.YRange.Max))
|
{
|
measured_x.Add(measuredXValid[i]);
|
measured_y.Add(measuredYValid[i]);
|
}
|
}
|
}
|
|
|
// 优化10:合并曲线生成优化
|
var (mergedX, mergedY) = MergeCurvesOptimized(splineX, splineY,
|
measured_x.ToArray(), measured_y.ToArray(), DynamicPolyDegree);
|
|
// 优化11:矩阵运算优化
|
double xMean = mergedX.Mean();
|
double xStd = mergedX.StandardDeviation();
|
var xNorm = mergedX.Select(x => (x - xMean) / xStd).ToArray();
|
|
var X = Matrix<double>.Build.DenseOfRowArrays(
|
xNorm.Select(x => new[] { Math.Pow(x, 3), x * x, x, 1.0 }).ToArray());
|
|
|
// 优化12:QR分解加速
|
var initialParams = MultipleRegression.QR(X, Vector<double>.Build.DenseOfArray(mergedY));
|
|
|
|
// 优化13:约束生成优化
|
var constraints = GenerateConstraints(xNorm, 50);
|
var optimizer = new Cobyla(BuildObjectiveFunction(xNorm, mergedY), constraints.ToArray())
|
{ MaxIterations = OptimizationMaxIterations };
|
|
if (!optimizer.Minimize(initialParams.ToArray()))
|
throw new OptimizationException("Optimization failed");
|
|
// 优化14:采样点生成优化
|
double[] optimizedX = GenerateOptimizedX(splineX, minX, maxX);
|
double[] optimizedY = optimizedX.Select(x => CubicModel(optimizer.Solution, (x - xMean) / xStd)).ToArray();
|
|
return (mergedX, mergedY, optimizedX, optimizedY);
|
}
|
|
|
public (double[,] ScaledData, List<PointData> Points) OptimizedScaleData(double[] x, double[] y)
|
{
|
int len = x.Length;
|
var scaled = new double[len, 2];
|
var points = new List<PointData>();
|
|
// 计算 x 和 y 的统计量
|
double xMean = 0, xStd = 0;
|
double yMean = 0, yStd = 0;
|
|
// 计算 x 的均值和标准差
|
for (int i = 0; i < len; i++)
|
{
|
xMean += x[i];
|
}
|
xMean /= len;
|
|
double xSumSq = 0;
|
for (int i = 0; i < len; i++)
|
{
|
xSumSq += (x[i] - xMean) * (x[i] - xMean);
|
}
|
xStd = Math.Sqrt(xSumSq / len);
|
|
// 计算 y 的均值和标准差
|
for (int i = 0; i < len; i++)
|
{
|
yMean += y[i];
|
}
|
yMean /= len;
|
|
double ySumSq = 0;
|
for (int i = 0; i < len; i++)
|
{
|
ySumSq += (y[i] - yMean) * (y[i] - yMean);
|
}
|
yStd = Math.Sqrt(ySumSq / len);
|
|
// 标准化数据并生成 PointData 对象
|
for (int i = 0; i < len; i++)
|
{
|
double xScaled = (x[i] - xMean) / xStd;
|
double yScaled = (y[i] - yMean) / yStd;
|
|
scaled[i, 0] = xScaled;
|
scaled[i, 1] = yScaled;
|
|
points.Add(new PointData(xScaled, yScaled));
|
}
|
|
return (scaled, points);
|
}
|
|
|
private static double[] GenerateOptimizedX(double[] splineX, double minX, double maxX)
|
{
|
double lower = Math.Min(splineX[0], minX);
|
double upper = Math.Max(splineX[^1], maxX);
|
return Enumerable.Range(0, 300)
|
.Select(i => lower + i * (upper - lower) / 299.0)
|
.ToArray();
|
}
|
|
private List<NonlinearConstraint> GenerateConstraints(double[] xNorm, int sampleCount)
|
{
|
var constraints = new List<NonlinearConstraint>(sampleCount);
|
double min = xNorm[0], max = xNorm[^1];
|
double step = (max - min) / (sampleCount - 1);
|
|
for (int i = 0; i < sampleCount; i++)
|
{
|
double x = min + i * step;
|
constraints.Add(new NonlinearConstraint(4,
|
p => -Derivative(p, x),
|
ConstraintType.GreaterThanOrEqualTo, 0));
|
}
|
return constraints;
|
}
|
|
private static (double[] X, double[] Y) MergeCurvesOptimized(
|
double[] originalX, double[] originalY,
|
double[] measuredX, double[] measuredY, int degree)
|
{
|
if (measuredX.Length < 3)
|
return (originalX, originalY);
|
|
// 优化15:多项式拟合加速
|
var polyCoeff = Fit.Polynomial(measuredX, measuredY, degree).Reverse().ToArray();
|
|
// 优化16:内存复用
|
var correctedY = new double[originalY.Length];
|
Array.Copy(originalY, correctedY, originalY.Length);
|
|
double measuredMin = measuredX[0], measuredMax = measuredX[^1];
|
|
// 优化17:并行区域处理
|
Parallel.Invoke(
|
() => ProcessCoreRegion(originalX, correctedY, polyCoeff, measuredMin, measuredMax),
|
() => ProcessTransitionRegions(originalX, correctedY, originalY, polyCoeff, measuredMin, measuredMax)
|
);
|
|
return (originalX, correctedY);
|
}
|
|
|
|
|
/// <summary>
|
/// 三次多项式模型(降幂排列)
|
/// </summary>
|
private static double CubicModel(double[] param, double x) =>
|
param[0] * x * x * x + param[1] * x * x + param[2] * x + param[3];
|
|
/// <summary>
|
/// 多项式导数(用于单调性约束)
|
/// </summary>
|
private static double Derivative(double[] param, double x) =>
|
3 * param[0] * x * x + 2 * param[1] * x + param[2];
|
|
|
/// <summary>
|
/// 构建目标函数(均方误差)
|
/// </summary>
|
private NonlinearObjectiveFunction BuildObjectiveFunction(double[] xNorm, double[] y) =>
|
new NonlinearObjectiveFunction(4, p =>
|
xNorm.Select((x, i) => Math.Pow(CubicModel(p, x) - y[i], 2)).Average()
|
);
|
|
// 多项式求值(支持降序系数)
|
private static double Polyval(double[] coefficients, double x)
|
{
|
double result = 0;
|
int degree = coefficients.Length - 1;
|
for (int i = 0; i < coefficients.Length; i++)
|
result += coefficients[i] * Math.Pow(x, degree - i);
|
return result;
|
}
|
|
// 线性插值
|
private static double LinearInterp(double x, double x0, double y0, double x1, double y1)
|
{
|
return x1 != x0
|
? y0 + (y1 - y0) * (x - x0) / (x1 - x0)
|
: y0;
|
}
|
|
private static void ProcessCoreRegion(double[] x, double[] y, double[] coeff, double min, double max)
|
{
|
for (int i = 0; i < x.Length; i++)
|
{
|
if (x[i].Between(min, max))
|
y[i] = Polyval(coeff, x[i]);
|
}
|
}
|
|
private static void ProcessTransitionRegions(double[] x, double[] y, double[] originalY,
|
double[] coeff, double measuredMin, double measuredMax)
|
{
|
// 左过渡处理
|
double xLeftStart = Math.Max(measuredMin - TransitionWidth, x[0]);
|
double yLeftStart = Polyval(Fit.Polynomial(x, originalY, 3).Reverse().ToArray(), xLeftStart);
|
double yLeftEnd = Polyval(coeff, measuredMin);
|
|
// 右过渡处理
|
double xRightEnd = Math.Min(measuredMax + TransitionWidth, x[^1]);
|
double yRightStart = Polyval(coeff, measuredMax);
|
double yRightEnd = Polyval(Fit.Polynomial(x, originalY, 3).Reverse().ToArray(), xRightEnd);
|
|
for (int i = 0; i < x.Length; i++)
|
{
|
double xi = x[i];
|
if (xi.Between(xLeftStart, measuredMin))
|
y[i] = LinearInterp(xi, xLeftStart, yLeftStart, measuredMin, yLeftEnd);
|
else if (xi.Between(measuredMax, xRightEnd))
|
y[i] = LinearInterp(xi, measuredMax, yRightStart, xRightEnd, yRightEnd);
|
}
|
}
|
|
}
|
|
|
public static class ArrayExtensions
|
{
|
public static double Mean(this double[] array) => ArrayStatistics.Mean(array);
|
public static double StandardDeviation(this double[] array) => Math.Sqrt(ArrayStatistics.Variance(array));
|
|
public static bool Between(this double value, double min, double max) =>
|
value >= min && value <= max;
|
}
|
}
|
|
|
public class PointData : IPointData
|
{
|
public PointData(double x, double y)
|
{
|
Point = new Point(x, y);
|
}
|
|
public Point Point { get; }
|
}
|
|
public class DenseArea
|
{
|
public (double Min, double Max) XRange { get; set; }
|
public (double Min, double Max) YRange { get; set; }
|
}
|
|
public class DBSCANProcessor
|
{
|
private double xMean;
|
private double xStd;
|
private double yMean;
|
private double yStd;
|
|
public List<(double MinX, double MaxX, double MinY, double MaxY)> PerformClustering(double[] x, double[] y)
|
{
|
// 数据标准化
|
var (scaledX, scaledY) = StandardizeData(x, y);
|
|
// 构建点集
|
var points = scaledX.Zip(scaledY, (a, b) =>
|
new PointData(a, b)).ToList();
|
|
// 自动参数计算
|
var minPts = CalculateMinPts(points.Count);
|
var eps = CalculateEpsilon(points, minPts);
|
|
int minSamples2= (int)(scaledX.GetLength(0) * 0.02);
|
minSamples2 = Math.Max(10, minSamples2);
|
var sc = EpsOptimizer.OptimizedScaleData(scaledX, scaledY);
|
var eps2 = EpsOptimizer.ComputeEps(sc, minSamples2);
|
|
// 执行DBSCAN聚类
|
var clusters = DbscanRBush.CalculateClusters(
|
points,
|
epsilon: eps,
|
minimumPointsPerCluster: minPts);
|
|
var list = new List<(double MinX, double MaxX, double MinY, double MaxY)>();
|
foreach (var item in clusters.Clusters)
|
{
|
list.Add(StandardizeData(item.Objects.ToList()));
|
}
|
|
return list;
|
}
|
|
private (double[] scaledX, double[] scaledY) StandardizeData(double[] x, double[] y)
|
{
|
// 使用MathNet进行标准化
|
xMean = x.Mean();
|
xStd = x.StandardDeviation();
|
yMean = y.Mean();
|
yStd = y.StandardDeviation();
|
|
return (
|
x.Select(v => (v - xMean) / xStd).ToArray(),
|
y.Select(v => (v - yMean) / yStd).ToArray()
|
);
|
}
|
|
private (double MinX, double MaxX, double MinY, double MaxY) StandardizeData(List<PointData> points)
|
{
|
int len = points.Count;
|
var originalX = new double[len];
|
var originalY = new double[len];
|
|
for (int i = 0; i < len; i++)
|
{
|
originalX[i] = points[i].Point.X * xStd + xMean;
|
originalY[i] = points[i].Point.Y * yStd + yMean;
|
}
|
|
var minX = originalX.Min(x => x);
|
var maxX = originalX.Max(x => x);
|
|
var minY = originalY.Min(x => x);
|
var maxY = originalY.Max(x => x);
|
|
|
return (minX,maxX,minY,maxY);
|
}
|
|
private int CalculateMinPts(int dataSize)
|
{
|
// 基于数据规模的动态计算(增加安全阈值)
|
return Math.Max(5, (int)(Math.Log(dataSize) * 1.5));
|
}
|
|
private double CalculateEpsilon(List<PointData> points, int minPts)
|
{
|
// K-距离图法计算最优epsilon
|
// 并行计算K-距离
|
var kDistances = new ConcurrentBag<double>();
|
Parallel.ForEach(points, point => {
|
var distances = points.AsParallel()
|
.Where(p => p != point)
|
.Select(p => EuclideanDistance(p.Point, point.Point))
|
.OrderBy(d => d)
|
.Take(minPts)
|
.ToList();
|
kDistances.Add(distances.Last());
|
});
|
|
// 寻找拐点
|
var sorted = kDistances.OrderBy(d => d).ToArray();
|
var maxCurvatureIndex = FindCurvaturePeak(sorted);
|
|
return sorted[maxCurvatureIndex] * 1.1;
|
|
//// 使用分位数法替代全排序
|
//var sorted = kDistances.Select(d => d).AsParallel().OrderBy(d => d).ToArray();
|
//double epsThreshold = sorted[(int)(sorted.Length * 0.9)]; // 取90%分位数
|
//return epsThreshold * 1.1
|
}
|
|
private int FindCurvaturePeak(double[] values)
|
{
|
// 曲率计算算法
|
var curvatures = new double[values.Length];
|
for (int i = 1; i < values.Length - 1; i++)
|
{
|
var dy1 = values[i] - values[i - 1];
|
var dy2 = values[i + 1] - values[i];
|
curvatures[i] = dy2 - dy1;
|
}
|
return Array.IndexOf(curvatures, curvatures.Max());
|
}
|
|
private double EuclideanDistance(Point a, Point b)
|
{
|
var dx = a.X - b.X;
|
var dy = a.Y - b.Y;
|
return Math.Sqrt(dx * dx + dy * dy);
|
}
|
|
|
|
}
|
|
public static class Extensions
|
{
|
public static IEnumerable<(double X, double Y)> GetOriginalPoints(
|
this Cluster<PointData> cluster,
|
double xMean,
|
double xStd,
|
double yMean,
|
double yStd)
|
{
|
return cluster.Objects.Select(p => (
|
X: p.Point.X * xStd + xMean,
|
Y: p.Point.Y * yStd + yMean
|
));
|
}
|
}
|
|
|
|
public static class EpsOptimizer
|
{
|
public static double[,] OptimizedScaleData(double[] x, double[] y)
|
{
|
int len = x.Length;
|
var scaled = new double[len, 2];
|
var points = new List<PointData>();
|
|
// 计算 x 和 y 的统计量
|
double xMean = 0, xStd = 0;
|
double yMean = 0, yStd = 0;
|
|
// 计算 x 的均值和标准差
|
for (int i = 0; i < len; i++)
|
{
|
xMean += x[i];
|
}
|
xMean /= len;
|
|
double xSumSq = 0;
|
for (int i = 0; i < len; i++)
|
{
|
xSumSq += (x[i] - xMean) * (x[i] - xMean);
|
}
|
xStd = Math.Sqrt(xSumSq / len);
|
|
// 计算 y 的均值和标准差
|
for (int i = 0; i < len; i++)
|
{
|
yMean += y[i];
|
}
|
yMean /= len;
|
|
double ySumSq = 0;
|
for (int i = 0; i < len; i++)
|
{
|
ySumSq += (y[i] - yMean) * (y[i] - yMean);
|
}
|
yStd = Math.Sqrt(ySumSq / len);
|
|
// 标准化数据并生成 PointData 对象
|
for (int i = 0; i < len; i++)
|
{
|
double xScaled = (x[i] - xMean) / xStd;
|
double yScaled = (y[i] - yMean) / yStd;
|
|
scaled[i, 0] = xScaled;
|
scaled[i, 1] = yScaled;
|
|
}
|
|
return scaled;
|
}
|
|
|
public static double ComputeEps(double[,] scaledData, int minSamples)
|
{
|
int k = Math.Max(1, minSamples);
|
var distances = new List<double>();
|
|
// 使用快速选择优化第k近邻计算
|
for (int i = 0; i < scaledData.GetLength(0); i++)
|
{
|
var tempDists = new List<double>();
|
for (int j = 0; j < scaledData.GetLength(0); j++)
|
{
|
if (i == j) continue;
|
double dx = scaledData[i, 0] - scaledData[j, 0];
|
double dy = scaledData[i, 1] - scaledData[j, 1];
|
tempDists.Add(dx * dx + dy * dy);
|
}
|
|
if (tempDists.Count >= k)
|
{
|
double kthDistSq = QuickSelect(tempDists, k);
|
distances.Add(Math.Sqrt(kthDistSq));
|
}
|
}
|
|
// 异常处理与边界检测
|
if (distances.Count == 0) return 0.5;
|
distances.Sort();
|
|
// 预计算前缀和以加速窗口平均值计算
|
double[] prefixSum = new double[distances.Count + 1];
|
for (int i = 0; i < distances.Count; i++)
|
prefixSum[i + 1] = prefixSum[i] + distances[i];
|
|
// 动态窗口曲率检测
|
double maxCurvature = double.MinValue;
|
double eps = distances[1]; // 使用 C# 8 的索引语法替代 Last()
|
int windowSize = Math.Max(1, distances.Count / 20);
|
windowSize = Math.Clamp(windowSize, 1, 5);
|
|
for (int i = windowSize; i < distances.Count - windowSize; i++)
|
{
|
int prevStart = i - windowSize;
|
double prevSum = prefixSum[prevStart + windowSize] - prefixSum[prevStart];
|
double prevAvg = prevSum / windowSize;
|
|
int nextStart = i;
|
double nextSum = prefixSum[nextStart + windowSize] - prefixSum[nextStart];
|
double nextAvg = nextSum / windowSize;
|
|
double curvature = nextAvg - prevAvg;
|
if (curvature > maxCurvature)
|
{
|
maxCurvature = curvature;
|
eps = distances[i];
|
}
|
}
|
|
return eps * 1.15;
|
}
|
|
// 快速选择算法实现
|
private static double QuickSelect(List<double> list, int k)
|
{
|
int left = 0;
|
int right = list.Count - 1;
|
var rand = new Random();
|
while (left <= right)
|
{
|
int pivotIndex = Partition(list, left, right, rand.Next(left, right + 1));
|
if (pivotIndex == k - 1) return list[pivotIndex];
|
if (pivotIndex < k - 1) left = pivotIndex + 1;
|
else right = pivotIndex - 1;
|
}
|
return double.NaN; // 理论不会执行到此
|
}
|
|
private static int Partition(List<double> list, int left, int right, int pivotIndex)
|
{
|
double pivotValue = list[pivotIndex];
|
Swap(list, pivotIndex, right);
|
int storeIndex = left;
|
for (int i = left; i < right; i++)
|
{
|
if (list[i] < pivotValue)
|
{
|
Swap(list, i, storeIndex);
|
storeIndex++;
|
}
|
}
|
Swap(list, storeIndex, right);
|
return storeIndex;
|
}
|
|
private static void Swap(List<double> list, int i, int j)
|
{
|
(list[i], list[j]) = (list[j], list[i]); // 使用元组交换
|
}
|
}
|
|
|
|
public class DataScaler
|
{
|
public (double[,] ScaledData, List<PointData> Points, double XMean, double XStd, double YMean, double YStd) OptimizedScaleData(double[] x, double[] y)
|
{
|
int len = x.Length;
|
var scaled = new double[len, 2];
|
var points = new List<PointData>();
|
|
// 计算 x 的均值和标准差
|
double xMean = 0, xStd = 0;
|
for (int i = 0; i < len; i++)
|
{
|
xMean += x[i];
|
}
|
xMean /= len;
|
|
double xSumSq = 0;
|
for (int i = 0; i < len; i++)
|
{
|
xSumSq += (x[i] - xMean) * (x[i] - xMean);
|
}
|
xStd = Math.Sqrt(xSumSq / len);
|
|
// 计算 y 的均值和标准差
|
double yMean = 0, yStd = 0;
|
for (int i = 0; i < len; i++)
|
{
|
yMean += y[i];
|
}
|
yMean /= len;
|
|
double ySumSq = 0;
|
for (int i = 0; i < len; i++)
|
{
|
ySumSq += (y[i] - yMean) * (y[i] - yMean);
|
}
|
yStd = Math.Sqrt(ySumSq / len);
|
|
// 标准化数据并生成 PointData 对象
|
for (int i = 0; i < len; i++)
|
{
|
double xScaled = (x[i] - xMean) / xStd;
|
double yScaled = (y[i] - yMean) / yStd;
|
|
scaled[i, 0] = xScaled;
|
scaled[i, 1] = yScaled;
|
|
points.Add(new PointData(xScaled, yScaled));
|
}
|
|
return (scaled, points, xMean, xStd, yMean, yStd);
|
}
|
|
|
public DenseArea RestoreOriginalDataDenseArea(List<PointData> list, double xMean, double xStd, double yMean, double yStd)
|
{
|
int len = list.Count;
|
var originalX = new double[len];
|
var originalY = new double[len];
|
|
for (int i = 0; i < len; i++)
|
{
|
originalX[i] = list[i].Point.X * xStd + xMean;
|
originalY[i] = list[i].Point.Y * yStd + yMean;
|
}
|
|
var minX = originalX.Min(x => x);
|
var maxX = originalX.Max(x => x);
|
|
var minY = originalY.Min(x => x);
|
var maxY = originalY.Max(x => x);
|
|
|
return new DenseArea()
|
{
|
XRange = (minX, maxX),
|
YRange = (minY, maxY)
|
};
|
|
}
|
|
|
}
|