/// <summary>
/// 提供正态分布的数据和图片
/// </summary>
public class StandardDistribution
{ /// <summary>
/// 样本数据
/// </summary>
public List<double> Xs { get; private set; } public StandardDistribution(List<double> Xs)
{
this.Xs = Xs; Average = Xs.Average();
Variance = GetVariance(Xs); if (Variance == 0) throw new Exception("方差为0");//此时不需要统计 因为每个样本数据都相同,可以在界面做相应提示 StandardVariance = Math.Sqrt(Variance);
} /// <summary>
/// 方差/标准方差的平方
/// </summary>
public double Variance { get; private set; } /// <summary>
/// 标准方差
/// </summary>
public double StandardVariance { get; private set; } /// <summary>
/// 算数平均值/数学期望
/// </summary>
public double Average { get; private set; } /// <summary>
/// 1/ (2π的平方根)的值
/// </summary>
public static double InverseSqrt2PI = 1 / Math.Sqrt(2 * Math.PI); /// <summary>
/// 获取指定X值的Y值 计算正太分布的公式
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
public double GetGaussianDistributionY(double x)
{
double PowOfE = -(Math.Pow(Math.Abs(x - Average), 2) / (2 * Variance)); double result = (StandardDistribution.InverseSqrt2PI / StandardVariance) * Math.Pow(Math.E, PowOfE); return result;
} /// <summary>
/// 获取正太分布的坐标<x,y>
/// </summary>
/// <returns></returns>
public List<Tuple<double, double>> GetGaussianDistributionYs()
{
List<Tuple<double, double>> XYs = new List<Tuple<double, double>>(); Tuple<double, double> xy = null; foreach (double x in Xs)
{
xy = new Tuple<double, double>(x, GetGaussianDistributionY(x));
XYs.Add(xy);
} return XYs;
} /// <summary>
/// 获取整型列表的方差
/// </summary>
/// <param name="src">要计算方差的数据列表</param>
/// <returns></returns>
public static double GetVariance(List<double> src)
{
double average = src.Average();
double SumOfSquares = 0;
src.ForEach(x => { SumOfSquares += Math.Pow(x - average, 2); });
return SumOfSquares / src.Count;//方差
} /// <summary>
/// 获取整型列表的方差
/// </summary>
/// <param name="src">要计算方差的数据列表</param>
/// <returns></returns>
public static float GetVariance(List<float> src)
{
float average = src.Average();
double SumOfSquares = 0;
src.ForEach(x => { SumOfSquares += Math.Pow(x - average, 2); });
return (float)SumOfSquares / src.Count;//方差
} /// <summary>
/// 画学生成绩的正态分布
/// </summary>
/// <param name="Width"></param>
/// <param name="Height"></param>
/// <param name="Scores">分数,Y值</param>
/// <param name="familyName"></param>
/// <returns></returns>
public Bitmap GetGaussianDistributionGraph(int Width, int Height,int TotalScore, string familyName = "宋体")
{
//横轴 分数;纵轴 正态分布的值 Bitmap bitmap = new Bitmap(Width, Height); Graphics gdi = Graphics.FromImage(bitmap); gdi.Clear(Color.White);
gdi.SmoothingMode = SmoothingMode.HighQuality;
gdi.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
gdi.PixelOffsetMode = PixelOffsetMode.HighQuality; List<Tuple<double, double>> Scores = GetGaussianDistributionYs().OrderBy(x => x.Item1).ToList();//排序 方便后面点与点之间的连线 保证 分数低的 在左边 float YHeight = 0.8F * Height;// 相对左下角 YHeight*0.9F 将表示 maxY
float XWidth = 0.9F * Width;//相对左下角 XWidth*0.9F 将表示 maxX float marginX = (Width - XWidth) / 2F;//x轴相对左右图片边缘的像素
float marginY = (Height - YHeight) / 2F;//y轴相对上下图片边缘的像素 PointF leftTop = new PointF(marginX, marginY); PointF leftBottom = new PointF(marginX, marginY + YHeight);//坐标轴的左下角 PointF rightBottom = new PointF(marginX + XWidth, marginY + YHeight);//坐标轴的右下角 gdi.DrawLine(Pens.Gray, leftBottom, rightBottom);//x轴
gdi.DrawLine(Pens.Gray, leftBottom, leftTop);//Y轴 //两个箭头 四条线 6个坐标 另需4个坐标 PointF YArrowLeft = new PointF(leftTop.X - 5, leftTop.Y + 5);
PointF YArrowRight = new PointF(leftTop.X + 5, leftTop.Y + 5);
PointF XArrowTop = new PointF(rightBottom.X - 5, rightBottom.Y - 5);
PointF XArrowBottom = new PointF(rightBottom.X - 5, rightBottom.Y + 5); gdi.DrawLine(Pens.Gray, leftTop, YArrowLeft);
gdi.DrawLine(Pens.Gray, leftTop, YArrowRight);
gdi.DrawLine(Pens.Gray, rightBottom, XArrowTop);
gdi.DrawLine(Pens.Gray, rightBottom, XArrowBottom); float unitX = 0.0F;//X轴转换比率
float unitY = 0.0F;//Y轴转换比率 List<PointF> pointFs = ConvertToPointF(Scores, XWidth * 0.9F, YHeight * 0.9F, leftTop, out unitX, out unitY);//将分数和概率 转换成 坐标 gdi.DrawCurve(Pens.Black, pointFs.ToArray(), 0.0F);//基数样条 //平均分 与 Y轴平行 PointF avg_top = new PointF(leftTop.X + (float)Average * unitX, leftTop.Y);
PointF avg_bottom = new PointF(leftTop.X + (float)Average * unitX, leftBottom.Y);
gdi.DrawLine(Pens.Black, avg_top, avg_bottom);
gdi.DrawString(string.Format("{0}", ((float)Average ).ToString("F2")), new Font("宋体", 11), Brushes.Black, avg_bottom.X, avg_bottom.Y-25); //将期望和方差写在横轴下方中间 PointF variance_pf = new PointF(leftBottom.X+(XWidth/2)-120, avg_bottom.Y + 25);
gdi.DrawString(string.Format("期望:{0};方差:{1}", ((float)Average).ToString("F2"), Variance.ToString("F2")), new Font("宋体", 11), Brushes.Black, variance_pf.X, variance_pf.Y); //将最小分数 和 最大分数 分成9段 标记在坐标轴横轴上 double minX = Scores.Min(x => x.Item1);
double maxX = Scores.Max(x => x.Item1); double perSegment = TotalScore/10;// (maxX - minX) / 9F;//每一段表示的分数 List<double> segs = new List<double>();//每一个分段分界线横轴的值 segs.Add(leftBottom.X + (float)minX * unitX); for (int i = 1; i < 11; i++)
{
segs.Add(leftBottom.X + (float)minX * unitX + perSegment * i * unitX);
}
for (int i = 0; i < 11; i++)
{
gdi.DrawPie(Pens.Black, (float)segs[i] - 1, leftBottom.Y - 1, 2, 2, 0, 360); gdi.DrawString(string.Format("{0}", ((minX + perSegment * (i))).ToString("F0")), new Font("宋体", 11), Brushes.Black, (float)segs[i] - 15, leftBottom.Y + 5);
} return bitmap;
} /// <summary>
/// 将数据转换为坐标
/// </summary>
/// <param name="Scores"></param>
/// <param name="X">最长利用横轴</param>
/// <param name="Y">最长利用纵轴 </param>
/// <param name="leftTop">左上角原点</param>
/// <returns></returns>
private static List<PointF> ConvertToPointF(List<Tuple<double, double>> Scores, float X, float Y, PointF leftTop, out float unitX, out float unitY)
{
double maxY = Scores.Max(x => x.Item2);
double maxX = Scores.Max(x => x.Item1); List<PointF> result = new List<PointF>(); float paddingY = Y * 0.01F;
float paddingX = X * 0.01F; unitY = (float)((Y - paddingY) / maxY);//单位纵轴表示出来需要的高度 计算出来的纵坐标需要 leftTop.Y+(Y-item2*unitY)+paddingY
unitX = (float)((X - paddingX) / maxX);//单位横轴表示出来需要的宽度 计算出来的横坐标需要 leftTop.X+item1*unitX PointF pf = new PointF();
foreach (Tuple<double, double> item in Scores)
{
pf = new PointF(leftTop.X + (float)item.Item1 * unitX, leftTop.Y + (Y - (float)item.Item2 * unitY) + paddingY);
result.Add(pf);
} return result;
} }

