看Github上的开发者是如何更换编程语言的?
YvetteHolid
7年前
<p><em>译者注:你是否曾经想过尝试换一门语言进行开发,从而挑战一下自己。本文作者分析了GitHub上面的用户,从而得到了用户切换开发语言的相关信息。以下为译文。</em></p> <p>你是否曾经一边挣扎于项目的混乱,一边思考着:“我可以用这门语言来做,但是为什么不尝试换一门语言,看看会不会更有趣呢?”。 <a href="/misc/goto?guid=4959750727802252378" rel="nofollow,noindex">埃里克·伯恩哈德森</a> 曾在博客中写过一篇很好的文章:“ <a href="/misc/goto?guid=4959750727897349025" rel="nofollow,noindex">为什么我们从语言X换成语言Y</a> ”的特征向量,他根据所有与语言变化相关的谷歌查询做了一个情形分析表。然而,当我读到它的时候,我忍不住想知道,真正跨行成功的人的比例是多少。因此,越来越多的人开始深入了解这一想法,并了解在GitHub用户中语言的流行程度是如何变化的。</p> <h2><strong>可用数据集</strong></h2> <p>多亏了数据检索管道,source{d}可以将数据集开放给用户,其中包含每年每位GitHub用户使用不同编程语言编写的代码的字节数。在一些图中,它是:</p> <ul> <li>450万GitHub用户</li> <li>393种不同的语言</li> <li>总共10TB的源码</li> </ul> <p>如果你想知道这些存储库和语言的细节,我建议你可以看看 <a href="/misc/goto?guid=4959750727980791287" rel="nofollow,noindex">Vadim Markovtsev</a> 的博客文章: <a href="/misc/goto?guid=4959750728063831449" rel="nofollow,noindex">Spaces or Tabs</a> 。</p> <p>为了更好的理解接下来将会发生什么,我发现如果用 <a href="/misc/goto?guid=4959736901020830738" rel="nofollow,noindex">甘特图</a> 的形式将开发语言的使用历史以可视化的形式进行展示,效果很不错。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/bb955c489ef325fc383472bf78f12ba1.png"></p> <p>注意,颜色表示每种语言的源码的比例。我们可以从这个图中推导出一些信息:</p> <ul> <li>用户最喜欢的语言是 <strong>Scala</strong> ,而且只钟情于它。</li> <li>用户尝试了了 <strong>Go语言</strong> ,但没坚持多久。</li> <li>他们用 <strong>Java</strong> 运行了一个重要的项目,但是他们宁愿在Scala中编写代码。使用Java可能是完成单个项目的一个约束。</li> </ul> <p>当然,从这张图中可能会推导出在2014年用户开始从 <strong>Java</strong> 切换到 <strong>Markdown</strong> 。我们希望避免去比较那些没有可比性的语言。这就是为什么我们将重点放在25个主要编程语言的样本上。实际上是22个,因为我们没有关于Lisp、Kotlin和Cobol这三门语言的数据。</p> <h2><strong>量化</strong></h2> <p>你肯定会同意,GitHub的“Hello world”库并不真正算作是切换到另一种语言。因此,我们决定对数据集中的贡献值进行量化,以减少干扰。出于这个原因,我们在下面的小节中展示了GitHub每个字节大小的贡献的分布。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/1486d6858a3d412d3c2bf0ffec1fe33f.png"></p> <p>按大小分配GitHub贡献</p> <p>正如我们所看到的,它的尾巴很长,大部分的贡献都是很小的。为了近似分布,我们使用了 <a href="/misc/goto?guid=4959750728183188347" rel="nofollow,noindex">核密度估计</a> ,也就是图中的橙色曲线。最后,通过将曲线下的面积划分成10个相等的部分来得到量化。从0开始编号。</p> <p>在对数据集进行过滤和量化之后,我们可以继续构建自己的转移矩阵。</p> <h2><strong>最小费用流问题</strong></h2> <p>对于每一个GitHub用户,我们聚合年度的矢量;我们将称它们为反应器,其中每个393个元素代表着当年对应的语言编码的字节数。在规范化之后,这些反应堆就像直方图一样,我们需要相互比较。</p> <p>在PyEMD中提供了一种优雅的方法,在编码和计算时间上都是有效的,它提供了一个Python包装器,用于“ <a href="/misc/goto?guid=4959750728265354850" rel="nofollow,noindex">地球搬运工</a> ”的距离,它对“Numpy”友好。这个距离度量——比用于直方图比较的欧氏距离要好的多——特别有趣,因为它是基于 <a href="/misc/goto?guid=4959750728346235317" rel="nofollow,noindex">线性规划</a> (LP)。事实上,它可以被看作是以下 <a href="/misc/goto?guid=4959750728438834922" rel="nofollow,noindex">交通问题</a> 的解决方案,where</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/0bf1ee2416dcb85e5e995cfe4b60a5ca.png"></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/49e44304fb3909c512b0aa8d655e5e68.png"></p> <p>运输问题,供应和需求</p> <p>我们可以看到,每隔几年,字节数要么被看作是“供给”,要么是“需求”。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/98184e0600790f2bb80339a081f29f1b.png"></p> <p>让我们在这里稍微讲一下。首先,边的“成本”被设为1,以使我们无偏见。其次,为了减少我们的问题到经典的 <a href="/misc/goto?guid=4959750728525768431" rel="nofollow,noindex">流量最小化公式</a> ,我们必须在两部分图的两边加上一个人工的源和水槽,以确保流体的守恒。这不是一个临界点, <a href="/misc/goto?guid=4959750728605383264" rel="nofollow,noindex">斯坦福CS97SI</a> 的最后一张幻灯片描述了这个转变。</p> <h2><strong>转移矩阵</strong></h2> <p>以下是为特定的GitHub用户计算连续两年之间的转移矩阵的核心代码。我们使用的主要功能是emd_with_flow,它由PyEMD包提供。</p> <pre> <code class="language-python">def get_transition_matrix_emd(user, year): # lang2keep is the list of the 22 programming languages we kept # stairvalue() is the step function that comes from quantization # Build user's reactors for year and year+1 reactors = zeros((len(lang2keep),2), order='f') for ind, code_in_lang in enumerate(dataset[user]): lang = code_in_lang[0] if lang in lang2keep: for y, qtt_coded_year in code_in_lang[1]: if y == year: reactors[lang2keep.index(lang),0] = stairvalue(qtt_coded_year) elif y == year+1: reactors[lang2keep.index(lang),1] = stairvalue(qtt_coded_year) if (sum(reactors[:,0]) == 0) or (sum(reactors[:,1]) == 0): # no transition to consider P = zeros((len(lang2keep), len(lang2keep))) return P else: # Normalization of reactors for i in [0, 1]: reactors[:,i] = [j/sum(reactors[:,i]) for j in reactors[:,i]] # compute the Earth Mover's distance between the 2 reactors thanks to the emd_with_flow function distance = np.ones((len(lang2keep), len(lang2keep))) dist, P = emd_with_flow(reactors[:,0], reactors[:,1], distance) P = np.asarray(P) return P</code></pre> <p>使用Python计算转移矩阵的函数</p> <p>最后,在对用户和过去16年(我们将考虑每年的转移)的流矩阵求和之后,我们得到了最终的转移矩阵。现在让我们将它与埃里克根据Google查询编译的情形分析表进行比较。下面的图是使用埃里克的脚本绘制的。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/664b53af805c8d6ace19d3ddc109fec0.png"></p> <p>与埃里克的表相比,我们在转移矩阵的主对角线上有一些元素。稍后我们将看到如何利用这些元素。然而,尽管我们使用的数据集是不同的,但是我们还是注意到有很多的相似点,并且感知到相同的语言概要。与埃里克的表相比,我们在过渡矩阵的主对角线上有一些元素。稍后我们将看到如何利用它。然而,尽管我们使用的数据集是不同的,我们注意到许多相关的相似点。</p> <h2><strong>GitHub的“语言排行榜”</strong></h2> <p>既然我们有了流矩阵,我们就可以知道哪种语言是最受欢迎的,哪一种最不受欢迎。还可以在表示的图上计算中心度量,例如特征向量的中心。事实上,这些措施传达了语言的相对流行程度,在某种程度上也就是反应了人们使用一种语言编码然后会转换成另一种语言的可能性。我们将采用计算特征向量中心的方法。如果你需要进一步的解释,可以阅读Vadim在他的博客文章中关于 <a href="/misc/goto?guid=4959750728691228693" rel="nofollow,noindex">GitHub的贡献图表</a> 的PageRank分析。</p> <p><img src="https://simg.open-open.com/show/38a4481fbba8a774320ad9138049aafd.png"></p> <ul> <li>我们的流矩阵包含严格的正元素,这是使其 <a href="/misc/goto?guid=4959750728777071240" rel="nofollow,noindex">不可约</a> 的充分条件;总有一种方法可以从任何给定的语言中获得所有其他语言。因此,根据 <a href="/misc/goto?guid=4959750728856946127" rel="nofollow,noindex">perron-fro</a> 定理,我们正在寻找最伟大的特征值及其对应的特征向量。</li> <li>我们可以使用 <a href="/misc/goto?guid=4959750728945978227" rel="nofollow,noindex">幂次迭代</a> 算法来找到最主要的特征向量。然而,除了不可约外,矩阵还需要是随机的和非周期的。</li> <li>当移除主对角并使行规格化时,我们的流矩阵就变成了 <a href="/misc/goto?guid=4959750729030208667" rel="nofollow,noindex">随机的</a> 。最大的特征值现在等于1。</li> <li>最后,为了使我们的矩阵 <a href="/misc/goto?guid=4959648889128261944" rel="nofollow,noindex">不受周期</a> 和条件的限制,拉里和谢尔盖在1998年引入了一个著名的技巧。在 <a href="/misc/goto?guid=4959750729143942128" rel="nofollow,noindex">斯坦福的CS246</a> 中有很好的解释,但是为了缩短它,它主要包括用以下公式更新我们的流动矩阵:</li> </ul> <p>where,</p> <ul> <li>β被称为随机游走因子,被设为0.85</li> <li>N是语言的数量</li> </ul> <h2><strong>幂迭代</strong></h2> <p>在这些步骤之后,我们的良好条件流矩阵包含了在语言之间切换的可能性,我们可以继续进行幂次迭代。该算法由以下矩阵乘法组成,直到收敛到主特征向量:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/17e72ca0780693a83951b2f0b3e594ed.png"></p> <p>在下面的代码中,您将找到返回所需要的主导特征向量的代码。</p> <pre> <code class="language-python">def power_iteration(A, nb_iterations=100, beta=0.85): u = np.random.rand(len(lang2keep)) u = np.reshape(u, (len(lang2keep), 1)) A = A * beta + ((1 - beta) / len(lang2keep)) * np.ones((len(lang2keep), len(lang2keep))) for _ in range(nb_iterations): u_next = np.dot(A,u) u_next_norm = sum(u_next) u = u_next / u_next_norm return u power_iteration(transition_matrix)</code></pre> <p>幂迭代算法,Python。</p> <h2><strong>GitHub上面最受欢迎的开发语言</strong></h2> <p>终于!这是奖励:我们的 <a href="/misc/goto?guid=4959648889128261944" rel="nofollow,noindex">马尔可夫链</a> 的平稳分布。这个概率分布是独立于初始分布的。它给出了语言之间随机切换过程的稳定性的信息。因此,无论目前的语言有多流行,假设的未来静止状态不变。以下是我们在GitHub上使用的22种语言的流行度排名:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/2fcc4e256b66dfa4317b136d5503590e.png"></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/57697f44f57ea6924637e242e4a6c7d5.png"></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/c0882c280e9c45499ecdb8406ebca1d9.png"></p> <p>根据 <a href="/misc/goto?guid=4959750729237631081" rel="nofollow,noindex">centrality measure</a> 在GitHub上,语言的受欢迎程度</p> <p>Python(16.1%)似乎是最吸引人的语言,紧随其后的是Java(15.3%)。这尤其有趣,因为GitHub上只有11.3%的源代码是用Python编写的。</p> <p>在埃里克的排名中,Go是最大的赢家,16.4%。由于Erik基于Google查询的方法,似乎围绕Go的热门话题,让人们在博客中明确地表示,如果他们想要使用这种语言,那么就需要花一点时间来生成在GitHub上有效编写的项目。</p> <p>此外,C(9.2%)的表现与埃里克的14.3%的评分是一致的,尽管这是由于在GitHub上用C编码的项目数量。</p> <p>尽管在GitHub上的代码行数比Ruby多10倍,但它们的静态分布是相同的。</p> <p>Go(3.2%)出现在第9位,这在很大程度上是值得尊敬的,因为在GitHub上托管的项目中有一小部分(0.9%)。例如,相同比例的项目是用Perl编写的,但是这种语言并没有真正激起激情(2%的流行)。</p> <h2><strong>坚持使用一种语言</strong></h2> <p>如果我们在应用幂次迭代之前保留了转换矩阵的主对角线,我们得到的结果会略有不同。它主要减少了高级语言的流行,同时也提高了小语种的知名度。事实上,似乎有理由相信,那些把时间花在掌握其他语言的开发人员身上的开发人员,往往会坚持他们的观点,而不像那些受欢迎的人。</p> <p>在剩下的文章中,我们将考虑我们的第一个特征向量的表示。</p> <h2><strong>回到转移矩阵</strong></h2> <p>埃里克的转移矩阵是排序的,因此最流行的语言出现在底部。我们用同样的顺序来比较它们:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/48b45bedf4cbe29bbc48e839dd8d27f9.png"></p> <p>这是我们的矩阵,独立排序:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/a1ac92b78b3b06bd1a70515f1733bf5f.png"></p> <p>source{d}的有序转换矩阵,原始顺序</p> <ul> <li>在最流行的5种语言(Java、C、C++、PHP、Ruby)中编写代码的开发人员最有可能用approx切换到Python。平均22%的几率。</li> <li>此外,根据埃里克的矩阵,人们从Ojective-C转换到Swift和返回的可能性更大——24%和19%。</li> <li>类似地,一个Visual Basic开发人员有更多的机会(24%)转移到C#,而Erik在这个转换过程中几乎肯定会有92%的机会。</li> <li>最重要的是,Scala的用户更愿意使用Scala,分别是22、29和40%。</li> <li>使用数字和统计环境的人,如Fortran(36%),Matlab(33%)或R(40%)最可能转向Python,与Erik的矩阵相反,这是C语言的未来语言。</li> <li>我在埃里克的研究结果中发现了一个共同点,那就是Go吸引了那些放弃研究Rust的人。</li> </ul> <h2><strong>过去的16年</strong></h2> <p>正如我们前面提到的,在对转换矩阵进行求和之前,我们现在考虑特定的年份,并研究这些年矩阵是怎样的。他们是否表达相同的语言资料?自2000年初以来,它是如何演变的?以下是来自不同时间轴的4个矩阵的样本:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/d3e320189731451310c5da3f5334b69f.png"></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/46c64ea0fe9b406002bb580374726a3f.png"></p> <p style="text-align:center">转变矩阵的时间演化</p> <p>最后,随着时间的推移,这些矩阵的演化似乎是仿射的,我们每年都观察同一种语言。因此,为了突出这个语言概要文件的时间线,我们将幂迭代应用到每个矩阵。在过去的16年里,我们的平均分配是固定的,但是现在我们看它的时间顺序。在堆栈区域图中给出了一系列的主要特征向量的序列。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/c70602f270824b940f9ceec62f5dcdeb.png"></p> <p style="text-align:center">在过去的16年里,语言的平稳分布</p> <p>每个带的厚度对应于占主导特征向量的值。这些带按我们之前计算过的平均受欢迎程度排序。</p> <ul> <li>前两种语言,Python和Java具有相同的配置文件。他们已经取代C的位置已经15年了。事实上,前三层的聚合给出了一个直的。</li> <li>2008年,当Java或Ruby等语言开始快速增长时,C++的吸引力显著下降。然而,自这一时期以来,它一直保持着它的受欢迎程度。</li> <li>我绝对支持Erik的结论:Perl正在消亡。</li> <li>苹果在2014年的WWDC大会上展示了Swift,而该公司本应取代Obj-C。因此,在此事件之后,Obj-C的采用应该开始减少,但是这两种语言的总和应该保持不变。看看这个数字,这个假设是正确的。</li> <li>从2007年开始,Ruby似乎已经有了6年的荣耀。这也许可以用web框架Ruby on Rails(RoR)的发布来解释,当苹果宣布将在10月份发布Mac OS X v10.5“Leopard”时,它达到了一个里程碑。</li> <li>至于Go,它的受欢迎程度相对较低。然而,这一动态显然是积极的。</li> </ul> <h2><strong>变化</strong></h2> <p>在发表这篇文章后,我看见有的读者在语言冗长性方面有些偏见。任何事情都是公平的:全球量化方案可能会给像Java这样的冗长的语言带来优势,而比如像Haskell这样的浓缩的语言可能就没有。我分别对每种语言进行了量化,并重新运行了其余部分的分析。正如在下面的表格中所看到的,没有什么真正的变化;Ruby和C++交换了位置,但是它们的级别非常接近。最后看起来完全一样。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/af7a84b2365cb0cf83c70a0b625c3b56.png"></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/5edcf2ff7fa88d6a5649caba5ea88cb4.png"></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/46a27f73f7d6a9a188954fd7ffd8ca12.png"></p> <h2><strong>结论</strong></h2> <p>把埃里克的情形分析表看作是语言分布问题的二阶导数,而我们的流转换就像一阶导数一样,这更合适。也就是说,首先你先要google查询,然后试着编写一个OSS项目,最后导致了语言的分布变化。</p> <p> </p> <p>来自:http://www.iteye.com/news/32554</p> <p> </p>