相似查找系列 海量数据相似查找系列 -- Annoy算法 特征向量相似度和距离的计算 Jaccard(杰卡德)相似性系数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/teleger/article/details/80853634
1.A

海量数据相似查找系列 -- Annoy算法

点击打开链接 Annoy

    1  .建立索引过程

Annoy的目标是建立一个数据结构,使得查询一个点的最近邻点的时间复杂度是次线性。Annoy 通过建立一个二叉树来使得每个点查找时间复杂度是O(log n)。 看下面这个图, 随机选择两个点,以这两个节点为初始中心节点,执行聚类数为2的kmeans过程,最终产生收敛后两个聚类中心点。这两个聚类中心点之间连一条线段(灰色短线),建立一条垂直于这条灰线,并且通过灰线中心点的线(黑色粗线)。这条黑色粗线把数据空间分成两部分。在多维空间的话,这条黑色粗线可以看成等距垂直超平面.
在划分的子空间内进行不停的递归迭代继续划分,知道每个子空间最多只剩下K个数据节点。
   2. 查询过程

上面已完成节点索引建立过程。如何进行对一个数据点进行查找相似节点集合呢?比如下。这个图的红色节点。 查找的过程就是不断看他在分割超平面的哪一边。从二叉树索引结构来看,就是从根节点不停的往叶子节点遍历的过程。通过对二叉树每个中间节点(分割超平面相关信息)和查询数据节点进行相关计算来确定二叉树遍历过程是往这个中间节点左孩子节点走还是右孩子节点走。通过以上方式完成查询过程。
3 返回最终近邻节点

每棵树都返回一堆近邻点后,如何得到最终的Top N相似集合呢?
首先所有树返回近邻点都插入到优先队列中,求并集去重, 然后计算和查询点距离, 最终根据距离值从近距离到远距离排序, 返回Top N近邻节点集合。

参考文献

[1]:https://www.slideshare.net/erikbern/approximate-nearest-neighbor-methods-and-vector-models-nyc-ml-meetup

[2]:https://github.com/spotify/annoy

[3]:https://erikbern.com/2015/10/01/nearest-neighbors-and-vector-models-part-2-how-to-search-in-high-dimensional-spaces.html


2 A  ---

特征向量相似度和距离的计算

https://blog.csdn.net/mjcheng8879/article/details/49404359

#include <iostream>
#include <vector>
#include <cassert>
#include <cmath>


using namespace std;

double dotProduct(const vector<double>& v1, const vector<double>& v2)
{
	assert(v1.size() == v2.size());
	double ret = 0.0;
	for (vector<double>::size_type i = 0; i != v1.size(); i++)
	{
		ret += v1[i] * v2[i];
	}
	return ret;
}

double module(const vector<double>& v)
{
	double ret = 0.0;
	for (vector<double>::size_type i = 0; i != v.size(); i++)
	{
		ret += v[i] * v[i];
	}
	return sqrt(ret);
}


double cosine(const vector<double>& v1, const vector<double>& v2)
{
	assert(v1.size() == v2.size());
	return dotProduct(v1, v2) / (module(v1) * module(v2));
}


double mean(const vector<double>& v)
{
	assert(v.size() != 0);
	double ret = 0.0;
	for (vector<double>::size_type i = 0; i != v.size(); ++i)
	{
		ret += v[i];
	}
	return ret / v.size();
}

double cov(const vector<double>& v1, const vector<double>& v2)
{
	assert(v1.size() == v2.size() && v1.size() > 1);
	double ret = 0.0;
	double v1a = mean(v1), v2a = mean(v2);

	for (vector<double>::size_type i = 0; i != v1.size(); ++i)
	{
		ret += (v1[i] - v1a) * (v2[i] - v2a);
	}

	return ret / (v1.size() - 1);
}

// 相关系数
double coefficient(const vector<double>& v1, const vector<double>& v2)
{
	assert(v1.size() == v2.size());
	return cov(v1, v2) / sqrt(cov(v1, v1) * cov(v2, v2));
}

