使用潜在语义分析在 3D 中可视化文档






4.37/5 (12投票s)
使用潜在语义分析在 3D 中可视化文档。
引言
这里使用 WPF 的 3D 功能来可视化文档集合,在本例中是 AAAI 2014(一个人工智能会议)的已接受论文列表。
潜在语义分析 (LSA) 使用文档/词项矩阵的奇异值分解 (SVD),将文档集合投影到三维潜在空间中。 然后,此空间在 3D 场景中可视化,该场景可以通过拖动鼠标来导航。
该应用程序使用开源 Bright Wire 机器学习库来创建和规范化词项文档矩阵,并使用其相关的线性代数库来执行 SVD 和 LSA。
背景
请参阅我之前的 CodeProject 文章,以简要介绍向量空间模型技术。 主要要点是它们围绕每个文档中每个词项的计数展开,这些计数被规范化然后存储在矩阵中。 然后,可以比较表示文档的列或行,以使用向量乘法来确定相似性。
SVD 的一种描述方式如下:假设您有数千条热带鱼在一个大鱼缸里游动。 您想拍摄一条鱼的照片,该照片可以显示鱼缸中鱼的全部种类,同时保留鱼之间的相对距离。 SVD 将能够告诉您,在任何给定的时刻,拍摄该“最佳”照片的最佳位置和角度。
构建可视化
当应用程序启动时,它会
- 下载已接受的论文数据集
- 将 CSV 解析为
DataTable
- 从
DataTable
创建强类型的AAAIDocument
- 使用每个文档的元数据来创建稀疏特征向量
- 规范化稀疏特征向量并创建密集特征向量
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 矩阵的相应行相乘,以创建潜在空间,文档/词项矩阵已投影到该空间中。
在潜在空间上运行 K-means 聚类,以找到相似的文档组,以及与每个群集关联的颜色。
// 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。