基于WPF开发动态可交互混淆矩阵

最近在项目中,为了算法结果的可视化,需要用到混淆矩阵(Confusion Matrix),而网上资源大多是基于Python绘制的混淆矩阵,并且是输出图片格式,并不能响应用户点击,今天以一个简单的小例子,简述如何通过WPF绘制混淆矩阵,并可响应用户点击事件,仅供学习分享使用,如有不足之处,还请指正。


什么是混淆矩阵?

在机器学习中, 混淆矩阵是一个误差矩阵, 常用来可视化地评估监督学习算法的性能. 混淆矩阵大小为 (n_classes, n_classes) 的方阵, 其中 n_classes 表示类的数量. 这个矩阵的每一行表示真实类中的实例, 而每一列表示预测类中的实例 (Tensorflow 和 scikit-learn 采用的实现方式). 也可以是, 每一行表示预测类中的实例, 而每一列表示真实类中的实例 (Confusion matrix From Wikipedia 中的定义). 通过混淆矩阵, 可以很容易看出系统是否会弄混两个类, 这也是混淆矩阵名字的由来.

混淆矩阵是一种特殊类型的列联表(contingency table)或交叉制表(cross tabulation or crosstab). 其有两维 (真实值 "actual" 和 预测值 "predicted" ), 这两维都具有相同的类("classes")的集合. 在列联表中, 每个维度和类的组合是一个变量. 列联表以表的形式, 可视化地表示多个变量的频率分布. 

对于应用程序开发人员而言,混淆矩阵就是一个二维数组,分别表示预测值和真实值,里面的值表示对应值的占比。

开发步骤

创建WPF应用程序项目

在了解了混淆矩阵的用途和原理后,就可以着手去开发,首先创建一个WPF应用程序项目,然后创建模型MatrixM,主要包括标题,x轴,y轴的标签和刻度说明,数据,颜色设置。如下所示:

public class MatrixM:ObservableObject
{
	private string title;
	public string Title { get { return title; } set { SetProperty(ref title, value); } }
 
	private string xLabel;
	public string XLabel { get { return xLabel; } set { SetProperty(ref xLabel, value); } }
 
	private string yLabel;
	public string YLabel { get { return yLabel; } set { SetProperty(ref yLabel,value); } }
 
	private string[] yaxis;
	public string[] Yaxis { get { return yaxis; } set { SetProperty(ref yaxis, value); } }
 
	private string[] xaxis;
	public string[] Xaxis { get { return xaxis; } set { SetProperty(ref xaxis, value); } }
 
	public double[,] Data { get; set; }
 
	private Color minBrush;
	public Color MinBrush { get { return minBrush; } set { SetProperty(ref minBrush, value); } }
 
	private Color maxBrush;
	public Color MaxBrush { get { return maxBrush; } set { SetProperty(ref maxBrush, value); } }
}

 

注意:在本示例中,矩阵的数据采用二维数组进行存储

构造数据

构造示例数据,在实际开发中,数据来源于算法的真实分析,本例主要用于演示前端开发,所以构造一些测试数据,如下所示:

private MatrixM dataM;
public MatrixM DataM { get { return dataM; } set { SetProperty(ref dataM,value); } }
 
private UniformGrid matrix;
 
public MainWindowViewModel()
{
	this.DataM = new MatrixM();
	this.DataM.Title = "Confusion  Matrix on Fer2024";
	this.DataM.XLabel = "Predict Label";
	this.DataM.YLabel = "Truth Label";
	this.DataM.Xaxis = new string[] { "Angry","Disgust","Fear","Happy","Sad","Surprise","Neutral"};
	this.DataM.Yaxis = new string[] { "Angry", "Disgust", "Fear", "Happy", "Sad", "Surprise", "Neutral" };
	this.DataM.MinBrush = Colors.White;
	this.DataM.MaxBrush= Colors.DarkSlateBlue;
	this.DataM.Data = new double[,] {
		{0.66,0.01,0.09,0.04,0.11,0.01,0.09 },
		{0.23,0.64,0.0,0.04,0.09,0.0,0.0},
		{0.08,0.0,0.58,0.02,0.15,0.08,0.1},
		{0.01,0.0,0.01,0.89,0.01,0.02,0.06 },
		{0.09,0.0,0.11,0.03,0.6,0.01,0.15},
		{0.02,0.0,0.05,0.04,0.02,0.85,0.02 },
		{0.05,0.0,0.04,0.07,0.11,0.01,0.72 }
	};
}

 

页面布局