// Dice 系数
double dice(const vector<double>& v1, const vector<double>& v2)
{
	assert(v1.size() == v2.size());
	return 2.0 * dotProduct(v1, v2) / (dotProduct(v1, v1) + dotProduct(v2, v2));
}

// Jaccard 系数
double jaccard(const vector<double>& v1, const vector<double>& v2)
{
	assert(v1.size() == v2.size());
	return dotProduct(v1, v2) / (dotProduct(v1, v1) + dotProduct(v2, v2) - dotProduct(v1, v2));
}

// Minkowsky 距离
double minkowsky(const vector<double>& v1, const vector<double>& v2, double m)
{
	assert(v1.size() == v2.size());
	double ret = 0.0;
	for (vector<double>::size_type i = 0; i != v1.size(); ++i)
	{
		ret += pow(abs(v1[i] - v2[i]), m);
	}
	return pow(ret, 1.0 / m);
}

// Euclidean 距离
double euclidean(const vector<double>& v1, const vector<double>& v2)
{
	assert(v1.size() == v2.size());
	return minkowsky(v1, v2, 2.0);
}
 
	 // Manhattan 距离
double manhattan(const vector<double>& v1, const vector<double>& v2)
{
	assert(v1.size() == v2.size());
	return minkowsky(v1, v2, 1.0);
}

// Jffreys & Matusita 距离
double jffreysMatusita(const vector<double>& v1, const vector<double>& v2)
{
	assert(v1.size() == v2.size());
	double ret = 0.0;
	for (vector<double>::size_type i = 0; i != v1.size(); ++i)
	{
		ret += (sqrt(v1[i]) - sqrt(v2[i])) * (sqrt(v1[i]) - sqrt(v2[i]));
	}
	return sqrt(ret);
}
 
 // Camberra 距离(Lance 距离,Williams 距离)
double camberra(const vector<double>& v1, const vector<double>& v2)
{
	assert(v1.size() == v2.size());
	double ret = 0.0;
	for (vector<double>::size_type i = 0; i != v1.size(); ++i)
	{
		ret += abs(v1[i] - v2[i]) / abs(v1[i] + v2[i]);
	}
	return ret;
}
int main()
{
	float a[] = {1, 2, 3, 4, 5};
	float b[] = {4, 3, 2, 1, 0};
	vector<double> v1(a, a + sizeof (a) / sizeof (*a)), v2(b, b + sizeof (b) / sizeof (*b));
	
	cout << "cosine = "<<cosine(v1, v2) << endl;
 	cout << "coefficient = "<<coefficient(v1, v2) << endl;
 	cout << "dice = "<<dice(v1, v2) << endl;
 	cout << "jaccard = "<<jaccard(v1, v2) << endl;
// 
 	cout << "minkowsky = "<<minkowsky(v1, v2, 5.0) << endl;
 	cout << "euclidean = "<<euclidean(v1, v2) << endl;
 	cout << "manhattan = "<<manhattan(v1, v2) << endl;
 	cout << "jffreysMatusita = "<<jffreysMatusita(v1, v2) << endl;

 	cout << "camberra = "<<camberra(v1, v2) << endl;

	return 0;
}
3  A  

Jaccard(杰卡德)相似性系数

Jaccard(杰卡德)相似性系数主要用于计算符号度量或布尔值度量的样本间的相似度。若样本间的特征属性由符号和布尔值标识,无法衡量差异具体值的大小,只能获得“是否相同这样一种结果,而Jaccard系数关心的是样本间共同具有的特征。

Jaccard系数等于样本集交集个数和样本集并集个数的比值,用表示

Jaccard系数相反的概念是Jaccard距离,用两个集合中不同元素所占元素的比例来衡量两个集合(样本)的区分度,可用如下公式表示:



Jaccard系数主要的应用的场景有: 


  1. 过滤相似度很高的新闻,或者网页去重

  2. 考试防作弊系统

  3. 论文查重系统


原文出处 : https://blog.csdn.net/BANANAML/article/details/52894295

猜你喜欢

转载自blog.csdn.net/teleger/article/details/80853634
今日推荐