namespace CloudWaterNetwork { public class Math_Expect { public List _datas = null; public Math_Expect(List datas) { _datas = datas.Select(p => Math.Round(p, 1)).Distinct().ToList(); } public double Average() { return _datas.Average(); } /// /// 返回置信区间的上下限值 /// /// 用户指定的置信水平,假设是90% /// public double[] GetExpect(double x_percentile) { //List datas = _datas; //double mean = datas.Average(); // 求期望值 //double std_err = StdErr(datas); // 计算标准误差 //double x_percentile_z_score = ZScore(x_percentile / 100.0); // 根据置信水平计算分位点 //double x_percentile_CI_lower = mean - x_percentile_z_score * std_err; // 下限 //double x_percentile_CI_upper = mean + x_percentile_z_score * std_err; // 上限 //return new double[] {x_percentile_CI_lower,x_percentile_CI_upper }; //List datas = new List() { 2.0, 3.5, 1.2, 4.6, 5.2, 6.8, 7.5, 8.1, 9.0, 10.5 }; List datas = _datas; // 计算期望值 double mean = datas.Average(); // 计算95%置信区间范围 //double alpha = 0.05; // 置信水平 double alpha = x_percentile; double z = InvNormal(1 - alpha / 2); // 根据正态分布求出z值 double stdDev = Math.Sqrt(datas.Select(x => Math.Pow((x - mean), 2)).Sum() / (datas.Count - 1)); // 计算标准差 double marginOfError = z * stdDev / Math.Sqrt(datas.Count); // 计算误差范围 double lowerBound = mean - marginOfError; // 下限范围 double upperBound = mean + marginOfError; // 上限范围 return new double[] { lowerBound, upperBound }; //// 计算x%置信区间范围,如80%置信区间范围 //double xAlpha = 0.8; // 置信水平 //double xZ = InvNormal(1 - xAlpha / 2); // 根据正态分布求出z值 //double xMarginOfError = xZ * stdDev / Math.Sqrt(datas.Count); // 计算误差范围 //double xLowerBound = mean - xMarginOfError; // 下限范围 //double xUpperBound = mean + xMarginOfError; // 上限范围 } public double[] GetPercent(double x_percentile) { return new double[] { GetPercent_single(x_percentile), GetPercent_single(1 - x_percentile) }; } public double GetPercent_single(double x_percentile) { _datas.Sort(); int n = _datas.Count; double index = x_percentile * (n - 1); double frac = index % 1; if (frac == 0) { return _datas[(int)index]; } else { int lowIndex = (int)index; int highIndex = lowIndex + 1; double lowValue = _datas[lowIndex]; double highValue = _datas[highIndex]; return lowValue + (highValue - lowValue) * frac; } } public static double InvNormal(double p) { double a0 = 2.50662823884; double a1 = -18.61500062529; double a2 = 41.39119773534; double a3 = -25.44106049637; double b1 = -8.47351093090; double b2 = 23.08336743743; double b3 = -21.06224101826; double b4 = 3.13082909833; double c0 = -2.78718931138; double c1 = -2.29796479134; double c2 = 4.85014127135; double c3 = 2.32121276858; double d1 = 3.54388924762; double d2 = 1.63706781897; double p_low = 0.02425; double p_high = 1.0 - p_low; double q, r; if ((p < 0) || (p > 1)) { throw new ArgumentOutOfRangeException("Probability p must be between 0 and 1."); } if (p < p_low) { q = Math.Sqrt(-2 * Math.Log(p)); return (((((c3 * q + c2) * q + c1) * q) + c0) / ((((d2 * q + d1) * q) + 1) * q + 0.0)); } else if (p <= p_high) { q = p - 0.5; r = q * q; return (((((a3 * r + a2) * r + a1) * r) + a0) * q) / ((((b4 * r + b3) * r + b2) * r + b1) * r + 1); } else { q = Math.Sqrt(-2 * Math.Log(1 - p)); return -((((((c3 * q + c2) * q) + c1) * q) + c0) / ((((d2 * q + d1) * q) + 1) * q + 0.0)); } } double StdErr(List datas) { double mean = datas.Average(); double sum_squares = datas.Sum(d => Math.Pow(d - mean, 2)); int n = datas.Count; return Math.Sqrt(sum_squares / (n - 1)) / Math.Sqrt(n); } double ZScore(double confidence_level) { double z_score = 0; if (confidence_level > 0 && confidence_level < 1) { double tail_area = (1 - confidence_level) / 2; z_score = Math.Abs(NormSInv(tail_area)); } return z_score; } double NormSInv(double p) { if (p < 0 || p > 1) { throw new ArgumentOutOfRangeException("Argument out of range: " + nameof(p)); } else if (p == 0) { return double.NegativeInfinity; } else if (p == 1) { return double.PositiveInfinity; } // Abramowitz and Stegun formula 26.2.23. // The absolute value of the error should be less than 4.5 e-4. double[] a = new double[] { -3.969683028665376e+01, 2.209460984245205e+02, -2.759285104469687e+02, 1.383577518672690e+02, -3.066479806614716e+01, 2.506628277459239e+00 }; double[] b = new double[] { -5.447609879822406e+01, 1.615858368580409e+02, -1.556989798598866e+02, 6.680131188771972e+01, -1.328068155288572e+01 }; double[] c = new double[] { -7.784894002430293e-03, -3.223964580411365e-01, -2.400758277161838e+00, -2.549732539343734e+00, 4.374664141464968e+00, 2.938163982698783e+00 }; double[] d = new double[] { 7.784695709041462e-03, 3.224671290700398e-01, 2.445134137142996e+00, 3.754408661907416e+00 }; // Define break-points. double p_low = 0.02425; double p_high = 1 - p_low; // Rational approximation for lower region: if (p < p_low) { double q = Math.Sqrt(-2 * Math.Log(p)); return (((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1); } // Rational approximation for upper region: else if (p > p_high) { double q = Math.Sqrt(-2 * Math.Log(1 - p)); return -(((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1); } // Rational approximation for central region: else { double q = p - 0.5; double r = q * q; return (((((a[0] * r + a[1]) * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * q / (((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1); } } } }