在WPF中,为了弹性呈现数据及自动缩放,主要用Grid,UniformGrid进行页面布局,交互主要用Button来实现,都是基础知识。如下所示:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"></ColumnDefinition>
        <ColumnDefinition Width="*"></ColumnDefinition>
        <ColumnDefinition Width="Auto"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
    </Grid.RowDefinitions>
    <TextBlock Text="{Binding DataM.Title}" FontSize="20" FontWeight="Bold" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5"></TextBlock>
    <TextBlock Text="{Binding DataM.YLabel}" Grid.Row="1" Grid.Column="0" FontWeight="Bold" FontSize="14" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5">
        <TextBlock.LayoutTransform>
            <RotateTransform Angle="270"></RotateTransform>
        </TextBlock.LayoutTransform>
    </TextBlock>
    <Grid Grid.Row="1" Grid.Column="1">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <ItemsControl Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" ItemsSource="{Binding DataM.Yaxis}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid Columns="1"></UniformGrid>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right">
                        <TextBlock Text="{Binding}"></TextBlock>
                        <Border Width="10" Height="1" BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Right" Margin="10 0 0 0"></Border>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <Border BorderBrush="Black" BorderThickness="1" Grid.Row="0" Grid.Column="1" >
            <UniformGrid x:Name="matrix" >
                <UniformGrid.Resources>
                    <Style TargetType="Button">
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Opacity" Value="0.5"></Setter>
                                <Setter Property="FontWeight" Value="Bold"></Setter>
                                <Setter Property="FontSize" Value="16"></Setter>
                                <Setter Property="Cursor" Value="Hand"></Setter>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </UniformGrid.Resources>
            </UniformGrid>
        </Border>
        <ItemsControl Grid.Row="1" Grid.Column="1" ItemsSource="{Binding DataM.Xaxis}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid Rows="1"></UniformGrid>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Vertical" VerticalAlignment="Top" HorizontalAlignment="Center">
 
                        <Border Width="10" Height="1" BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Center" Margin="0 0 0 0">
                            <Border.RenderTransformOrigin>
                                <Point X="0.5" Y="0.5"></Point>
                            </Border.RenderTransformOrigin>
                            <Border.LayoutTransform>
                                <TransformGroup>
                                    <RotateTransform Angle="90"></RotateTransform>
                                </TransformGroup>
                            </Border.LayoutTransform>
                        </Border>
                        <TextBlock Text="{Binding}">
                            <TextBlock.RenderTransformOrigin>
                                <Point X="0.5" Y="0.5"></Point>
                            </TextBlock.RenderTransformOrigin>
                            <TextBlock.LayoutTransform>
                                <TransformGroup>
                                    <RotateTransform Angle="-45"></RotateTransform>
                                    <TranslateTransform Y="20"></TranslateTransform>
                                </TransformGroup>
 
                            </TextBlock.LayoutTransform>
                        </TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <Rectangle  Grid.Row="0" Grid.Column="2" Width="20" Margin="10 0">
            <Rectangle.Fill>
                <LinearGradientBrush StartPoint="0 0" EndPoint="1 1">
                    <GradientStop Offset="0" Color="{Binding DataM.MaxBrush}"></GradientStop>
                    <GradientStop Offset="1" Color="{Binding DataM.MinBrush}"></GradientStop>
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
    </Grid>
 
    <TextBlock Text="{Binding DataM.XLabel}" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" FontWeight="Bold" FontSize="14" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5"></TextBlock>
 
</Grid>

 

注意:标题,刻度,轴说明 ,都是固定布局,可以进行数据绑定,而矩阵内容需要动态创建,所以分开处理。

构造矩阵

在本示例中,混淆矩阵以UniformGrid为容器,动态根据数据创建,并填充到容器中,如下所示:

private IRelayCommand<object> loadedCommand;
 
public IRelayCommand<object> LoadedCommand =>loadedCommand??=new RelayCommand<object>(Loaded);
 
private void Loaded(object obj)
{
	if (obj != null)
	{
		var win = obj as MainWindow;
		if (win != null)
		{
			this.matrix = win.matrix;
			InitMatrix();
		}
	}
}
 
