GoogleNgram查看器是一个有趣且有用的工具,它使用Google从书籍中扫描的大量数据来映射单词使用情况随时间的变化。例如,单词Python(区分大小写):这张图表来自:books.google.com/ngrams…描述了单词“Python”随时间的使用情况。它由Google的n-gram数据集提供支持,该数据集记录了GoogleBooks在该书出版的每一年中特定单词或短语的使用情况。虽然这并不完整(它不包括曾经出版的每一本书!),但数据集中有数百万本书,涵盖从16世纪到2008年的时间段。可以从此处免费下载数据集。我决定使用Python和我的新数据加载库PyTubes,看看重新生成上面的图表有多么容易。challenge1-gram的数据集在硬盘上可以扩展到27Gb的数据,读入python是一个很大的数据量级。Python可以轻松地一次处理千兆字节的数据,但是当数据被破坏和处理时,它会很慢并且内存效率低下。总共,这14亿条记录(1,430,727,243)分布在38个源文件中,总计2400万(24,359,460)个单词(和词性标签,见下文),从1505年到2008年计算。处理1时速度很快亿行数据。并且原生Python并未针对处理这方面的数据进行优化。幸运的是,numpy非常擅长处理大量数据。使用一些简单的技巧,我们可以使用numpy使这种分析变得可行。在python/numpy中处理字符串很复杂。python中字符串的内存开销很大,而numpy只能处理已知且固定长度的字符串。基于此,大多数单词都有不同的长度,所以这并不理想。加载数据下面的所有代码/示例都在具有8GBRAM的2016MacbookPro上运行。如果硬件或云实例有更好的内存配置,性能会更好。1-gram数据以tab键划分的形式存储在文件中,如下所示:每条数据包含以下字段:为了按要求生成图表,我们只需要知道这些信息,即:通过提取这些信息,忽略了处理不同长度的字符串数据的额外消耗,但是我们仍然需要通过比较不同字符串的值来区分哪些行数据有我们感兴趣的字段。这个是pytubes可以做的:大约170秒(3分钟)后,one_grams是一个包含大约14亿行数据的numpy数组,看起来像这样(为说明添加表头):╒═══════════╤═══════╤══════════Is_Word│年│计数│╞═══════?═──│179│────────┼──────────┼────────────┤│0│1804│1│├──────────────┼──────────┼────────────┤│0│1805│1│├──────────────┼────────────┼────────────────┤│0│1811│1│├──────────────┼────────────┼──────────┤│0│1820│...│╘════════════════╧═════════╛从现在开始,这只是用numpy计算一些东西的问题:总计wordusageperyear谷歌显示了每个词出现的百分比(某个词在该年出现的次数/该年所有词出现的总次数),这比仅仅统计原始词更有用。要计算这个百分比,我们需要知道单词总数是多少。幸运的是,numpy使这变得非常简单:绘制此图以显示google每年收集了多少单词:很明显,在1800年之前,数据总数迅速下降,因此这会曲解最终结果,并将隐藏我们的模式有兴趣的。为了避免这个问题,我们只导入1800之后的数据:这会返回13亿行数据(只有1800之前数据的3.7%)每年的python百分比得到现在每年的python百分比非常简单的。使用一个简单的技巧,创建基于年份的数组,长度为2008个元素意味着每个年份的索引等于年份的数字,因此,例如1995只是获取1995的元素的问题。这些都不是值得用numpy做:绘制word_counts的结果:形状看起来类似于Google的版本,实际百分比不匹配,我认为这是因为下载的数据集,它以不同的方式包含单词(例如:Python_VERB).这个数据集在谷歌页面上没有得到很好的解释,并提出了几个问题:我们如何将Python用作动词?“Python”的计算总数是否包括“Python_VERB”?幸运的是,大家都知道我使用的方法产生了一个类似谷歌的图标,并且相关的趋势没有受到影响,所以对于这次探索,我并没有打算尝试修复它。性能Google在大约1秒内生成图像,与此脚本的8分钟相比,这也是合理的。Google单词计算的背景将从明显的准备好的数据集视图开始工作。例如,提前计算前一年的总单词使用量并将其存储在单独的查找表中可以节省大量时间。此外,将单词用法保存在单独的数据库/文件中,然后索引第一列几乎可以缩短所有处理时间。这种探索确实表明,使用带有标准商品硬件和Python的numpy和初出茅庐的pytubes,可以在合理的时间内从数十亿行的数据集中加载、处理和提取任意统计数据,语言大战用于稍微演示这个概念更复杂的例子,我决定比较提到的三种相关编程语言:Python、Pascal和Perl。源数据是嘈杂的(它包含所有使用的英文单词,而不仅仅是编程语言参考,例如,python也有非技术含义!),为了适应这一点,我们做了两件事:只匹配名称的大写形式(Python,不是python)每一种语言的总提及次数已转换为从1800年到1960年的百分比平均值,考虑到Pascal在1970年首次被提及,这应该给出一个合理的基线。结果:与谷歌(没有任何基线调整):运行时间:PyTubes在10多分钟后提升在这个阶段,pytubes只有单个整数的概念,即64位。这意味着pytubes生成的numpy数组对所有整数使用i8dtypes。在某些地方(如ngrams数据),8位整数是多余的并且浪费内存(总的ndarray是38Gb,dtypes可以轻松地将其减少60%)。我计划添加一些class1、2和4位整数支持(github.com/stestagg/py…)不)能力。在某些用例中,这可以更快地减少加载数据的大小。更好的字符串匹配-简单的测试,如:startswith、endswith、contains和is_one_of可以轻松添加,以显着提高加载字符串数据的效率。
