C++でJaccard係数

順位がついたリストでできた行列(行ごとにそれぞれランクがついているもの)から上位20番目(#define TOPKで変えれる)までに含まれる集合同士のJaccard係数を求めるプログラム。
入力形式は最初の全てスペースか改行区切りで最初の最初の二つが行と列であとは要素を並べた行列を与える。
例えば
\left( \begin{array}{ccc} 1\ 2\ 3\\ 2\ 3\ 1\\ \end{array} \right)
なら
3 2
1 2 3
2 3 1
とする。
出力はx行目とy行目のJaccard係数をJ(x,y)とすると
J(1,2) J(1,3) J(1,4)…
J(2,3) J(2,4) J(2,5)…

となる。

// Jaccard係数を求めるプログラム。
#include <stack>
#include <iostream>
#define TOPK 20
using namespace std;
 
void search_topk(int, int);
void change_topk(double[], double);
 
int main(){
  int i,j;
  cin >> i >> j;
  search_topk(i,j);
}
 
void search_topk(int i, int j){
  double rank[i];
  double topk[TOPK];
  stack<int> st[j];
  int all[j];   // topk以上の数を保持する配列
 
  for(int k=0; k<j; k++){
    for(int l=0; l<TOPK; l++){
      topk[l] = 0;
    }
    for(int l=0; l<i; l++){
      cin >> rank[l];
      change_topk(topk,rank[l]);
    }
    int no = 0;   // topk以上の数
    for(int l=0; l<i; l++){
      if(rank[l] > topk[TOPK-1]){
	no++;
	st[k].push(l);
      }
    }
    all[k] = no;
  }
  int compare[j][j];
  for(int k=0; k<j; k++){
    for(int l=0; l<j; l++){
      compare[k][l] = 0;
    }
  }
  // 比較する
  for(int k=0; k<j-1; k++){
    for (int l=k+1; l<j; l++){
      stack<int> st1,st2;
      st1 = st[k];
      st2 = st[l];
      while(!(st1.empty()) && !(st2.empty())){
	if(st1.top() == st2.top()){
	  compare[k][l]++;
	  st1.pop();
	  st2.pop();
	}else if(st1.top() > st2.top()){
	  st1.pop();
	}else{
	  st2.pop();
	}
      }
    }
  }
 
  // 結果の表示
  for(int k=0; k<j-1; k++){
    for (int l=k+1; l<j; l++){
      cout << 1.0*compare[k][l]/(all[k] + all[l] - compare[k][l]) << " ";
    }
    cout << endl;
  }
}
 
void change_topk(double topk[], double r){   // topkを入れ替える関数
  int rank=0;
  for(int i=TOPK-1; 0<=i; i--){
    if(topk[i] > r){
      rank = i+1;
      break;
    }
  }
  if(rank != TOPK){
    int tmp, tmp2;
    tmp = topk[rank];
    topk[rank] = r;
    for(int i=rank+1; i<TOPK; i++){
      tmp2 = topk[i];
      topk[i] = tmp;
      tmp = tmp2;
    }
  }
}
 


ほとんど同じだが、PPM形式でJaccard係数を出力するもの。

// Jaccard係数を求めるプログラム。
// ついでにPPM形式で出力
#include <stack>
#include <iostream>
#define TOPK 40
using namespace std;
 
void search_topk(int, int);
void change_topk(double[], double);
 
int main(){
  int i,j;
  cin >> i >> j;
  search_topk(i,j);
}
 
void search_topk(int i, int j){
  double rank[i];
  double topk[TOPK];
  stack<int> st[j];
  int all[j];   // topk以上の数を保持する配列
 
  for(int k=0; k<j; k++){
    for(int l=0; l<TOPK; l++){
      topk[l] = 0;
    }
    for(int l=0; l<i; l++){
      cin >> rank[l];
      change_topk(topk,rank[l]);
    }
    int no = 0;   // topk以上の数
    for(int l=0; l<i; l++){
      if(rank[l] > topk[TOPK-1]){
	no++;
	st[k].push(l);
      }
    }
    all[k] = no;
    //    print_topk(topk);
    //    cout << no << endl;
  }
  int compare[j][j];
  for(int k=0; k<j; k++){
    for(int l=0; l<j; l++){
      if(k==l){
	compare[k][l] = all[k];
      }else{
	compare[k][l] = 0;
      }
    }
  }
  // 比較する
  for(int k=0; k<j-1; k++){
    for (int l=k+1; l<j; l++){
      stack<int> st1,st2;
      st1 = st[k];
      st2 = st[l];
      while(!(st1.empty()) && !(st2.empty())){
	if(st1.top() == st2.top()){
	  compare[k][l]++;
	  compare[l][k]++;
	  st1.pop();
	  st2.pop();
	}else if(st1.top() > st2.top()){
	  st1.pop();
	}else{
	  st2.pop();
	}
      }
    }
  }
 
  // 結果の表示
  cout << "P3" << endl;
  cout << j << " " << j << endl;
  cout << 255 << endl;
  for(int k=0; k<j; k++){
    for (int l=0; l<j; l++){
      cout << (int)(255.0*compare[k][l]/(all[k] + all[l] - compare[k][l])) << " " << 0 << " " << 0 << endl;
    }
  }
}
 
void change_topk(double topk[], double r){   // topkを入れ替える関数
  int rank=0;
  for(int i=TOPK-1; 0<=i; i--){
    if(topk[i] > r){
      rank = i+1;
      break;
    }
  }
  if(rank != TOPK){
    int tmp, tmp2;
    tmp = topk[rank];
    topk[rank] = r;
    for(int i=rank+1; i<TOPK; i++){
      tmp2 = topk[i];
      topk[i] = tmp;
      tmp = tmp2;
    }
  }
}
 
最終更新:2009年11月25日 19:28
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。