预测GitHub和Stack Overflow主题建模的良好配置
摘要——软件库包含大量的文本数据,从源代码和issue描述到Stack Overflow上的问题、答案和相关文本。为了理解这些文本数据,主题建模经常被用作文本挖掘工具,用于发现文本主体中隐藏的语义结构。LDA是一种常用的主题模型,其目的是通过文本分组来解释语料库的结构。LDA需要多个参数才能很好地工作,对于如何设置这些参数,只有粗略的指导原则。在这篇论文中,我们贡献了①一个广泛的参数研究,以在GitHub和Stack Overflow的文本语料库上达到局部最优化;②与八种编程语言有关的文本语料库的后验特征;③通过每个语料库的LDA配置来分析语料库特征的重要性。我们发现①关于主题建模参数配置的常用经验法则并不适用于我们实验中使用的语料库;②从GitHub和Stack Overflow中采样的语料库具有不同的特性,需要不同的配置才能实现良好的模型拟合;③我们可以可靠地预测未知语料库的良好结构。这些发现支持研究人员和实践者在分析软件库中包含的文本数据时,有效地为主题建模确定合适的配置。
关键词:主题建模,语料库特征,算法组合。
由于技术的支持,人类产生的文本比以往任何时候都多,许多领域的生产力取决于文本内容的使用速度和效率。在软件开发领域,自2008年创建以来,超过800万用户在问答论坛Stack Overflow上发表了超过3800万篇帖子,在同一年成立的社交开发者网站GitHub上,已经创建了6700万个资料库。开发人员的生产力在很大程度上取决于他们如何有效地理解这些过多的信息。
文本处理领域发明了许多技术来处理大量文本数据,例如主题建模。主题建模是一种概率技术,通过自动发现隐藏在数据中的语义主题来总结大型文本文档。但如果要使用主题建模,必须设置许多参数。
Agrawal等人最近写了一篇软件工程领域主题建模的文献综述。他们发现在24篇文章中有23篇提到了创建主题模型的不稳定性,主要包括启动条件和参数的选择两个方面。尽管存在不稳定性,研究人员还是都选择使用默认参数,并且只对三个参数执行了某种排序的调优。即使研究人员将优化应用到他们的主题建模工作中,也无法从调优中得到更好的结果,而且在多大程度上进行调优取决于所分析的语料库的特性,例如,Stack Overflow需要的调优和GitHub数据需要的调优是相同的吗?与讨论其他编程语言的文本内容相比,与该编程语言相关的文本内容需要不同的参数设置吗?在本文中,我们使用数据驱动软件工程(DSE)和数据挖掘算法(DUO)对40个从GitHub和Stack Overflow中采样的语料库进行数据挖掘,以研究每个语料库的配置对主题建模的影响。我们提出两个研究问题:
问题一:从GitHub和Stack Overflow得到的文本语料库的最佳主题建模配置是什么?
问题二:我们能否仅根据未知语料库的特性自动选择好的配置?
我们发现(1)流行的主题建模参数配置不适用于从软件库中挖掘的文本语料库;(2)从GitHub和Stack Overflow采样的语料库具有不同的特征,需要不同的配置才能获得良好的模型拟合;(3)基于语料库特征,可以可靠地预测出未知语料库的良好配置。图1展示了我们实验中使用的语料库,在进行主成分分析后,根据它们的特征进行聚类。从图中可以看出,与不同编程语言相关的文本语料库以及来自不同来源的语料库(GitHub和Stack Overflow)确实可以根据它们的特性进行区分。即使跨源,文档的特定语言特征仍然存在,属于类似编程语言的语料库也彼此接近。此外,编程语言与它们的父辈(例如,C和c++)非常接近。我们使用这一发现作为对每个语料库进行主题建模配置的起点。我们的预测比基准高出4%,与虚拟最佳解决方案的差距不到1%。
这些发现为理解语料库特性对软件工程中的主题建模的影响提供了思路。它们为今后的工作提供了用来确定合适的主题建模配置的有效方法,最终使开发人员和研究人员更容易、更可靠地理解他们面临的大量文本数据。
本文的结构如下。首先,我们将在第二部分介绍主题建模;然后,在第三节中描述数据的收集,并提供数据的第一个统计特征;在第四节中,报告我们对个别语料库的调优;第五节提供了从每个语料库配置和每个语料库参数选择中获得的结论;第六部分确定了可能影响我们研究结果有效性的威胁;最后,我们总结并概述未来的工作。
主题建模是一种信息检索技术,它可以自动地在给定的文本语料库中找到主要的主题,而不需要标签、训练数据或预定义的分类法。主题建模是利用语料库的文档中单词的出现频率和单词的共现来建立相关单词的模型,已经被广泛应用于软件工程的研究中,例如,理解移动开发人员正在谈论的主题,确定测试用例的优先级,以及检测重复的bug报告。
创建主题模型最常用的技术是LDA,这是一个三层的贝叶斯模型,其中集合的每一项都被建模为一组主题的有限混合。一个文档的主题分布是从狄利克雷分布超参数α中随机抽样,每个主题的词分布是从狄利克雷分布超参数β中随机抽样。α表示文档主题的密度,α越高,文档中主题越多。β表示主题词的密度,β越高,主题中包含的文档中的词越多。此外,主题的数量(通常用k表示)是使用LDA创建主题模型所需的另一个参数。在许多研究中这些参数使用默认设置(α= 1.0,β= 0.01,k = 100或者α= 50 / k,β= 0.1)。近年来,研究人员发现,默认值不会导致最佳的模型拟合,并研究了使用优化来确定良好的参数值。为了测量模型的吻合度,研究人员使用了语言模型复杂度,即在给定上下文的条件上,句子中每个位置平均可以选择的单词数量。我们在这篇文章中也使用了它,低语言模型复杂度意味着语言模型正确地猜测测试数据中不可见的单词。
在本文中,我们着手研究在何种程度上,主题建模的最佳参数设置取决于被建模的语料库的特征。我们所有的实验都是使用Mallet中的实现的LDA进行的,版本为2.0.8.2。
现在我们来描述一下我们是如何收集研究中用到的数据的。我们定义用来描述它们的特性,并根据这些特性对它们进行描述。
A. 数据采集
为了涵盖不同来源和不同内容的数据,我们从GitHub和Stack Overflow中采样了与八种编程语言相关的文本内容。我们选择了两种来源中最流行的语言: C、 C++、 CSS、HTML、Java、 JavaScript、Python、Ruby。Stack Overflow的HTML和HTML5标签是独立的,GitHub没有区分它们,我们将它们设置为两个标签。类似地,Stack Overflow区分了Ruby和Ruby-on-Rails,而GitHub没有。
对于每一种编程语言,我们收集了5000个文档,并将它们存储为5个语料库,每个语料库包含1000个文档,以便能够在单个语料库之外进行归纳。我们对这两个来源的采样和预处理方法如下所述。
Stack Overflow抽样:我们通过Stack Overflow API下载了八种编程语言中每种语言最近的5000个题目。每个题目形成一个文档(标题+正文+可选答案,用一个空格分隔)。
Stack Overflow预处理:我们删除了换行符、代码块以及文档中的所有HTML标记。此外,还替换了HTML符号,用双引号替换了表示特殊字符的字符串,将空格序列替换为单个空格。
GitHub抽样:我们随机抽样了GitHub存储库的README文件,这些文件至少使用了八种编程语言中的一种,使用脚本反复选择0到120000000之间的随机项目ID(在我们收集数据时,所有GitHub存储库的ID都小于120000000)。如果随机选择的GitHub存储库至少使用了这八种编程语言中的一种,我们将确定它是否包含README文件,如果这个README文件包含至少100个字符,并且没有非ascii字符,那么我们将其内容作为文档包含在我们的数据集中。
GitHub预处理:与Stack Overflow预处理类似,我们删除了换行符、代码块、所有HTML标记、单个反引号、竖线和水平线和注释。我们还删除了表示节标头的字符(#)、表示格式的字符(*、_)、链接(保留链接文本)和标志(前面有感叹号的链接)。此外,我们还替换了HTML符号,用双引号替换了表示特殊字符的字符串,将空格序列替换为单个空格。
B. 语料库的特征
如前所述,在软件工程数据的主题建模应用中,只有一小部分对配置进行了优化,但优化后也没有从实验中获得更好的结果。虽然他们都认为参数调优很重要,但是还不清楚调优在多大程度上依赖于语料库特性。为了能够进行这样的探索,我们计算了表1(每个特征被计算两次,一次考虑停止词,一次不考虑停止词,来判断两者之间的潜在差异)。
我们计算了每个语料库中的字符数,以及一个语料库中每个文档的字符数。为了将每个文档的字符数聚合到语料库级别,我们为它们的中值和标准差创建了单独的特性。这使我们能够捕获语料库中典型的文档长度,以及语料库在文档长度方面的多样性。类似地,我们计算每个语料库和每个文档的单词数和唯一单词数。
虽然这些特性在长度方面捕获了文档和语料库的基本特征,但它们没有捕获语料库的性质。为了抓住这一点,我们依赖于熵的概念。正如克特里卡所描述的那样,文档的熵越高,文档涵盖的主题就越多,因此就越普遍。为了计算熵,我们用香农的定义:
式中pi为文档中单词i出现在单词流中的概率。我们计算了每个语料库和每个文档的熵值,分别考虑了有停止词和没有停止词的文本内容。
C. 描述统计
虽然我们已经定义了许多语料库特性,但是还不清楚这些特性之间的相关性如何,以及同样的关系是否适用于GitHub的README文件和Stack Overflow的文本。图2显示了24个特征之间基于皮尔逊相关系数的相关关系,并采用层次聚类方法进行聚类。正如预期的那样,基于熵的特征是相关的,那些基于中位数和标准差的特征也是相关的,当我们考虑所有语料库之间的关系时,这一点变得尤为明显(图2c)。
然而,GitHub和Stack Overflow两个来源之间存在着差异。例如,与Stack Overflow语料库相比,GitHub语料库中的stdevDocumentEntropy与其他特性的相关性较小。一个原因可能是GitHub中的README文件在结构上与Stack Overflow的问题不同。此外,与Stack Overflow相比,GitHub语料库中基于中位数的特性值与其他特性的相关性更小。我们推测这是因为README文件的长度变化比Stack Overflow的更大,Stack Overflow的问题长度更一致。
接下来,我们将研究不同编程语言之间的差异。由于我们有24个特性和跨越两个源的8种编程语言,这里我们将只讨论一些有趣的情况。在图3中,我们从一些易于计算的特征开始。我们在第一行看到GitHub文档的长度大约是Stack Overflow讨论的两倍。联合的分布也显示了这一点,左和右的驼峰来自两个不同的来源。如果去掉停止字,趋势将保持不变。这表明只要考虑其中一个易于计算的特性,我们就可以很准确地将这两个源区分开。尽管如此,单文档的可靠分类似乎并不是简单地基于非停止词的唯一单词的数量:在第三行中,我们可以看到两个图完美的合并了。
对于熵来说,它的计算时间要长得多,我们可以看到非常相似的特征(参见图3中底部的两行)。如图2所示,熵和字数是相关的,但它们之间的关系不如其他度量方法那样紧密。有趣的是,GitHub文档包含的停止字(约40%)比Stack Overflow文档包含的停止字(约50%)少。这似乎显示了前者中包含更多的技术描述,而后者中包含更多一般的讨论,这反映在GitHub内容相对于Stack Overflow内容的更高的熵上。接下来,我们简要地研究了Stack Overflow特性的重尾。这是由C和c++语料库引起的,这些文档比Ruby、Python、Java上的短文档大约长20-30%,最短的文档在HTML、JavaScript和CSS上。
最后,利用k-means方法对特征空间中的语料库进行聚类,预处理时我们使用标准尺度和主成分分析映射到两个维度。事实证明,使用这种聚类几乎可以很好地区分每个源的各个语言(图4),并且可以很好地区分GitHub和Stack Overflow两个源。即使在不同的源之间,文档的特定于语言的特征仍然存在,而且类似的语言彼此接近(参见图1)。此外,编程语言在他们的父辈附近。
许多优化方法可用于调优LDA参数,正如前面提到的,在最近的文献综述中有三篇文章进行了调优,都使用了遗传算法。
LDA对起始种子很敏感,并且这种噪声可能对许多优化算法造成挑战。幸运的是,近年来,许多自动参数优化方法已经开发出来,并以软件包的形式发布,这样做的目的是使广泛的参数能够以系统的方式得到有效的测试。一旦有足够强的统计证据表明某个特定的参数设置是次优的,那么就将其从考虑范围中删除。在实践中,通常只需几次迭代就可以消除大量的参数设置,从而使这成为一个有效的过程。
为了回答我们的第一个研究问题,从GitHub和Stack Overflow得到的文本语料库的最佳主题建模配置是什么?我们使用irace 2.3。我们给irace一个运行LDA10000次的方案,如果发现收敛,我们允许irace重新启动,它基于初步的实验,提供了非常好的结果,几乎不依赖于CPU时间预算。LDA的性能是用语言模型复杂度来度量的,在最后的测试中,每个语料库(由irace确定)的最佳配置运行101次,以获得稳定的平均性能值,标准误差为10%。在接下来的分析中,我们考虑这101次运行的中位数。
我们的参数范围比文献中考虑的范围更宽,并通过我们的初步实验得知:主题数k∈[3,1000],α∈[0.001,200.0],β∈[0.001,200.0]。作为初始配置,irace可以设置为Mallet中的默认值,k = 100,α= 1.0,β= 0.01。
作为一个例子,我们在图5中展示了irace的最终输出,它优化了与C相关的5个语料库的参数,这些语库来自GitHub CGitHub-1。作为比较,默认配置的语言模型复杂度中值为342.1。配置进化到有大量的主题,和一个非常大的β值。我们观察到尽管配置不同,但语言模型复杂度的值彼此之间非常接近(大约在234到237之间,比Mallet低31%)。
结果如表二所示,来自这两种语言的语料库和来自这八种编程语言的语料库需要不同的参数设置,以获得良好的语言模型复杂度,从而获得有用的主题。
我们可以看到,GitHub语料库中处理的主题数量明显高于Stack Overflow语料库,这可能是由于不同软件项目的README文件的性质,Stack Overflow中的讨论可能更有限。此外,Stack Overflow语料库的差异似乎比GitHub语料库(16%)更大一些(标准差为22%)。
当涉及到不同的编程语言时,我们发现在Python / C / c++中,GitHub语料库的主题数量是最多的,这似乎与第三部分中观察到的这些语料库的corpusEntropyNoStopwords的突出值高度相关。同样的,熵最小的语料(即CSS / HTML / JavaScript)似乎需要最小的主题数量来达到良好的语言模型复杂度。
其他有趣的观察是,β值在Stack Overflow语料库变化更多,而α值的变化大多是因为语料库的来源不同。
总结:流行的主题建模参数配置不适用于来自GitHub和Stack Overflow的文本语料库。这些语料库具有不同的特点,需要不同的配置才能实现良好的模型拟合。
对算法进行调优的另一种方法是从一个组合中选择一个算法,或者在给定一个实例时确定一个算法配置。这通常涉及到将机器学习模型与作为特征数据的实例结合起来,对算法的性能数据进行训练。这种方法在软件工程中受到了很多关注,对此感兴趣的可以参考最近更新的调查文章。算法选择的思想是,给定一个实例,算法选择器从一组(通常很小)算法中选择一个性能良好的算法,即所谓的组合。
为了回答我们的第二个研究问题,我们能否仅根据未知语料库的特性自动选择好的配置?我们研究是否可以将算法选择应用到LDA配置中,以进一步提高其性能,而不仅仅是参数调整。我们从每种语言和每个源中提取每个语料库的调优配置(按字母顺序排序),然后考虑我们的默认配置,总共生成17个名为gh.C, ... so.C, ...的配置和默认配置。由于在算法组合领域中很常见,我们将这些不同的配置视为不同的算法,并尝试预测哪个配置应该用于一个新的给定实例。这将让我们有效地测试哪一个调优的配置在其他类上执行得很好。
由于算法选择通常使用机器学习来实现,我们需要两个准备步骤:(1)用数字表示实例的实例特性;(2)每个实例上的每个算法的性能数据。我们已经在第三部分描述了我们的语料库,所以我们只需要在所有语料库上运行17种配置中的每一种。
图6概述了在所有语料库上运行的17种配置的性能。我们可以看到,在主题建模中,每个语料库的配置对于获得最低的语言模型复杂度是必要的。17种构型的平均语言模型复杂度为227.3,最佳配置是so.Java,其语言模型复杂度平均值为222.9,默认配置平均达到250.3(多了12%)。
根据我们拥有的所有数据,我们可以模拟所谓的虚拟最佳解算器,它将为17个配置中的每个语料库选择最佳的配置。这个虚拟最佳解算器的语言模型复杂度平均为217.9,比so.Java好2%,比默认配置好14%。最后,让我们看看实际的配置选择。我们为每一对配置训练一个对成本敏感的随机森林,然后为每一对配置预测性能更好的配置。然后,整个模型提出了性能最佳的配置。在我们的例子中,我们使用这种方法从17种配置中选择一种,给定一个实例,用它的特性来描述。经过训练的模型的预测的平均语言模型复杂度为219.6:这比17个调优配置的平均性能提高了4%,与虚拟最佳解决方案的差距不到1%。
我们对模型中特征的重要性很感兴趣,不仅是为了了解领域,而且实例特征的计算是算法组合应用的重要步骤。图7显示,没有一个单独的特性,而是一组很大的特性,它们共同描述了一个语料库。因此,根据语料库特性来选择适当的配置几乎是不可能的,尽管许多特性是相关的。有趣的是,基于需要昂贵计算的熵的特性在随机森林中并不重要,这对将来的每个语料库配置都有好处,因为其他的特性可以很快地计算出来。
总结:我们可以可靠地预测未知语料库的良好配置。我们的预测比默认配置的性能好14%,比最佳调优配置的性能好4%,与虚拟最佳解决程序的性能差不到1%。
与所有的实证研究一样,有一些威胁可能会削弱我们的结果的有效性。结构效度的威胁关系到我们评估标准的适用性。我们使用语言模型复杂度来衡量我们的主题模型的适合度,语言模型复杂度并不是唯一可以用来评估主题模型的指标,Chang等人的一项研究发现,语言模型复杂度和人类的判断往往是不相关的。未来的工作将必须研究使用其他指标(如简洁性或一致性)来预测文本软件工程语料库的良好配置,根据主题模型的优化目标的变化,最优值可能会有所不同。此外,选择不同的语料库特征可能会导致不同的结果。我们选择了易于计算的特性和熵作为起点,研究其他特性的影响是我们未来工作的一部分。
外部有效性的威胁影响我们发现的普遍性。我们不能声称我们的发现是泛化的,我们的工作可能不会超出GitHub README文件和Stack Overflow问题的范围,也不会超出我们在本工作中考虑的特定编程语言。此外,我们在这项工作中能够考虑的数据量必然是有限的。选择不同的文档可能会导致不同的结果。内部有效性的威胁与实施和实验中的错误有关。我们仔细检查了我们的实现和实验,并修正了我们发现的错误。不过,可能还有我们没有注意到的其他错误。
主题建模是一种自动化技术,用于理解大量文本数据。为了了解参数调优对软件开发语料库中主题建模应用的影响,我们使用了从GitHub中采样的40个语料库,从Stack Overflow中采样的40个语料库,每个语料库包含1000个文档。我们发现(1)流行的主题模型参数配置并不适用于我们的实验中使用的语料库;(2)GitHub和Stack Overflow有不同的特点和需要不同的配置来达到好的模型;(3)我们能根据未知语料库的特性自动选择好的配置。
这些发现对于有效地确定合适的主题建模配置起着重要的作用。最新的方法分别为每个语料库确定最佳配置,而我们的工作表明语料库特性可以用于预测好的配置。我们的工作证明在文本数据中数据来源和上下文(如编程语言)很重要,与同一编程语言相关的语料库自然形成集群,甚至来自相关编程语言(如C和C++)的内容也是相同集群的一部分。在未来的工作中,我们还将进一步探索特征与良好的主题建模配置之间的关系,使用更大、更多样化的语料库以及其他特征和纵向方法。我们还将通过工具向最终用户提供我们的方法,并进行定性研究,以确定所发现的主题在多大程度上对人类有意义。
个人想法:LDA主题提取是一种论文中提取主题经常使用的方法,但少有文章对它的参数配置问题进行研究。该论文从LDA的参数配置问题出发,考虑了不同平台、不同语言对LDA主题提取的影响,从一个比较小的点出发,在分析出不同语料库需要不同的LDA参数配置时又继续研究是否可以通过未知语料库的特性进行LDA配置的预测,虽然论文中的指标和方法都比较基础,但实验的过程和结果的推理都有比较强的逻辑性,利用比较基础的数据挖掘知识就得出了有意义的结果,而且还有跨平台实验的背景,所以能在顶会上看到这篇论文。