private void InitMatrix()
{
	if(this.matrix == null)
	{
		return;
	}
	this.matrix.Children.Clear();
	this.matrix.Rows = this.DataM.Data.GetLength(0);
	this.matrix.Columns = this.DataM.Data.GetLength(1);
	var color = this.DataM.MaxBrush;
	for(int row = 0; row < this.DataM.Data.GetLength(0); row++)
	{
		for(int col = 0; col < this.DataM.Data.GetLength(1); col++)
		{
			Border border = new Border();
			border.Background = new SolidColorBrush(Color.FromArgb((byte)(this.DataM.Data[row, col] * color.A), color.R, color.G, color.B));
			var button = new Button();
			button.Content = this.DataM.Data[row, col].ToString("0.00");
			button.FontSize = 12;
			button.HorizontalContentAlignment= System.Windows.HorizontalAlignment.Center;
			button.VerticalContentAlignment= System.Windows.VerticalAlignment.Center;
			button.Background = Brushes.Transparent;
			button.BorderThickness = new System.Windows.Thickness(0);
			border.Child= button;
			this.matrix.Children.Add(border);
		}
	}
}

 

注意,在Grid,UniformGrid此类容器中,控件不需要设置宽和高,会自动根据容器大小进行自适应。且不能设置对齐属性,否则控件大小则不会自适应调整大小。

示例效果

运行VS,实例效果如下所示:

以上就是【基于WPF开发动态可交互混淆矩阵】的全部内容。希望可以一起学习,共同进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/677215.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

正序输入一串数,倒序输出,c语言

正序输入一串数&#xff0c;倒序输出 #include <stdio.h> int main () {int i,a[5]; for(i0;i<5;i) {scanf("%d",&a[i]);} for(i4;i>0;i--) {printf("%d",a[i]);} printf("\n"); return 0; } 运行结果

三分钟“手撕”队列与习题

代码放开头&#xff0c;方便大家查阅 目录 一、实现代码 二、什么是队列 三、队列常见方法 入队push&#xff08;&#xff09; 出队 四、Queue使用 Java自带的Queue 双端队列 五、习题 循环队列 用队列实现栈 用栈实现队列 一、实现代码 package demo2;publi…

【leetcode10-21】子串、普通数组、矩阵

子串 560.和为K的子数组【没理解】 什么是前缀和&#xff1a;前缀和指一个数组的某下标之前的所有数组元素的和&#xff08;包含其自身&#xff09; 通常&#xff0c;会在前缀和首位放一个0。比如数组[1,2,3。其前缀和是[0,1,3,6] 前缀和通常可以帮助我们快速计算某个区间内的…

【控制实践——四旋翼无人机】【一】四旋翼无人机运动分析和建模

传送门 系列博客前言坐标系定义及姿态位置描述坐标系定义姿态描述及坐标系变换 受力分析牛顿-欧拉方程状态空间方程总结 系列博客 前言 在C站摸爬滚打一段时间后&#xff0c;发现控制类相关的圈子较小&#xff08;话题热度低&#xff09;&#xff0c;想顺便跟各位同行读者了解…

Netty是什么?深入理解高性能网络框架

Netty是什么&#xff1f;——深入理解高性能网络框架 引言 在现代互联网应用中&#xff0c;网络通信是不可或缺的一部分。无论是构建微服务架构、游戏服务器、实时通信系统还是物联网应用&#xff0c;高效稳定的网络编程框架都是成功的关键。Netty&#xff0c;作为一款高性能…

项目:仿RabbitMQ实现的消息队列组件

文章目录 写在前面开源仓库和项目上线其他文档说明 需求分析BrokerServer交换机类型持久化消息应答 模块划分服务端模块客户端模块交换机数据管理模块队列数据管理模块绑定数据管理模块消息数据管理模块队列信息管理模块虚拟机数据管理模块路由匹配模块消费者管理模块信道管理模…

HTML+CSS+JS 选项卡导航栏

效果演示 实现了一个导航栏切换内容的效果。页面上方有一个导航栏,每个导航项都有一个圆形背景,点击导航项时,圆形背景会放大并显示对应的内容。每个内容区域都包含一个大号字母,数字会在内容区域显示时淡入。点击其他导航项时,当前内容区域会淡出并隐藏,同时新的内容区域…

[数据集][目标检测]csgo头部身体检测数据集VOC+YOLO格式1265张4类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1265 标注数量(xml文件个数)&#xff1a;1265 标注数量(txt文件个数)&#xff1a;1265 标注…

群体优化算法----人工蜂群优化算法应用于路径规划(机器人避开平面障碍寻找最短路线)

介绍 人工蜂群优化算法&#xff08;Artificial Bee Colony Algorithm, ABC&#xff09;是由Dervis Karaboga在2005年提出的一种模拟蜜蜂觅食行为的优化算法。该算法基于蜜蜂群体的分工合作和信息交流机制&#xff0c;通过模拟蜜蜂寻找食物源的过程来解决优化问题。ABC算法因其…