调用:

            StandardDistribution mathX = new StandardDistribution(scores);
Bitmap bitmap = mathX.GetGaussianDistributionGraph(800, 480, totalScore);
bitmap.Save("tt.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);

测试数据生成的正态分布图:

c# 画正态分布图的更多相关文章

  1. R 正态性检验:正态概率图

    检验模型是否满足正态性假设的方法: 1.正态概率图 这是我编写的画正态概率图的函数: #绘制正态概率图 plot_ZP = function(ti) #输入外部学生化残差 { n = length(t ...

  2. 正态QQ图的原理

    code{white-space: pre;} pre:not([class]) { background-color: white; }if (window.hljs && docu ...

  3. 【译文】利用STAN做贝叶斯回归分析:Part 2 非正态回归

    [译文]利用STAN做贝叶斯回归分析:Part 2 非正态回归 作者 Lionel Hertzogn 前一篇文章已经介绍了怎样在R中调用STAN对正态数据进行贝叶斯回归.本文则将利用三个样例来演示怎样 ...

  4. R-2 - 正态分布-中心极限-置信区间-正态假设检验

    本节内容 1:样本估计总体均值跟标准差,以及标准误 2:中心极限定理 3:如何查看数据是否是正态分布QQ图 4:置信区间的理解跟案例 5:假设检验 参考文章: 假设检验的学习和理解 一.样本估计总体均 ...

  5. 数据分布转换:非正态 -> 正态

    来源:丁香园论坛:SPSS上的把非正态分布数据转换为正态分布数据 一楼 可以应用变量变换的方法,将不服从正态分布的资料转化为非正态分布或近似正态分布.常用的变量变换方法有对数变换.平方根变换.倒数变换 ...

  6. 在opencv3中实现机器学习之:利用正态贝叶斯分类

    opencv3.0版本中,实现正态贝叶斯分类器(Normal Bayes Classifier)分类实例 #include "stdafx.h" #include "op ...

  7. 【R】正态检验与R语言

    正态检验与R语言 1.Kolmogorov–Smirnov test 统计学里, Kolmogorov–Smirnov 检验(亦称:K–S 检验)是用来检验数据是否符合某种分布的一种非参数检验,通过比 ...

  8. Java中的的画正三角方法

    在循环的语句的练习中,画正三角是一个很经典的例子,但是如果方法找的不对的话,即使最终画出来了,那么得到的代码也是非常的复杂,应用性不高. 下面有两种方法来画正三角,第一种是一种比较麻烦的办法,是通过归 ...

  9. 估计量|估计值|置信度|置信水平|非正态的小样本|t分布|大样本抽样分布|总体方差|

    5 估计量和估计值是什么? 估计量不是估计出来的量,是用于估计的量. 估计量:用于估计总体参数的随机变量,一般为样本统计量.如样本均值.样本比例.样本方差等.例如:样本均值就是总体均值的一个估计量. ...

随机推荐

  1. Vue学习之Webpack小结(十二)

    一.nrm: nrm是专门用来管理和快速切换私人配置的registry; nrm提供了一些最常用的npm包镜像地址,能够让我们快速的切换安装包时候的服务器地址: 二.镜像: 原来   包    刚一开 ...

  2. iOS之Category关联属性

    Objective-C /** 原文件 */ // Person.h #import <Foundation/Foundation.h> @interface Person : NSObj ...

  3. 转摘Python安装与环境变量的配置

    Python安装与环境变量的配置   python下载: Python安装包下载地址:http://www.python.org/ 根据实际的操作系统,安装合适的安装版本. Python安装: 本文以 ...

  4. 实例讲解ip地址、子网掩码、可用地址范围的计算

    关于ip以及相关的掩码.网络号等概念可以查看相关的博客.资料,这些东西很容易找着,一搜一大片.本文主要记录通过实例进行ip相关的计算. 我自己使用的在线网络计算器地址:https://www.sojs ...

  5. dfs 解决(隐式)图搜索问题

    132. 单词搜索 II 中文 English 给出一个由小写字母组成的矩阵和一个字典.找出所有同时在字典和矩阵中出现的单词.一个单词可以从矩阵中的任意位置开始,可以向左/右/上/下四个相邻方向移动. ...

  6. python--中文和UTF-8之间的转换

    因为想更改数据库里内容. 而这个内容,没有通过WEB开放编辑显示, 且放在里面的中文为UTF-8编码过的. 所以,想快速显示和更新里面的内容, 想到了这个方法. # coding=utf-8 org_ ...

  7. 项目Beta冲刺(团队5/7)

    项目Beta冲刺(团队) --5/7 作业要求: 项目Beta冲刺(团队) 1.团队信息 团队名 :男上加男 成员信息 : 队员学号 队员姓名 个人博客地址 备注 221600427 Alicesft ...

  8. python基础笔记-字符串

    字符串是 Python 中最常用的数据类型.我们可以使用引号(‘或”)来创建字符串. def main(): str1 = 'hello,world' print(len(str1))#计算字符串的长 ...

  9. python 使用 requests 做 http 请求

    1. get import requests # 最简单的get请求 r = requests.get(url) print(r.status_code) print(r.json()) # url ...

  10. cmds系统归并缓慢的处理过程 2017-2-16

      检查反应较慢的时间段,数据库整体运行情况,从awr报告总看看是否有异常   以上是两个节点的等待事件排行,其中发现cursor: pin S wait on X等待事件类型是并行,切较高,开始分析 ...