Hash概述
基本原理
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
数组特点:寻址容易,插入和删除困难;链表特点:寻址困难,插入和删除容易;综合两者的特性的数据结构,就是哈希表。
拉链法实现:
左边是个数组,数组的每个成员包括一个指针,指向一个链表的头,链表可能为空,也可能元素很多。根据元素的一些特征把元素分配到不同的链表中去,也是根据这些特征,找到正确的链表,再从链表中找出这个元素。
要点是hash函数选择,针对字符串,整数,排列,具体相应的hash方法。
Hash应用
加密算法
它把一些不同长度的信息转化成杂乱的128位的编码,这些编码值叫做Hash值. 也可以说,Hash就是找到一种数据内容和数据存放地址之间的映射关系。
查找
我们之前的查找,都是:集合中拿出来一个元素,看看是否与我们要找的相等,如果不等,缩小范围,继续查找。而哈希表是完全另外一种思路:当我知道key值以后,我就可以直接计算出这个元素在集合中的位置,根本不需要一次又一次的查找!
举例,假如数组A中,第i个元素里面装的key就是i,那么数字3肯定是在第3个位置,数字10肯定是在第10个位置。哈希表就是利用利用这种基本的思想,建立一个从key到位置的函数,然后进行直接计算查找。
海量数据处理
Hash Table的查询速度非常的快,几乎是O(1)的时间复杂度。
散列法:元素特征转变为数组下标的方法。
散列冲突
不同的关键字经过散列函数的计算得到了相同的散列地址。
一种是open hashing,也称为拉链法;另一种就是closed hashing,也称开地址法,opened addressing。
建立缓冲区
把重复的放进去。当发现找的不对,就在缓冲区里找。
再探测
就是在其他地方查找。探测的方法也可以有:
1.在找到查找位置的index的index-1,index+1位置查找,index-2,index+2查找,依次类推。这种方法称为线性再探测。
2.在查找位置index周围随机的查找。称为随机在探测。
3.再哈希,就是当冲突时,采用另外一种映射方式来查找。
如果不需要有序遍历数据,并且可以提前预测数据量的大小。那么哈希表在速度和易用性方面是无与伦比的。
Hash-trick
在大规模的文本处理中,由于特征的维度对应分词词汇表的大小,所以维度可能非常恐怖需要降维,而最常用的文本降维方法是Hash Trick。
定义一个特征Hash后对应的哈希表的大小,具体的方法是,对应任意一个特征名,我们会用Hash函数找到对应哈希表的位置,然后将该特征名对应的词频统计值累加到该哈希表位置。
哈希后的特征是否能够很好的代表哈希前的特征呢?从实际应用中说,由于文本特征的高稀疏性,这么做是可行的。
在scikit-learn的HashingVectorizer类中,实现了基于signed hash trick的算法,演示将m维词汇表corpus,哈希降维到6维。
from sklearn.feature_extraction.text import HashingVectorizer
vectorizer=HashingVectorizer(n_features = 6,norm = None)
print vectorizer.fit_transform(corpus)
top K问题
分治+Trie树/hash+小顶堆
先将数据集按照Hash方法分解成多个小数据集,然后使用Trie树或着Hash统计每个小数据集中的query词频,之后用小顶堆求出每个数据集中出现频率最高的前K个数,最后在所有top K中求出最终的top K。
如果这1亿个数里面有很多重复,先通过Hash法去重,会减少很大的内存用量。
top K问题很适合采用MapReduce框架解决,用户只需编写一个Map函数和两个Reduce 函数,然后提交到Hadoop(采用Mapchain和Reducechain)上即可解决该问题。
具体而言,就是首先根据数据值或者把数据hash(MD5)后的值按照范围划分到不同的机器上,最好可以让数据划分后一次读入内存,这样不同的机器负责处理不同的数值范围,实际上就是Map。
得到结果后,各个机器只需拿出各自出现次数最多的前N个数据,然后汇总,选出所有的数据中出现次数最多的前N个数据,这实际上就是Reduce过程。
对于Map函数,采用Hash算法,将Hash值相同的数据交给同一个Reduce task;对于第一个Reduce函数,采用HashMap统计出每个词出现的频率,对于第二个Reduce 函数,统计所有Reduce task,输出数据中的top K即可。