python十亿数据
使用pytubes,numpy和matplotlib
Google Ngram查看器是一个有趣/有用的工具,它使用Google从书本中扫描的大量数据来绘制一段时间内的单词使用情况。 以单词Python (区分大小写)为例:
它由Google的n-gram数据集提供动力,该数据集是每个出版年份Google 图书发现特定单词或单词序列的次数的日志。 虽然不完整(它不包括所有出版过的书!),但集合中有数百万本书,包括1500年代至2008年出版的书籍。可在此处免费下载数据集。
我决定看看使用Python和新的数据加载库PyTubes重现上面的图形有多么容易。
挑战性
1克数据集在磁盘上扩展到27 Gb,这是可读取到python中的相当大量的数据。 一次总算,Python可以轻松处理千兆字节的数据,但是一旦数据被解构和处理,事情就会变得很慢,内存效率也更低。
在1505年到2008年之间,总共有14亿行(1,430,727,243)分布在38个源文件中,总计2400万(24,359,460)个单词(以及带有POS标签的单词,请参见下文)。
当处理10亿行时,情况可能会很快变慢。 而且原生Python并未针对此类处理进行优化。 幸运的是, numpy在处理大量数字数据方面确实很棒。 通过一些简单的技巧,我们可以使用numpy使此分析可行。
在python / numpy中处理字符串很复杂。 python中字符串的内存开销非常可观,并且只有在字符串长度已知且固定的情况下,numpy才真正处理字符串。 在这种情况下,大多数单词具有不同的长度,因此并不理想。
加载数据
以下所有代码/示例均在具有8 GB内存的2016 Macbook Pro上运行。 具有相当数量的ram的硬件/云实例应该表现得更好
1克计数以一组制表符分隔的文件形式提供,如下所示:
Python 1587 4 2
Python 1621 1 1
Python 1651 2 2
Python 1659 1 1
每行具有以下字段:
1. Word
2. Year of Publication
3. Total number of times the word was seen
4. Total number of books containing the word
要生成所请求的图,我们只需要真正了解一些信息,即:
1. Is the word the one we’re interested in?
2. Year of publication
3. Total number of times the word was seen
通过仅提取这些信息,就避免了处理可变长度字符串数据的开销,但是我们仍然需要比较字符串值以标识哪些行与我们感兴趣的字段有关。这就是pytubes的来历:
大约170秒(3分钟)后, one_grams是一个具有约14亿行的numpy数组,看起来像这样(为清楚起见添加了标题):
╒═══════════╤════════╤═════════╕
│ Is_Word │ Year │ Count │
╞═══════════╪════════╪═════════╡
│ 0 │ 1799 │ 2 │
├───────────┼────────┼─────────┤
│ 0 │ 1804 │ 1 │
├───────────┼────────┼─────────┤
│ 0 │ 1805 │ 1 │
├───────────┼────────┼─────────┤
│ 0 │ 1811 │ 1 │
├───────────┼────────┼─────────┤
│ 0 │ 1820 │ ... │
╘═══════════╧════════╧═════════╛
从这里开始,这只是使用numpy方法计算一些事情的问题:
每年的总字数
Google会显示每个单词的出现百分比(一个单词出现的次数/当年发布的单词总数),这比原始单词计数要有用。 要计算此值,我们需要知道总字数是多少。
幸运的是,numpy使这一过程变得非常简单:
绘制此图可显示google每年收集了多少单词:
显而易见的是,在1800年之前,数据量会Swift下降,因此可能会使结果偏斜,并隐藏有趣的模式。 为了解决这个问题,我们只包含1800之后的数据:
返回13亿行(仅记录1800年之前的单词的3.7%)
Python年百分比
现在获取python的%计数非常容易。
使用使基于年的数组成为2008年元素的简单技巧,就意味着每年的索引等于年数,因此,查找1995年的条目只是获取第1,995个元素的问题。
为此甚至不值得使用numpy操作:
绘制结果word_counts:
结果在形状上与Google版本非常相似:
实际的百分比数字根本不匹配,我认为这是因为可下载的数据集包含带有各个词性标记的单词(例如:Python_VERB)。 对于此数据集,这在google页面中无法很好地解释,并引发了几个问题:
- 如何使用Python作为动词?
- “ Python”的计数是否包括“ Python_VERB”的计数? 等等
幸运的是,很明显,我使用的方法产生的图形与Google类似,足以影响相对趋势,因此对于本次探索,我将不尝试对其进行修复。
性能
Google在大约1秒钟内生成其图形,而使用此脚本大约需要8分钟,但这是合理的。 Google字数统计的后端将在数据集经过充分准备的视图下工作。
例如,预先计算每年的总字数并将其存储在单个查找表中将在此处节省大量时间。 同样,将单词计数存储在单个数据库/文件中并为第一列建立索引将消除几乎所有的处理时间。
但是,这项探索确实显示出,使用numpy和蓬松的pytube,可以在合理的时间内使用标准商品硬件和Python从原始的十亿行数据集中加载,处理和提取一些任意统计信息。
语言大战
为了用稍微复杂一点的示例来证明这一概念,我决定比较三种编程语言的相对提及率: Python,Pascal和Perl。
源数据非常嘈杂(它包括所有使用的英语单词,而不仅仅是编程语言的提法,例如,python也具有非技术意义!),试图对此进行调整,做了两件事:
- 仅名称的标题大小写形式匹配(Python,而不是python)
- 在1800年至1960年之间,每种语言的提及次数均已以平均百分比数变化。考虑到Pascal在1970年首次被提及,这应该提供一个合理的基准。
结果:
与Google相比( 未进行任何基准调整 ):
播放时间:刚超过10分钟
代码: https : //gist.github.com/stestagg/910859576f44f20e509822365414290d
未来的PyTubes改进
目前,pytubes仅具有一个整数概念,即64位int。 这意味着pytubes生成的numpy数组对所有整数都使用i8 dtypes。 在某些情况下(例如ngrams数据),8字节整数会有点过大,浪费内存(此处的完整ndarray约为38Gb,使用更好的dtypes可以很容易地减少60%)。 我计划很快添加一些级别的1、2和4字节整数支持( https://github.com/stestagg/pytubes/issues/9 )
更多过滤器逻辑— Tube.skip_unless()方法是过滤行的一种简单方法,但是缺乏组合条件(AND / OR / NOT)的任何能力。 在某些用例中,这将使减少加载数据的速度更快。
更好的字符串匹配-简单的测试(例如:startswith,endswith,contains和is_one_of)易于添加,并且在加载大量字符串数据时显着提高了实用性。
一如既往, 补丁 受到欢迎!
翻译自: https://hackernoon.com/analysing-1-4-billion-rows-with-python-6cec86ca9d73
python十亿数据