基於WPF開發動態可交互混淆矩陣

来源:https://www.cnblogs.com/hsiang/p/18227765
-Advertisement-
Play Games

最近在項目中,為了演算法結果的可視化,需要用到混淆矩陣(Confusion Matrix),而網上資源大多是基於Python繪製的混淆矩陣,並且是輸出圖片格式,並不能響應用戶點擊,今天以一個簡單的小例子,簡述如何通過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開發動態可交互混淆矩陣】的全部內容。希望可以一起學習,共同進步。


作者:小六公子
出處:http://www.cnblogs.com/hsiang/
本文版權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段聲明,且在文章頁面明顯位置給出原文連接,謝謝。
關註個人公眾號,定時同步更新技術及職場文章


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Lambda表達式 Lambda表達式,也可以稱為閉包,是Java 8發佈的最重要新特性 Lambda允許把函數作為一個方法的參數(函數作為參數傳遞進方法中) 使用Lambda表達式可以使代碼變的更加簡潔緊湊 語法: (parameter) -> expression (parameter) -> ...
  • Node.js是一個基於 Chrome V8 引擎的 JavaScript 運行環境。Node.js 使用了一個事件驅動、非阻塞式 I/O 的模型,使其輕量又高效。Express是一個保持最小規模的靈活的 Node.js Web應用程式開發框架,為Web和移動應用程式提供一組強大的功能。使用Node ...
  • 進程是電腦分配資源的基本單位,線程是cpu調度的基本單位 線程基本概念: LWP:light weight process 輕量級的進程。創建線程的底層函數和進程一樣,都是clone,因此線程的本質仍是進程(在linux環境下) 與進程相比,線程有獨立的TCB結構體(類似於進程的PCB),但沒有獨 ...
  • this,構造器,static,final,單例模式 this關鍵字 在java中this是一個引用變數,即指向當前對象地址的引用(指針),→可以把this當作當前對象,便於更好的索引. this() 實際是調用了當前對象的構造器 1. 引用當前對象的屬性 當在方法中要訪問當前對象的屬性時,可以用t ...
  • 1.線程池本質 ​ 多個線程組成的一個集合,目的為了併發執行任務,定義時是一個結構體,成員有互斥鎖,條件變數,任務鏈隊列指針,任務鏈隊列中等待的任務個數,當前活躍的線程數量,線程ID,線程銷毀標記等 2.線程池的關鍵技術 (1)萬能函數指針(通用函數指針): *void *(*p)(void ) ( ...
  • 要求:調用PLL—IP核,50Mhz晶振輸入,輸出四路時鐘不同信號:100Mhz,25Mhz,50Mhz(90°相位),50Mhz(20%占空比)。 晶元型號:cyclone Ⅳ EP4CE10F17C8 平臺工具:Quartus II 15.0 (64-bit)、Modelsim SE-64 ... ...
  • Redis是基於Reactor模式開發的網路事件處理器,這個處理器是單線程的,所 以redis是單線程的。 為什麼它是單線程還那麼快呢? 主要有以下幾個原因: 一、純記憶體操作 由於Redis是純記憶體操作,相比於磁碟來說,記憶體就快得多,這個是Redis快的主要 原因。 二、多路復用I/O機制(NIO) ...
  • 1. MyBatis中的介面代理機制及其使用 @目錄1. MyBatis中的介面代理機制及其使用2. 實操2.1 準備工作2.2 insert 增加操作2.3 delete 刪除操作2.4 update 修改操作2.5 select 查詢一條記錄操作2.6 select 查詢多條記錄操作3. 總結: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...