应用潜在语义分析技术将文档进行3D可视化

简介

这里使用了 WPF(译者注:Windows Presentation Foundation) 的 3D 展示功能来对一个文档集合进行了可视化,这些文档是根据 AAAI 2014(一个人工智能会议)所接受的论文列表获取的。

潜在语义分析(LSA,Latent Semantic Analysis)使用文档词频矩阵(Document-term Matrix)的奇异值分解(SVD,Singular Value Decomposition)将文档集合投影到三维潜在空间(3D Latent Space)中。这个空间就被可视化在一个可以通过拖动鼠标进行操控的 3D 场景中。

本文中的程序使用了 Bright Wire 的开源机器学习库 来创建和归一化文档词频矩阵,并导入其相关的线性代数库以进行 SVD 和 LSA。

背景知识

详情请参阅我之前的 CodeProject 文章,以了解关于向量空间模型技术的简单知识。这其中最主要的一点是,它们以每个文档的每个单词的计数为中心进行归一化,然后存储在一个矩阵中。于是我们就可以使用向量乘法来比较代表文档的列或行的相似性。

我们可以用一个简单的比喻来描述 SVD 的用途:

· 假设你有数以千计的热带鱼在一个大鱼缸里游来游去。而你则想拍摄这样一张照片:照片中展示了鱼缸中各种各样的鱼,同时保留了鱼之间的相对距离。这时候 SVD 就可以告诉我们,在任意给定的时刻,能让我们拍摄到最佳照片的定位相机的最好的位置与角度。

构建可视化

应用程序启动后,首先进行如下操作:

  1. 下载论文数据集
  2. 将 CSV 文件解析到一个 DataTable
  3. DataTable 中创建强类型的 AAAIDocument
  4. 基于每个文档的元数据来创建稀疏特征向量
  5. 归一化稀疏特征向量,并创建密集特征向量
var uri = new Uri("https://archive.ics.uci.edu/ml/machine-learning-databases/00307/%5bUCI%5d%20AAAI-14%20Accepted%20Papers%20-%20Papers.csv");
var KEYWORD_SPLIT = " \n".ToCharArray();
var TOPIC_SPLIT = "\n".ToCharArray();
 
// download the document list
var docList = new List<AAAIDocument>();
using (var client = new WebClient()) {
    var data = client.DownloadData(uri);

    Dispatcher.Invoke(() => {
        _statusMessage.Add("Building data table...");
    });

    // parse the file CSV
    var dataTable = new StreamReader(new MemoryStream(data)).ParseCSV(',');
 
    // create strongly typed documents from the data table
    dataTable.ForEach(row => docList.Add(new AAAIDocument {
        Abstract = row.GetField<string>(5),
        Keyword = row.GetField<string>(3).Split(KEYWORD_SPLIT, StringSplitOptions.RemoveEmptyEntries).Select(str => str.ToLower()).ToArray(),
        Topic = row.GetField<string>(4).Split(TOPIC_SPLIT, StringSplitOptions.RemoveEmptyEntries),
        Group = row.GetField<string>(2).Split(TOPIC_SPLIT, StringSplitOptions.RemoveEmptyEntries),
        Title = row.GetField<string>(0)
    }));
}
 
// create a document lookup table
var docTable = docList.ToDictionary(d => d.Title, d => d);
 
// extract features from the document's metadata
var stringTable = new StringTableBuilder();
var classificationSet = new SparseVectorClassificationSet {
    Classification = docList.Select(d => d.AsClassification(stringTable)).ToArray()
};
 
// create dense feature vectors and normalise along the way
var encodings = classificationSet.Vectorise(true);

接下来的操作就是将这些密集特征向量组合成文档词频矩阵,并计算其 SVD。

找到前三个奇异值和 VT(V 矩阵的转置) 矩阵相应的行,然后相乘以产生潜在空间并投影到已经构建的文档词频矩阵中。

在潜在空间上运行 K 均值聚类来查找类似文档的组,以及为每个聚类关联不同颜色。

