K最邻近算法和局部敏感哈希LSH
2015-06-29 16:31
134 查看
1. K最近邻(k-Nearest Neighbor)分类算法
采用测量不同特征值之间的距离方法进行分类。K近邻分类算法的主要思想:
如果一个样本在特征空间中的k个最相似)的样本中的大多数属于某一个类别,则该样本也属于这个类别(这里对于最相似的判定主要是通过特征值向量的距离)
1.1. 算法特点及伪代码
KNN算法中,所选择的邻居都是已经正确分类的对象(训练集)KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数
伪代码描述
12345 | 1. 计算已知类别数据集中的点与当前点之间的距离2. 按照距离递增次序排序3. 选取与当前点距离最小的k个点4. 确定前k个点所在类别的出现频率5.返回前k个点出现频率最高的类别作为当前点的预测分类 |
1.2. Python实现
这篇博文写的有些匆忙, 如果以后有时间的话, 我会进行重新整理特征抽取, 对于每个类别的文本进行特征抽取, 获取特征词集合, 用于匹配测试文本, 生成特征向量
12345678910111213 | def extract_feature() : text = "" post_set = []; class_set = []; feature = [] jieba.analyse.set_stop_words("stop_word.txt") for index in range(len(dict_list)) : with open("./lily/" + dict_list[index] + ".txt", "r") as my_file : #读入每个板块所有的帖子 for post in my_file : post_set.append(list(jieba.cut(post, cut_all = False))) #将post字符串存入list class_set.append(index) text += post feature.extend(jieba.analyse.extract_tags(text, 100)) return feature, post_set, class_set |
12345678910111213141516 | def createQuery(post_set, feature) : query_set = [] vec_size = len(feature) for post in post_set : vector = [0] * vec_size for word in post : if word in feature : vector[feature.index(word)] += 1 query_set.append(vector) return query_setdef makeVector(post, feature, size) : vector = [0] * size for word in post : if word in feature : vector[feature.index(word)] += 1 return vector |
1234567891011121314 | def knnClassify(vecX, query_set, class_set, k) : query_set = array(query_set) query_set_size = query_set.shape[0] mid_mat = tile(vecX, (query_set_size, 1)) - query_set sqrt_two = mid_mat ** 2 sqrt_distances = sqrt_two.sum(axis = 1) distances = sqrt_distances ** 0.5 sorted_dist = distances.argsort() class_count = {} for i in range(k) : label = class_set[sorted_dist[i]] class_count[label] = class_count.get(label, 0) + 1 sort_class_count = sorted(class_count.iteritems(), key = operator.itemgetter(1), reverse = True) return sort_class_count[0][0] |
距离搜索的缺陷: 当训练文本过大时, 需要用测试文本与每个训练文本计算欧式距离, 导致计算时间过长,
2.局部敏感哈希
LSH的基本思想是:将原始数据空间中的两个相邻数据点通过相同的映射或投影变换(projection)后,这两个数据点在新的数据空间中仍然相邻的概率很大,而不相邻的数据点被映射到同一个桶的概率很小
哈希桶(HashBucket):哈希表中同一个位置可能存有多个元素,以应对哈希冲突问题,这样,哈希表中的每个位置表示一个哈希桶。
2.1. LSH的具体描述
如果我们对原始数据进行一些hash映射后,我们希望原先相邻的两个数据能够被hash到相同的桶内,具有相同的桶号。对原始数据集合中所有的数据都进行hash映射后,我们就得到了一个hash table,这些原始数据集被分散到了hash table的桶内,每个桶会落入一些原始数据,属于同一个桶内的数据就有很大可能是相邻的,当然也存在不相邻的数据被hash到了同一个桶内。因此,如果我们能够找到这样一些hash functions,使得经过它们的哈希映射变换后,原始空间中相邻的数据落入相同的桶内的话,那么我们在该数据集合中进行近邻查找就变得容易了,我们只需要将查询数据进行哈希映射得到其桶号,然后取出该桶号对应桶内的所有数据,再进行线性匹配即可查找到与查询数据相邻的数据。LSH将一个在超大集合内查找相邻元素的问题转化为了在一个很小的集合内查找相邻元素的问题,显然计算量下降了很多
123456 | hash function需要满足以下两个条件:1)如果d(x,y) ≤ d1, 则h(x) = h(y)的概率至少为p1;2)如果d(x,y) ≥ d2, 则h(x) = h(y)的概率至多为p2;其中d(x,y)表示x和y之间的距离,d1 < d2, h(x)和h(y)分别表示对x和y进行hash变换。满足以上两个条件的hash functions称为(d1,d2,p1,p2)-sensitive。而通过一个或多个(d1,d2,p1,p2)-sensitive的hash function对原始数据集合进行hashing生成一个或多个hash table的过程称为Locality-sensitive Hashing。 |
LSH算法可以看做两步:
将与测试文本完全不相关的向量剔除掉(
哈希函数映射过程),只保留与测试文本相似的概率较大的向量作为待比较向量(
哈希表中希望产生冲突, 使类似的文本能够映射到同一个桶里)
讲测试文本向量与剩余向量逐一对比, 找到前k个临近的向量
2.Python实现
使用 Cosine distanceCosine distance:cos(theta) = A·B / |A||B|
常用来判断两个向量之间的夹角,夹角越小,表示它们越相似
12345678910111213141516171819202122232425 | //Cosine distance的计算#计算向量的模def magnitudeProd(vec1, vec2) : total1 = 0 total2 = 0 for i in xrange(dimension) : val1 = vec1[i] val2 = vec2[i] total1 += val1**2 total2 += val2**2 return (total1 * total2)**0.5#计算两个向量之间的夹角, 看是否在一个角度范围内def cosineDistance(vec1, vec2) : mag_prod = magnitudeProd(vec1, vec2) if mag_prod == 0 : return 0 return dotProduct(vec1, vec2) / magnitudeProd(vec1, vec2)#计算两个向量的内积def dotProduct(vec1, vec2) : total = 0 for i in xrange(len(vec1)) : total += vec1[i] * vec2[i] return total |
12345678 | def localitySensitiveHash(vec, planes) : dot_prod_list = [dotProduct(vec, plane) for plane in planes] return (sum([2 ** i if dot_prod_list[i] > 0 else 0 for i in xrange(0, len(dot_prod_list))]) % 8)hash_table = [(localitySensitiveHash(row, planes), class_set[class_index]) for class_index, row in enumerate(train_set)]hash_dict = defaultdict(list)for (hash_value, class_index) in hash_table : hash_dict[hash_value].append(class_index) |
相关文章推荐
- [华为机试练习题]12.整型字符串排序
- json学习系列(3)-JSONObject的过滤设置
- Kerberos ticket lifetime及其它
- UNP 环境配置
- php基础教程-输出Hello World
- 链表的游标实现
- linux core文件GDB调试方法
- 桥接模式多维思想
- nginx 中禁止爬虫
- 不要轻易在数据库(尤其是线上数据库)执行,update、delete数据 !!!
- 如何成为一名优秀的web前端工程师(前端攻城师)?
- CentOS7 防火墙配置(关闭)
- PHPthinking邀请您一起赚Money
- Ajax两张表单一起上传
- Ubuntu PPA软件源的介绍与使用
- maven实战
- 简单数据结构之二叉树(C++实现)
- 解决spring+c3p0数据库连接一直增加的问题
- java基础-多线程
- Dubbo+Zookeeper