mybatis—plus和mybatis的区别

一前置知识&#xff1a; CRUD操作&#xff08;create 添加数据read读取数据 update 修改数据delete删除数据&#xff09; 二&#xff0c;总体概览 MyBatis-Plus 是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发工作、提高…

INT202 例题

算法复杂度 O(n)&#xff1a;表示算法的渐进上界。如果一个算法的运行时间是O(n)&#xff0c;那么它的运行时间最多与输入规模n成正比。换句话说&#xff0c;当输入规模n增加时&#xff0c;算法的运行时间不会超过某个常数倍的n。比如&#xff0c;如果一个算法的时间复杂度是O(…

【InternLM实战营第二期笔记】04:XTuner 微调 LLM:1.8B、多模态、Agent

文章目录 笔记微调基础知识Xtuner8G显存微调模型InternLM2 1.8B多模态实践环节数据微调过拟合WebUI 交互 多模态微调 作业 这回学乖了&#xff0c;打开本节课第一件事先不看教程而是装环境~ 笔记 微调基础知识 这里感慨一下&#xff0c;垂直领域的训练还是挺困难的&#xff0c;…

jenkins的简单使用

2.1.简介 Jenkins是一个开源软件项目&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;旨在提供一个开放易用的软件平台&#xff0c;使软件的持续集成变成可能。 2.4.Jenkins安装 1.下载安装包jenkins.war&#xff1b; 2.在安装…

dpdk uio整体分析及网卡加载

参考:https://zhuanlan.zhihu.com/p/477600165 一、Linux内核知识点 1. __attribute__ constructor/destructor (1)若函数被设定为constructor属性,则该函数会在 main()函数执行之前被自动的执行。 (2)若函数被设定为destructor属性,则该函数会在main()函数执…

C++类的继承与派生概念

派生和继承是自然界普遍存在的一种现象。例如&#xff0c;“猫”和“白猫”。当人们谈及“猫”时&#xff0c;知道它有4条腿&#xff0c;1条尾巴&#xff0c;抓老鼠,为哺乳动物。如谈论“白猫”时&#xff0c;它也是猫&#xff0c;只不过增加了一个新的特征&#xff0c;即它的毛…

Harmony开发 List/Scroll 组件最后一个item显示不全或布局显示不完整

今天在做Harmony开发的时候遇到一个问题,List组件的最后一个item显示不全&#xff0c;如下图&#xff0c;item-9显示不出来&#xff0c;显示了一部分 这个页面的代码结构如下&#xff1a; Column() {Row() {Text(文本1).fontSize(15).fontColor(Color.Black)Text(文本2).font…

论文浅尝 | THINK-ON-GRAPH:基于知识图谱的深层次且可靠的大语言模型推理方法...

笔记整理&#xff1a;刘佳俊&#xff0c;东南大学硕士&#xff0c;研究方向为知识图谱 链接&#xff1a;https://arxiv.org/pdf/2307.07697.pdf 1. 动机 本文是IDEA研究院的工作&#xff0c;这篇工作将知识图谱的和大语言模型推理进行了结合&#xff0c;在每一步图推理中利用大…

2024视频号·短视频+直播极简培训班:抓住视频号风口,流量红利

课程下载&#xff1a;2024视频号短视频直播极简培训班&#xff1a;抓住视频号风口&#xff0c;流量红利-课程网盘链接提取码下载.txt资源-CSDN文库 更多资源下载&#xff1a;关注我。 课程内容&#xff1a; 02 1、为什么视频号有机会&#xff0c;而不是抖音?(直播2024.03.0…

攻防世界---misc---can_has_stdio?

1、下载附件是一个没有后缀的文件&#xff0c;尝试将后缀改为txt发现里面有一些特殊字符的编码 2、查阅资料得知它是一种编程代码 3、知道了它是什么代码之后&#xff0c;我们就去解码&#xff08;网址&#xff1a;El Brainfuck (copy.sh)&#xff09; 4、 flag{esolangs_for_f…

Centos 7之Hadoop搭建

介绍 Hadoop Distributed File System简称 HDFS&#xff0c;是一个分布式文件系统。HDFS 有着高容错性&#xff08;fault-tolerent&#xff09;的特点&#xff0c;并且设计用来部署在低廉的&#xff08;low-cost&#xff09;硬件上。而且它提供高吞吐量&#xff08;high throu…