cloudflight
2024-07-27 49eb2a09634e439090d4a2b13ec7d6f911d3deaf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
using MathNet.Numerics;
using MathNet.Numerics.LinearAlgebra.Double;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms.DataVisualization.Charting;
 
namespace Hydro.CommonBase
{
    public class CurveFitHelper
    {
 
 
        public DenseVector coefficients;
        int degree;
        double xMax;
        double xMin;
        List<PointF> data;
        bool isFitted = false;
 
        public CurveFitHelper(List<PointF> data, int degree = 2)
        {
            this.degree = degree;
            this.data = data;
 
            double[] xlist = data.Select(p => (double)p.X).ToArray();
            if (data.Count>2)
            {
                coefficients = Fit.Polynomial(xlist, data.Select(p => (double)p.Y).ToArray(), 2);
                isFitted = true;
            }
            else if(data.Count==2)
            {
                //使用两个点的线性拟合
                var tuple = Fit.Line(xlist, data.Select(p => (double)p.Y).ToArray());
                coefficients= new DenseVector(new double[] { tuple.Item1, tuple.Item2 });
                isFitted = true;
            }
            else if (data.Count==1)
            {
                coefficients = new DenseVector(new double[] { data[0].Y });
                isFitted = true;
            }
            else
            {
                coefficients = new DenseVector(new double[] { 0});
                isFitted = true;
            }
            
            var list = xlist.ToList();
            xMax = list.Max();
            xMin = list.Min();
        }
 
        public double Evaluate(double x)
        {
            if (!isFitted) return double.NaN;
            double y = 0;
            for (int i = 0; i < coefficients.Count; i++)
            {
                y += (float)(coefficients[i] * Math.Pow(x, i));
            }
            return y;
        }
 
 
        public List<PointF> GetFitCurve(int count)
        {
            List<PointF> curve = new List<PointF>();
            
            for (double x = xMin; x <= xMax && curve.Count<count; x += (xMax - xMin) / count)
            {
                double y = Evaluate(x);
                curve.Add(new PointF((float)x, (float)y));
            }
            return curve;
 
        }
 
