C#实现封装六西格玛数据统计工具类SixSigmaHelper
背景
在不同项目开的发过程中,可能会用到许多相同或类似的功能开发或业务处理,从抽象设计的角度考虑,通常会把这些功能或业务操作进行封装,方便在不同项目中调用,这也是重用思想的重要体现。本次分享的是在C#中实现六西格玛数据统计的功能封装。在大数据、人工智能、数据科学家炙手可热的当下,本类可以说是C#工程师在处理数据分析业务上的必备类。
相关概念请学习SPC相关课程和歇息MiniTab工具的使用
代码实现
SixSigmaHelper
常量定义
public const double d2 = 1.128;
public const double d3 = 1.693;
public const double d4 = 2.059;
public const double d5 = 2.326;
数组求和
/// <summary>
/// 数组求和
/// </summary>
/// <param name="originalData">原始数据数组</param>
/// <returns>返回数组的和</returns>
public static double GetSumValue(double[] originalData)
{
double sum = 0.0;
for (int i = 0; i < originalData.Length; i++)
{
sum = sum + originalData[i];
}
return DoubleFormat(sum);
}
数组求平均数
/// <summary>
/// 数组求平均数
/// </summary>
/// <param name="originalData">原始数据数组</param>
/// <returns>返回数组的平均值</returns>
public static double GetAverageValue(double[] originalData)
{
double sum = 0.0;
double ave = 0.0;
for (int i = 0; i < originalData.Length; i++)
{
sum = sum + originalData[i];
}
ave = sum / originalData.Length;
return DoubleFormat(ave);
}
按指定小数精度计算数组平均值
/// <summary>
/// 按指定小数精度计算数组平均值
/// </summary>
/// <param name="digits">精度,即保留的小数位数</param>
/// <param name="originalData"原始数据>原始数据数组</param>
/// <returns>返回指定小数精度的平均值</returns>
public static double GetAverageValue(int digits, double[] originalData)
{
double sum = 0.0;
double ave = 0.0;
for (int i = 0; i < originalData.Length; i++)
{
sum = sum + originalData[i];
}
ave = sum / originalData.Length;
return DoubleFormat(digits, ave);
}
获取整体平均值:先分组,计算组内平均值,然后计算整体平均值
/// <summary>
/// 获取整体平均值:先分组,计算组内平均值,然后计算整体平均值
/// </summary>
/// <param name="digits">精度,小数位数</param>
/// <param name="groupSize">组大小</param>
/// <param name="originalData"> 原始数据</param>
/// <returns>返回整体平均值</returns>
public static double GetTotalAveByGroup(int digits, int groupSize, double[] originalData)
{
double[] groupAve = GetGroupAve(digits, groupSize, originalData);
return SixSigmaHelper.GetAverageValue(digits, groupAve);
}
获取子组平均数,以数组形式返回
/// <summary>
/// 获取子组平均数,以数组形式返回
/// </summary>
/// <param name="digits">精度,小数位数</param>
/// <param name="groupSize">组大小</param>
/// <param name="originalData">原始数据</param>
/// <returns>返回子组平均值</returns>
public static double[] GetGroupAve(int digits, int groupSize, double[] originalData)
{
double groupNum = Math.Ceiling(Convert.ToDouble(originalData.Length / groupSize));
double[] groupAve = new double[Convert.ToInt32(groupNum)];
for (int i = 0; i < Convert.ToInt32(groupNum); i++)
{
int index = i * groupSize;
double[] temp = new double[groupSize];
for (int j = 0; j < groupSize; j++)
{
temp[j] = originalData[index + j];
}
groupAve[i] = SixSigmaHelper.GetAverageValue(digits, temp);
}
return groupAve;
}
求整体标准差
/// <summary>
/// 求整体标准差
/// </summary>
/// <param name="originalData">原始数据</param>
/// <returns>返回标准差</returns>
public static double GetTotalStdDev(double[] originalData)
{
double ave = 0.0;
double stdDev = 0.0;
if (originalData.Length == 1 && originalData[0] == 0.0)
{
return stdDev = 0.0;
}
ave = GetAverageValue(originalData);
for (int i = 0; i < originalData.Length; i++)
{
stdDev = (double)(stdDev + Math.Pow((originalData[i] - ave), 2));
}
stdDev = (double)Math.Sqrt(stdDev / (originalData.Length - 1));
return DoubleFormat(stdDev);
}
按指定小数精度获取标准差
/// <summary>
/// 按指定小数精度获取标准差
/// </summary>
/// <param name="digits">精度,即小数位数</param>
/// <param name="originalData">原始数据</param>
/// <returns>返回标准差</returns>
public static double GetStdDev(int digits, double[] originalData)
{
double ave = 0.0;
double stdDev = 0.0;
ave = GetAverageValue(originalData);
for (int i = 0; i < originalData.Length; i++)
{
stdDev = (double)(stdDev + Math.Pow((originalData[i] - ave), 2));
}
stdDev = (double)Math.Sqrt(stdDev / (originalData.Length - 1));
return DoubleFormat(digits, stdDev);
}
求移动极差均值
/// <summary>
/// 求移动极差均值
/// </summary>
/// <param name="size">子组容量</param>
/// <param name="originalData">原始数据</param>
/// <returns>返回移动极差均值</returns>
public static double GetMoveRangeMean(int size, double[] originalData)
{
double moveSum = 0.0;
double moveAve = 0.0;
double[] range = new double[originalData.Length - (size - 1)];
for (int i = (size - 1); i < originalData.Length; i++)
{
double[] temp = new double[size];
int count = size;
int idx = 0;
do
{
temp[idx] = originalData[i - (count - 1)];
idx++;
count--;
} while ((count > 0));
range[i - (size - 1)] = (double)Math.Abs(GetArrMax(temp) - GetArrMin(temp));
}
for (int i = 0; i < range.Length; i++)
{
moveSum = moveSum + range[i];
}
moveAve = moveSum / range.Length;
return DoubleFormat(moveAve);
}
求组内标准差
/// <summary>
/// 求组内标准差
/// </summary>
/// <param name="size">子组容量</param>
/// <param name="originalData">原始数据</param>
/// <returns>返回组内标准差</returns>
public static double GetInGroupStdDev(int size, double[] originalData)
{
double gourpStdDev = 0.0;
double moveAve = GetMoveRangeMean(size, originalData);
switch (size)
{
case 2:
gourpStdDev = (double)(moveAve / d2);
break;
case 3:
gourpStdDev = (double)(moveAve / d3);
break;
case 4:
gourpStdDev = (double)(moveAve / d4);
break;
case 5:
gourpStdDev = (double)(moveAve / d5);
break;
default:
gourpStdDev = (double)(moveAve / d2);
break;
}
return DoubleFormat(gourpStdDev);
}
获取整体正态分布曲线数组值
/// <summary>
/// 获取整体正态分布曲线数组值
/// </summary>
/// <param name="target">望目</param>
/// <param name="original">原始数据</param>
/// <returns>返回整体正态分布曲线数组值</returns>
public static Dictionary<string, object> GetNormalDistribution(double target, double[] original)
{
Dictionary<string, object> json = new Dictionary<string, object>();
double sigma = GetTotalStdDev(original);
double lcl = DoubleFormat(target - 3 * sigma);
double ucl = DoubleFormat(target + 3 * sigma);
int idx = 10;
double plus = 0.0;
plus = ((double)((int)(ucl - lcl + 1))) / 10;
double[] categories = new double[idx];
double[] values = new double[idx];
categories[0] = lcl;
for (int i = 1; i < idx; i++)
{
categories[i] = DoubleFormat(categories[i - 1] + plus);
}
for (int i = 0; i < idx; i++)
{
values[i] = 0.0;
}
for (int i = 1; i < categories.Length; i++)
{
values[i] = DoubleFormat(1
/ ((Math.Sqrt(2 * Math.PI) * GetTotalStdDev(original)))
* Math.Pow(
Math.E,
-Math.Pow((categories[i] - GetAverageValue(original)), 2)
/ (2 * Math
.Pow(GetTotalStdDev(original), 2))));
}
json.Add("categories", categories);
json.Add("values", values);
return json;
}
获取组内正态分布曲线数组值
/// <summary>
/// 获取组内正态分布曲线数组值
/// </summary>
/// <param name="target">望目</param>
/// <param name="original">原始数据</param>
/// <returns>返回组内正态分布曲线数组值</returns>
public static Dictionary<string, object> GetInGroupNormalDistribution(double target, double[] original)
{
Dictionary<string, object> json = new Dictionary<string, object>();
double sigma = GetTotalStdDev(original);
double lcl = DoubleFormat(target - 3 * sigma);
double ucl = DoubleFormat(target + 3 * sigma);
int idx = 10;
double plus = 0.0;
plus = ((double)((int)(ucl - lcl + 1))) / 10;
double[] categories = new double[idx];
double[] values = new double[idx];
double inGroupStdDev = GetInGroupStdDev(2, original);
double ave = GetAverageValue(original);
categories[0] = lcl;
for (int i = 1; i < idx; i++)
{
categories[i] = DoubleFormat(categories[i - 1] + plus);
}
for (int i = 0; i < idx; i++)
{
values[i] = 0.000000;
}
for (int i = 1; i < categories.Length; i++)
{
values[i] = DoubleFormat(1
/ ((Math.Sqrt(2 * Math.PI) * inGroupStdDev))
* Math.Pow(
Math.E,
-Math.Pow((categories[i] - ave), 2)
/ (2 * Math.Pow(inGroupStdDev, 2))));
}
json.Add("categories", categories);
json.Add("values", values);
return json;
}
获取数据分布情况
/// <summary>
/// 获取数据分布情况
/// </summary>
/// <param name="target">望目</param>
/// <param name="original">原始数据</param>
/// <returns>返回数据分布情况</returns>
public static Dictionary<string, object> GetDataDistribution(double target, double[] original)
{
Dictionary<string, object> json = new Dictionary<string, object>();
double sigma = GetTotalStdDev(original);
double lcl = DoubleFormat(target - 3 * sigma);
double ucl = DoubleFormat(target + 3 * sigma);
int idx = 10;
double plus = 0.0;
plus = ((double)((int)(ucl - lcl + 1))) / 10;
double[] categories = new double[idx];
double[] values = new double[idx];
String[] test = new String[idx];
categories[0] = lcl;
for (int i = 1; i < idx; i++)
{
categories[i] = DoubleFormat(categories[i - 1] + plus);
}
for (int i = 0; i < idx; i++)
{
values[i] = 0.0;
test[i] = "";
}
for (int i = 0; i < original.Length; i++)
{
for (int j = 0; j < categories.Length; j++)
{
if (categories[j] - 0.5 < original[i] && original[i] <= categories[j] + 0.5)
{
values[j] += 1;
test[j] += original[i] + ",";
}
}
}
for (int i = 0; i < idx; i++)
{
values[i] = values[i] / 100;
}
json.Add("categories", categories);
json.Add("values", values);
return json;
}
无偏移过程能力指数
/// <summary>
/// 无偏移过程能力指数
/// </summary>
/// <param name="upperT">公差上限</param>
/// <param name="lowerT">公差下限</param>
/// <param name="original">原始数据</param>
/// <returns>返回无偏移过程能力指数</returns>
public static double GetPP(double upperT, double lowerT, double[] original)
{
double pp = new double();
double sigma = GetTotalStdDev(original);
pp = (upperT - lowerT) / (6 * sigma);
return DoubleFormat(pp);
}
无偏移下单限过程能力指数
/// <summary>
/// 无偏移下单限过程能力指数
/// </summary>
/// <param name="lowerT">公差下限</param>
/// <param name="original">原始数据</param>
/// <returns>返回无偏移下单限过程能力指数</returns>
public static double GetPPL(double lowerT, double[] original)
{
double ppl = new double();
double sigma = GetTotalStdDev(original);
double ave = GetAverageValue(original);
ppl = (ave - lowerT) / (3 * sigma);
return DoubleFormat(ppl);
}
无偏移上单限过程能力指数
/// <summary>
/// 无偏移上单限过程能力指数
/// </summary>
/// <param name="upperT">公差上限</param>
/// <param name="original">原始数据</param>
/// <returns>返回无偏移上单限过程能力指数</returns>
public static double GetPPU(double upperT, double[] original)
{
double ppl = new double();
double sigma = GetTotalStdDev(original);
double ave = GetAverageValue(original);
ppl = (upperT - ave) / (3 * sigma);
return DoubleFormat(ppl);
}
有偏移过程能力指数
/// <summary>
/// 有偏移过程能力指数
/// </summary>
/// <param name="upperT">公差上限</param>
/// <param name="lowerT">公差下限</param>
/// <param name="original">原始数据</param>
/// <returns>返回有偏移过程能力指数</returns>
public static double getPPK(double upperT, double lowerT, double[] original)
{
double ppl = GetPPL(lowerT, original);
double ppu = GetPPU(upperT, original);
return DoubleFormat(ppl > ppu ? ppu : ppl);
}
无偏移短期过程能力指数
/// <summary>
/// 无偏移短期过程能力指数
/// </summary>
/// <param name="upperT">公差上限</param>
/// <param name="lowerT">公差下限</param>
/// <param name="original">原始数据</param>
/// <returns>返回无偏移短期过程能力指数</returns>
public static double GetInGroupCP(double upperT, double lowerT, double[] original)
{
double cp = new double();
double sigma = GetInGroupStdDev(2, original);
if (sigma == 0)
{
cp = 0;
}
else
{
cp = (upperT - lowerT) / (6 * sigma);
}
return DoubleFormat(cp);
}
无偏移下单限短期过程能力指数
/// <summary>
/// 无偏移下单限短期过程能力指数
/// </summary>
/// <param name="lowerT">公差下限</param>
/// <param name="original">原始数据</param>
/// <returns>返回无偏移下单限短期过程能力指数</returns>
public static double GetInGroupCPL(double lowerT, double[] original)
{
double cpl = new double();
double sigma = GetInGroupStdDev(2, original);
if (sigma == 0)
{
return 0;
}
else
{
double ave = GetAverageValue(original);
cpl = (ave - lowerT) / (3 * sigma);
return DoubleFormat(cpl);
}
}
无偏移上单限短期过程能力指数
/// <summary>
/// 无偏移上单限短期过程能力指数
/// </summary>
/// <param name="upperT">公差上限</param>
/// <param name="original">原始数据</param>
/// <returns>反回无偏移上单限短期过程能力指数</returns>
public static double GetInGroupCPU(double upperT, double[] original)
{
double cpu = new double();
double sigma = GetInGroupStdDev(2, original);
if (sigma == 0)
{
return 0;
}
else
{
double ave = GetAverageValue(original);
cpu = (upperT - ave) / (3 * sigma);
return DoubleFormat(cpu);
}
}
有偏移短期过程能力指数
/// <summary>
/// 有偏移短期过程能力指数
/// </summary>
/// <param name="upperT">公差上限</param>
/// <param name="lowerT">公差下限</param>
/// <param name="original">原始数据</param>
/// <returns>返回有偏移短期过程能力指数</returns>
public static double GetInGroupCPK(double upperT, double lowerT, double[] original)
{
double cpl = GetInGroupCPL(lowerT, original);
double cpu = GetInGroupCPU(upperT, original);
return DoubleFormat(cpl > cpu ? cpu : cpl);
}
自然上限
/// <summary>
/// 自然上限
/// </summary>
/// <param name="target">望目</param>
/// <param name="original">原始数据</param>
/// <returns>返回自然上限</returns>
public static double GetUCL(double target, double[] original)
{
double sigma = GetTotalStdDev(original);
return DoubleFormat(target + 3 * sigma);
}
自然下限
/// <summary>
/// 自然下限
/// </summary>
/// <param name="target">望目</param>
/// <param name="original">原始数据</param>
/// <returns>返回自然下限</returns>
public static double GetLCL(double target, double[] original)
{
double sigma = GetTotalStdDev(original);
return DoubleFormat(target - 3 * sigma);
}
最小值
/// <summary>
/// 最小值
/// </summary>
/// <param name="array">原始数据数组</param>
/// <returns>返回最小值</returns>
public static double GetArrMin(double[] array)
{
double min = array[0];
for (int i = 0; i < array.Length; i++)
{
if (min > array[i])
min = array[i];
}
return min;
}
最大值
/// <summary>
/// 最大值
/// </summary>
/// <param name="array">原始数据数组</param>
/// <returns>返回最大值</returns>
public static double GetArrMax(double[] array)
{
double max = array[0];
for (int i = 0; i < array.Length; i++)
{
if (max < array[i])
max = array[i];
}
return max;
}
数据格式化,默认保留5位小数
/// <summary>
/// 数据格式化,默认保留5位小数
/// </summary>
/// <param name="d">要格式化的数据</param>
/// <returns>返回格式化后的数据</returns>
public static double DoubleFormat(double d)
{
double result = 0.0;
if (double.TryParse(d.ToString(), out result))
{
decimal b = new decimal(d);
double formatD = Convert.ToDouble(Math.Round(b, 5));
//b.setScale(5, BigDecimal.ROUND_HALF_UP).doubleValue();
return formatD;
}
else
{
return 0.0;
}
}
按指定精度进行数据格式化
/// <summary>
/// 按指定精度进行数据格式化
/// </summary>
/// <param name="digits">精度,小数位数</param>
/// <param name="d">要格式化的数据</param>
/// <returns>返回格式化后的数据</returns>
public static double DoubleFormat(int digits, double d)
{
double result = 0.0;
if (double.TryParse(d.ToString(), out result))
{
decimal b = new decimal(d);
double formatD = Convert.ToDouble(Math.Round(b, digits));
//Double formatD = b.setScale(digits, BigDecimal.ROUND_HALF_UP).doubleValue();
return formatD;
}
else
{
return 0.0;
}
}