相似項發現(四)--LSH深入

    可以對所有的行條使用相同的哈希哈數,但是對每個行條我們需要使用一個獨立的桶數組(爲什麼要用獨立的桶呢?其實也能用一個桶,如使用x[ri][hvalue]<vector>=(c1,c2,c3,cn), ),如果檢測到r,c已經存在)。所以R/b個行條需要一個R/B X M', M'<=M(需要比較的文檔數)。

   使用獨立的桶是爲了後面可以將結果相交,或者相併

例如:

    12行的簽名矩陣,分成4個行條,每個行條由3行組成。圖中顯示可見的行條1中的第2,4列包含的列向量相同,因此他們肯定會被哈希到行條1下的相同桶中。因此,不管這兩列在其他3個行條下的結果如何,他們都是一個相似候選對。

    在行條1中不相等的兩個列仍然還有另外3次機會成爲候選對。行條化策略能夠使得相似列會比不相似列更有可能成爲候選對。

   按照如上描述,採用不同的上面的策略可以修改上文代碼:

1. 修改getCandidate.需要包含vector和algorithm頭文件

//used to get candidate
const int B=2;
//setN is bucket index
vector<int> candidate[B][15];
vector<int> RL[setN];
//candidate[B][15],RL 需要採用可以採用堆棧結構進行排序,每次取最小值
int getSmallest(vector<int>& v)
{
	vector<int>::iterator ite=v.begin();
	int smallest = *ite;
	for(; ite!=v.end();ite++)
	{
		if(*ite<smallest)
			smallest = *ite;
	}
	v.erase(remove(v.begin(),v.end(),smallest));

	return smallest;
}
bool isExist(vector<int>& v, int n)
{
	vector<int>::iterator ite=v.begin();
	for(; ite!=v.end();ite++)
	{
		if(*ite == n)
			return true;
	}
	return false;

}
void getCandidate(int R)//get candidate for LSH
{
	int row = 0;
	if(R%B != 0)
	{
		return;
	}
	row = R/B;

	for(int i=0;i<B;i++)
	{
		for(int m=0;m<setN;m++)
		{
			int bucket_index=0;
			for(int r =2*i;r<(R/B+2*i);r++)//row(0,R/B=2),then 2,4, from 2*i, to R/B+2*i
			{
				bucket_index += h1(SIG[r][m]-1);
			}
			candidate[i][bucket_index].push_back(m);
		}
		for(int m=0;m<15;m++)
		{
			if(candidate[i][m].size()>1)
			{
				int smallest = getSmallest(candidate[i][m]);
				vector<int>::iterator ite = candidate[i][m].begin();
				for(;ite!= candidate[i][m].end();ite++)
				{
					if(!isExist(RL[smallest],*ite))
					//get smalleset
					RL[smallest].push_back(*ite);
				}

			}
		}
	}
}

2.  flag=true和false分別反映了採用行條化策略和不採用行條化策略的計算。

/used to get SIM
template<int C,int map[][C]>
void countForSIM(int R, bool flag=false)//flag used to control if it will use the LSH
{
	reset(x);
	reset(xpy);
	for(int r=0;r<R;r++)
	{
		for(int m = 0;m<C;m++)
		{
			if(flag==true)
			{
				if(RL[m].size()==0)
				{
					continue;
				}
				vector<int>::iterator ite = RL[m].begin();
				int j=*ite;
				for(;ite!= RL[m].end(); ite++)
				{
					if(map[r][m]==1 && map[r][j]==1)
					{
						x[m][j]++;
						xpy[m][j]++;
					}
					else if(map[r][m]==1 || map[r][j]==1)
					{
						xpy[m][j]++;
					}
					if(ite!=RL[m].end())
					{
						j=*ite;
					}
				}				
			}
			else
			{
				for(int j=m+1;j<C;j++)
				{
					if(map[r][m]==1 && map[r][j]==1)
					{
						x[m][j]++;
						xpy[m][j]++;
					}
					else if(map[r][m]==1 || map[r][j]==1)
					{
						xpy[m][j]++;
					}
				}
			}
		}
	}
}

3. 測試代碼如下:

int main()
{
	cout<<"original set................................."<<endl;
	printM<setN,matrix>(5);
	initSIG();
	//printM<setN,SIG>(2);
	inithash();
	minHash(setN,4,5);
	cout<<"hash signature set..........................."<<endl;
	printM<setN,SIG>(4);

    countForSIM<setN,matrix>(5);
	getSIM1();
	cout<<"SIM1........................................."<<endl;
	printMd<setN,SIM1>(setN);

    getCandidate(4);
	//cout<<"candidate........................................."<<endl;
	//printM<setN,candidate>(2);
    //cout<<"RL........................................."<<endl;
	//printM<setN,RL>(setN);

	countForSIM<setN,SIG>(4,true);
	getSIM2();
	cout<<"SIM2........................................."<<endl;
	printMd<setN,SIM2>(setN);

	system("pause");
}


    如果針對原來的SIM矩陣分析,那麼閥值 = (1/2)^(1/2)==0.707, 即最後計算出的SIM是相似性超過70%的。

4.2 行條化策略的分析

    假定使用b個行條,每個行條由r行組成,並假定某對具體文檔之間的Jaccard相似度爲s。所以具體某行中兩個簽名相等的概率爲S。

    1. 在某個具體的行條中所有行的兩個簽名相等的概率是s^r。

    2. 在某個具體行條中至少有一對簽名不相等的概率是1-s^r

    3.在任何行條中任意一行的簽名對都不相等的概率=每個行條中都至少有一對簽名不相等=(1-s^r)^b

    4.簽名至少在一個行條中全部相等的概率,也即成爲候選對的概率爲1- (1-s^r)^b

    不論常數b,r的取值如何,函數1-(1-s^r)^b的圖像爲S-曲線(S-curve)。曲線中候選概率1/2處對應的相似度就是所謂的閥值(threshold),他是b和r的函數,近視估計爲

(1/b)^(1/r)。

這個LSH技術是一個具體函數族(最小哈希函數族)上的應用例子,這些函數可以組合在一起,如這裏的行條化技術來更有效的區分低距離和高距離的對。S-曲線的陡度能夠反映從候選對中避免僞正例和僞反例的有效程度。

五、擴展局部敏感函數理論

    這裏探討的是除了最小哈希函數之外的其他函數族,他們也同樣能夠非常高效的產生候選對。他們能夠作用於集合空間/Jaccard距離,或者其他類型的空間和距離測度。對於這些函數族來說,需要滿足如下的3個條件。

    1. 必須更可能選擇近距離對而不是遠距離對作爲候選對

    2. 函數之間必須在統計上相互獨立,在這個意義上講,兩個或者多個函數的聯合概率等於每個函數上獨立事件的概率乘積。

   3. 必須在以下兩個方面擁有很高的效率。

      a) 必須在短時間內識別候選對,該時間遠低於掃描所有對所花費的時間。(最小哈希函數就具有這個能力,它將集合映射爲最小哈希值的時間與數據的規模成正比,而不是與數據集合數目的平方成正比)。由於具有公共值的集合會映射到同一個桶中,因此單個哈希函數產生候選對的時間遠遠低於集合對的數目。

     b) 必須組合在一起可以更好的避免僞正例和僞反例,組合後函數所花費的時間也必須遠低於對的數目。

 

比如行條化技術可以組合一系列的單個哈希函數,每個哈希函數滿足條件3(a),但是其本身並不符合我們所期望的S-曲線的性質,但是通過組合這些最小哈希函數,我們卻可以得到S-曲線。

5.1 局部敏感函數

    函數f會對兩個輸入項求哈希值,最後判定兩個值是否相等。如果f(x)=f(y),來判定“x與y是候選項”,f(x)≠f(y),在沒有其他函數來判定x,y時,可以判定他們不是候選對。這種形式的一系列函數集合構成了函數族(function family)。例如在哈希函數族中的每個函數都基於特徵矩陣的一個可能的行排列轉換而形成,各個行條即使採用一樣的哈希函數,這個哈希函數族只包括一個哈希函數,可以讓不同行條採用不同的哈希函數,這個哈希函數族便包含b個函數

    令d1<d2是定義在某個距離測度d下的兩個距離值。如果一個函數族F中的每一個函數f都滿足下列條件,則稱其爲(d1,d2,p1,p2)敏感函數族:

    1. 如果d(x,y)≤d1, 那麼f(x)=f(y)的概率至少是p1;

    2.如果d(x,y)≥d1, 那麼f(x)=f(y)的概率最大是p2;

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章