        public List<List<PointF>> GetConfidenceCurve(int count)
        {
            List<PointF> up_list = new List<PointF>();
            List<PointF> down_list = new List<PointF>();
            List<PointF> avg_list = new List<PointF>();
 
            double X =0;
            double Y=0;
            for (double x = xMin; x < xMax; x += (xMax - xMin) / count)
            {
                var list = data.FindAll(p => x - (xMax - xMin) / count / 2 <= p.X && p.X < x + (xMax - xMin) / count/2).Select(p => (double)p.Y).ToList();
                if (list.Count >= 3)
                {
                    var Bounds = GetConfidenceRange(list, 95);
                    var x_avg = x;
                    if (Bounds[0] == double.NaN || Bounds[1] == double.NaN) continue;
                    down_list.Add(new PointF((float)x_avg, (float)Bounds[0]));
                    up_list.Add(new PointF((float)x_avg, (float)Bounds[1]));
                    X = x;
                    //平均值
                    Y = (Bounds[0] + Bounds[1] )/ 2;
                    avg_list.Add(new PointF((float)x_avg, (float)Y));
                }
                else if (list.Count == 2)
                {
                    var x_avg = x;
                    down_list.Add(new PointF((float)x_avg, (float)list.Min()));
                    up_list.Add(new PointF((float)x_avg, (float)list.Max()));
                    X = x;
                    Y = (list.Min() + list.Max()) / 2;
                    avg_list.Add(new PointF((float)x_avg, (float)Y));
                }
                else if (list.Count == 1)
                                       {
                    var x_avg = x;
                    down_list.Add(new PointF((float)x_avg, (float)list[0]));
                    up_list.Add(new PointF((float)x_avg, (float)list[0]));
                    X = x; 
                    Y = list[0];
                    avg_list.Add(new PointF((float)x_avg, (float)Y));
                }
                else if(list.Count == 0)
                {
                    //使用前一个点的值,X和Y都是前一个点的值
                    down_list.Add(new PointF((float)X, (float)Y));
                    up_list.Add(new PointF((float)X, (float)Y));
                    avg_list.Add(new PointF((float)X, (float)Y));
                }
 
            }
 
            //CurveFitHelper h0 = new CurveFitHelper(down_list);
            //var curve0 = h0.GetFitCurve(count);
            //CurveFitHelper h1 = new CurveFitHelper(up_list);
            //var curve1 = h1.GetFitCurve(count);
            return new List<List<PointF>> { down_list, up_list, avg_list };
        }
        public static double[] GetConfidenceRange(List<double> data, double confidenceLevel = 90, bool mode = true)//true是中位数,置信区间是false
        {
            //如果model==true,这计算中位数,比例为confidenceLevel
            if (mode)
            {
 
                data.Sort();
 
                double lowerBound = 0;
                double upperBound = 0;
                //取百分位confidenceLevel/100和1-confidenceLevel/100.0的数
                int upperIndex = (int)Math.Round(data.Count * confidenceLevel / 100.0);
                int lowerIndex = (int)Math.Round(data.Count * (1 - confidenceLevel / 100.0));
                if (upperIndex == data.Count)
                {
                    upperIndex = data.Count - 1;
                }
                if (lowerIndex < 0)
                {
                    lowerIndex = 0;
                }
                return new double[] { data[lowerIndex], data[upperIndex] };
 
 
            }
 
            else
            {
                // 使用循环计算数据的最小值和最大值
                double minValue = double.MaxValue;
                double maxValue = double.MinValue;
                foreach (double value in data)
                {
                    if (value < minValue)
                    {
                        minValue = value;
                    }
                    if (value > maxValue)
                    {
                        maxValue = value;
                    }
                }
 
                // 使用循环计算样本均值
                double sum = 0;
                foreach (double value in data)
                {
                    sum += value;
                }
                double mean = sum / data.Count;
 
                // 使用循环计算标准差
                double sumOfSquares = 0;
                foreach (double value in data)
                {
                    sumOfSquares += Math.Pow(value - mean, 2);
                }
                double stdDev = Math.Sqrt(sumOfSquares / (data.Count - 1));
 
                double zValue = 0;
                double alpha = 1 - confidenceLevel / 100.0;
 
                double zValueOneTail = GetZValueOneTail(alpha / 2);
                double marginOfError = zValueOneTail * stdDev;
                double lowerBound = mean - marginOfError;
                double upperBound = mean + marginOfError;
 
                return new double[] { lowerBound, upperBound };
            }
 
 
 
        }
        static double[,] zTable = {
      {0.0000, 0.0039, 0.0078, 0.0117, 0.0156, 0.0195, 0.0234, 0.0274, 0.0314, 0.0353},
      {0.0392, 0.0432, 0.0471, 0.0510, 0.0550, 0.0589, 0.0628, 0.0668, 0.0708, 0.0749},
      {0.0789, 0.0830, 0.0871, 0.0912, 0.0953, 0.0994, 0.1035, 0.1076, 0.1117, 0.1158},
      {0.1190, 0.1231, 0.1272, 0.1314, 0.1357, 0.1398, 0.1441, 0.1483, 0.1525, 0.1568},
      {0.1611, 0.1654, 0.1697, 0.1740, 0.1783, 0.1826, 0.1869, 0.1912, 0.1955, 0.1999},
      {0.2042, 0.2085, 0.2129, 0.2172, 0.2216, 0.2260, 0.2304, 0.2348, 0.2392, 0.2436},
      {0.2480, 0.2524, 0.2568, 0.2612, 0.2658, 0.2703, 0.2747, 0.2793, 0.2838, 0.2883},
      {0.2929, 0.2974, 0.3020, 0.3066, 0.3112, 0.3159, 0.3205, 0.3251, 0.3299, 0.3346},
      {0.3393, 0.3441, 0.3487, 0.3535, 0.3583, 0.3632, 0.3679, 0.3727, 0.3776, 0.3823},
      {0.3872, 0.3920, 0.3968, 0.4017, 0.4066, 0.4115, 0.4164, 0.4214, 0.4264, 0.4313}
    };
        static double GetZValueOneTail(double alpha)
        {
            if (alpha == 0.5)
            {
                return 0;
            }
            else if (alpha > 0.5)
            {
                // Use symmetry property of the normal distribution
                return -GetZValueOneTail(1 - alpha);
            }
            double[] alphaValues = { 0.1, 0.05, 0.025, 0.01, 0.005, 0.001 };
            double[] zValues = { 1.28, 1.645, 1.96, 2.33, 2.575, 3.09 };
            int n = alphaValues.Length;
            int i = 0;
            while (i < n && alpha < alphaValues[i])
            {
                i++;
            }
 
            if (i == 0)
            {
                return 0;
            }
            else if (i == n)
            {
                return zValues[n - 1];
            }
 
            double x0 = alphaValues[i - 1];
            double x1 = alphaValues[i];
            double y0 = zValues[i - 1];
            double y1 = zValues[i];
 
            double zValue = ((y1 - y0) / (x1 - x0)) * (alpha - x0) + y0;
 
            return zValue;
        }
 