// create a term/document matrix with terms as columns and documents as rows
var matrix = lap.CreateMatrix(vectorList.Select(d => d.Data).ToList());
 
const int K = 3;
var kIndices = Enumerable.Range(0, K).ToList();
var matrixT = matrix.Transpose();
var svd = matrixT.Svd();
 
var s = lap.CreateDiagonal(svd.S.AsIndexable().Values.Take(K).ToList());
var v2 = svd.VT.GetNewMatrixFromRows(kIndices);
using (var sv2 = s.Multiply(v2)) {
    var vectorList2 = sv2.AsIndexable().Columns.ToList();
    var lookupTable2 = vectorList2.Select((v, i) => Tuple.Create(v, vectorList[i])).ToDictionary(d => (IVector)d.Item1, d => lookupTable[d.Item2]);
    var clusters = vectorList2.KMeans(COLOUR_LIST.Length);
    var clusterTable = clusters
        .Select((l, i) => Tuple.Create(l, i))
        .SelectMany(d => d.Item1.Select(v => Tuple.Create(v, d.Item2)))
        .ToDictionary(d => d.Item1, d => COLOUR_LIST[d.Item2])
    ;

然后通过相关的AAAIDocument,3D 投影以及簇色彩来创建Document模型。然后对文档位置进行归一化以将其可视化。

var documentList = new List<Document>();
int index = 0;
double maxX = double.MinValue, minX = double.MaxValue, maxY = double.MinValue, minY = double.MaxValue, maxZ = double.MinValue, minZ = double.MaxValue;
foreach (var item in vectorList2) {
    float x = item[0];
    float y = item[1];
    float z = item[2];
    documentList.Add(new Document(x, y, z, index++, lookupTable2[item], clusterTable[item]));
    if (x > maxX)
        maxX = x;
    if (x < minX)
        minX = x;
    if (y > maxY)
        maxY = y;
    if (y < minY)
        minY = y;
    if (z > maxZ)
        maxZ = z;
    if (z < minZ)
        minZ = z;
}
double rangeX = maxX - minX;
double rangeY = maxY - minY;
double rangeZ = maxZ - minZ;
foreach (var document in documentList)
    document.Normalise(minX, rangeX, minY, rangeY, minZ, rangeZ);

最后,每个都Document被转换成一个Cube并添加到 3D 视窗。

var numDocs = documentList.Count;
_cube = new Cube[numDocs];
 
var SCALE = 10;
for(var i = 0; i < numDocs;  i++) {
    var document = documentList[i];
    var cube = _cube[i] = new Cube(SCALE * document.X, SCALE * document.Y, SCALE * document.Z, i);
    cube.Colour = document.Colour;
    viewPort.Children.Add(cube);

使用 3D 模型

3D 场景中包含了:一个方向灯 —— 它能给予立方体一些额外的深度;以及一个PerspectiveCamera —— 其位置都通过响应鼠标输入进行轨迹球代码转换而得来。

我们可以使用下述代码来测试 3D 立方体:

Cube foundCube = null;
SearchResult correspondingSearchResult = null;
HitTestResult result = 
   VisualTreeHelper.HitTest(viewPort, e.GetPosition(viewPort));
RayHitTestResult rayResult = result as RayHitTestResult;
if(rayResult != null) {
    RayMeshGeometry3DHitTestResult rayMeshResult = 
            rayResult as RayMeshGeometry3DHitTestResult;
    if(rayMeshResult != null) {
        GeometryModel3D model = 
              rayMeshResult.ModelHit as GeometryModel3D;
        foreach(KeyValuePair<int,> item in _cubeLookup) {
            if(item.Value.Content == model && 
                      _searchResultLookup.TryGetValue(item.Key, 
                      out correspondingSearchResult)) {
                foundCube = item.Value;
                break;
            }
        }
    }
}

然后,选择/取消选中的多维数据集的笔刷和对应的搜索结果也可以进行相应更新。

我们可以通过按住鼠标左键或右键并拖动它以定位 3D 场景。这个轨迹球代码的有趣的之处,就是鼠标事件是被触发在一个叠加在 3D 场景上的透明的边界上的。这是因为WPF的Viewport3D类只有在光标位于 3D 模型上时才会触发鼠标事件。轨迹球代码基本上是一个“黑盒”,它可以附加到任何 3D 场景来实现场景的视觉操纵。我们将其附加如下(注意,我们正在附加到强加的边界):

ModelViewer.Trackball trackball = new ModelViewer.Trackball();
myPerspectiveCamera.Transform = trackball.Transform;
directionalLight.Transform = trackball.Transform;
...
trackball.EventSource = borderCapture;

小结

LSA 是广泛用于减少数据集维度的一项技术。在本文所述项目中,我们通过将其投影到三维而不是更为典型的二维来可视化,使我们得以保留更多实用的信息。

使用本文的可视化技术我们可以看到,这些论文通常遵循着相当一致的模式,论文的三个主要峰值主题是 博弈论人工智能与人类 以及 计划与执行,我们还能发现在所收集到的论文中,有大量的论文主要描述了一些具体的机器学习技术。

这样的可视化方法也可以让我们更容易地发现数据集中的异常值。

这种技术的主要缺点是 SVD 计算开销较大。如果你使用 GPU 运行 Bright Wire,可能会有所改进,但通常 LSA 对于非常大的矩阵来说并不实用。

版本回顾

  • 2009年5月19日:首版出世。
  • 2017年2月23日:主要更新了数据集的 URL。

本文的版权归 StoneDemo 所有,如需转载请联系作者。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大数据文摘

三种可视化方法,手把手教你用R绘制地图网络图!

28040
来自专栏量化投资与机器学习

【Python机器学习】支持向量机(附源码)

从本周开始,推送一个系列关于 Python 机器学习 。为了保证内容的原汁原味。我们采取全英的推送。希望大家有所收获。提高自己的英语阅读能力和研究水平。 In...

21590
来自专栏人工智能

Redis-ML简介(第5部分)

原文地址:https://dzone.com/articles/an-introduction-to-redis-ml-part-five-redis-labs

1.2K90
来自专栏生信技能树

ChIP-seq实战分析

作者注 本次讲解选取的文章是为了探索PRC1,PCR2这样的蛋白复合物,不是转录因子或者组蛋白的CHIP-seq,请注意区别。 文章题目 RYBP and Cb...

37560
来自专栏JadePeng的技术博客

贝叶斯文本分类c#版

关于这个话题,博客园已经有多个版本了 基于朴素贝叶斯分类器的文本分类算法(上) 也谈贝叶斯分类(C#)版本 PyMining-开源中文文本数据挖掘平台 Ver ...

47150
来自专栏算法修养

文本分类学习 (十)构造机器学习Libsvm 的C# wrapper(调用c/c++动态链接库)

前言: 对于SVM的了解,看前辈写的博客加上读论文对于SVM的皮毛知识总算有点了解,比如线性分类器,和求凸二次规划中用到的高等数学知识。然而SVM最核心的地方应...

11220
来自专栏专知

【重磅】深度学习顶会 ICLR 2018 匿名提交论文列表(附pdf下载链接)

【导读】ICLR,全称为「International Conference on Learning Representations」(国际学习表征会议),201...

676100
来自专栏安富莱嵌入式技术分享

【安富莱二代示波器教程】第10章 示波器设计—数字信号处理

本章节为大家讲解二代示波器中用到的FFT和FIR。单纯从应用上来说,比较省事,调用API函数即可,从学习的角度来说,需要大家花点精力。

11130
来自专栏C/C++基础

n个骰子点数和及各自出现的概率

题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。输入n,打印出S的所有可能的值出现的概率。

20710
来自专栏AI研习社

Github 项目推荐 | 用 Pytorch 实现的 Capsule Network

本库用 Pytorch 实现的 Capsule Network 基于以下论文: Dynamic Routing Between Capsules by Sara...

42690

扫码关注云+社区

领取腾讯云代金券