using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Misc { /// <summary> /// 扩展 Enumerable 计算 /// </summary> public static class Enumerable { /// <summary> /// 获取 σ /// </summary> /// <typeparam name="TSource"></typeparam> /// <param name="source"></param> /// <param name="selector"></param> /// <returns></returns> public static double Sigma<TSource>(this IEnumerable<TSource> source, Func<TSource, double> selector) { if (source.Count() == 0) return double.NaN; double avg = source.Average(selector); double sum_pow = source.Sum((s) => Math.Pow((selector(s) - avg), 2)); return Math.Sqrt(sum_pow / (source.Count() - 1)); } /// <summary> /// 获取 σ /// </summary> /// <param name="source"></param> /// <returns></returns> public static double Sigma(this IEnumerable<int> source) { return source.Sigma(d => (int)d); } /// <summary> /// 获取 σ /// </summary> /// <param name="source"></param> /// <returns></returns> public static double Sigma(this IEnumerable<double> source) { var list = source.Where((d) => { if (double.IsNaN(d)) return false; else return true; }); return list.Sigma(d => d); } /// <summary> /// 获取CPK /// </summary> /// <typeparam name="TSource"></typeparam> /// <param name="source"></param> /// <param name="selector"></param> /// <param name="usl"></param> /// <param name="lsl"></param> /// <returns></returns> public static double CPK<TSource>(this IEnumerable<TSource> source, Func<TSource, double> selector, double usl, double lsl) { if (source.Count() == 0) return -1; //CPK = Min(CPKu,CPKl) //USL(Upper specification limit): 规格上限。 //LSL(Low specification limit): 规格下限。 //ˉx = (x1 + x2 +...+ xn) / n : 平均值。 //T = USL - LSL : 规格公差。 //U = (USL + LSL) / 2:规格中心。 //CPKu = | USL - ˉx | / 3σ //CPKl = | ˉx - LSL | / 3σ double avg = source.Average(selector); double sigma3 = source.Sigma(selector) * 3; double CPKu = Math.Abs(usl - avg) / sigma3; double CPKl = Math.Abs(lsl - avg) / sigma3; double CPK = Math.Min(CPKu, CPKl); return CPK; } /// <summary> /// 获取CPK /// </summary> /// <param name="source"></param> /// <param name="usl"></param> /// <param name="lsl"></param> /// <returns></returns> public static double CPK(this IEnumerable<double> source, double usl, double lsl) { var list = source.Where((d) => { if (double.IsNaN(d)) return false; else return true; }); return list.CPK(d => d, usl, lsl); } /// <summary> /// 获取直方图,统计数据 /// </summary> /// <typeparam name="TSource"></typeparam> /// <param name="source"></param> /// <param name="selector"></param> /// <param name="step"></param> /// <returns></returns> public static List<XY> GetHistogram<TSource>(this IEnumerable<TSource> source, Func<TSource, double> selector, double step) { List<XY> list = new List<XY>(); foreach (var v in source) { double x = ((int)(selector(v) / step)) * step; XY xy = list.Find(_xy => _xy.X == x); if (xy != null) { xy.Y++; } else { xy = new XY(x, 1); list.Add(xy); } } //没有数据也能排序的,不会错 list.Sort(); return list; } /// <summary> /// 获取直方图,统计数据 /// </summary> /// <param name="source"></param> /// <param name="step"></param> /// <returns></returns> public static List<XY> GetHistogram(this IEnumerable<double> source, double step) { var list = source.Where((d) => { if (double.IsNaN(d)) return false; else return true; }); return list.GetHistogram(d => d, step); } /// <summary> /// 当有 NaN 数据,不统计它。 /// </summary> /// <param name="source"></param> /// <returns></returns> public static double AverageNoNull(this IEnumerable<double> source) { return source.AverageNoNull(d => d); } /// <summary> /// 当有 NaN 数据,不统计它。 /// </summary> /// <typeparam name="TSource"></typeparam> /// <param name="source"></param> /// <param name="selector"></param> /// <returns></returns> public static double AverageNoNull<TSource>(this IEnumerable<TSource> source, Func<TSource, double> selector) { if (source.Count() == 0) return double.NaN; var list = source.Select(selector); var list2 = list.Where((d) => { if (double.IsNaN(d)) return false; else return true; }); if (list2.Count() == 0) return double.NaN; return list2.Average(); } } /// <summary> /// X Y 组合 /// </summary> public class XY : IComparable, ICloneable, ICopiable { public double X { get; set; } public double Y { get; set; } public XY() { } public XY(double x, double y) { X = x; Y = y; } public int CompareTo(object obj) { XY xy = obj as XY; return X.CompareTo(xy.X); } public object Clone() { XY xy = new XY(); xy.Copy(this); return xy; } public override string ToString() { return $"{X}.{Y}"; } public void Copy(object src) { Misc.PropertiesManager.CopyTo(src, this); } } }