        //数据频率分布图的英文怎么说,
        /// <summary>
        /// 获取数据频率的分布图
        /// </summary>
        /// <param name="data"></param>
        /// <param name="numIntervals"></param>
        /// <param name="filterNum">以最小值作为过滤的系数</param>
        /// <returns></returns>
        public static List<DataPoint> GetFrequencyDistribution(List<Result> data, out List<DataPoint>[] datapoints, int numIntervals = 10,double filterNum=5 )
        {
 
            List<DataPoint> resultPoints = new List<DataPoint>();
            datapoints= new List<DataPoint>[numIntervals];
            for(int i=0;i<numIntervals;i++)
            {
                datapoints[i]= new List<DataPoint>();
            }
            // 设置置信水平
 
 
            // 设置区间数量
 
 
            ////在data中过滤和最大的5%的数据
            //data = data.Where(d => d <= data.Min() * filterNum).ToList();
 
 
 
            // 计算数据的最小值和最大值
            double minValue = data.Min(x=>x.ObjFunctionValue);
            double maxValue = data.Max(x => x.ObjFunctionValue);
 
            // 计算区间宽度
            double intervalWidth = (maxValue - minValue) / numIntervals;
 
            // 初始化频率分布数组
            int[] freqDist = new int[numIntervals];
 
            // 计算各个区间的频率
            foreach (var xd in data)
            {
                var x = xd.ObjFunctionValue;
                int index = (int)((x - minValue) / intervalWidth);
                if (index < 0) // 数据小于最小值
                {
                    freqDist[0]++;
                    datapoints[0].Add(new DataPoint() {XValue= x,Tag=xd });
                }
                else if (index >= numIntervals) // 数据大于最大值
                {
                    freqDist[numIntervals - 1]++;
                    datapoints[numIntervals - 1].Add(new DataPoint() { XValue = x, Tag = xd });
                }
                else // 数据在区间内
                {
                    freqDist[index]++;
                    datapoints[index].Add(new DataPoint() { XValue = x, Tag = xd });
                }
            }
            double[] freqDistPersent =new double[numIntervals];
            double sum = freqDist.Sum();
            //计算freqDist的频率百分比
            for (int i = 0; i < numIntervals; i++)
            {
                freqDistPersent[i] = (freqDist[i] / (double)sum );
            }
 
            //// 计算样本均值和标准差
            //double mean = data.Average();
            //double stdDev = Math.Sqrt(data.Select(x => (x - mean) * (x - mean)).Sum() / (data.Length - 1));
 
            //double zValue = 0;
            //double alpha = 1 - confidenceLevel / 100.0;
 
            //double zValueOneTail = GetZValueOneTail(alpha / 2);
 
            ////zValue = mean + zValueOneTail * stdDev / Math.Sqrt(data.Length);
            //// 计算置信区间的范围
            ////double z = GetZValue(confidenceLevel); //chart1.DataManipulator.Statistics.InverseNormalDistribution(1 - confidenceLevel / 200.0); // 根据置信水平查找标准正态分布的临界值
            //double marginOfError = zValueOneTail * stdDev;/// Math.Sqrt(data.Length);
            //double lowerBound = mean - marginOfError;
            //double upperBound = mean + marginOfError;
            for (int i = 0; i < numIntervals; i++)
            {
                double xValue = minValue + i * intervalWidth + intervalWidth / 2;
                double yValue = freqDistPersent[i];
                if (isValid(xValue) && isValid(yValue))
                    resultPoints.Add(new DataPoint(xValue, yValue));
            }
 
 
            return resultPoints;
 
 
 
        }
        
        static bool isValid(double value)
        {
            if (value == (int)value && value < 0) return false;
            return !Double.IsNaN(value) && !Double.IsInfinity(value);
        }
       
 
    }
 
    //public static class ConfidenceRangeHelper
    //{
 
 
    //}
}