페이지

2014. 11. 11.

[IR] 벡터 모델 검색





#include <iostream>
#include <string> // 문자열 사용
#include <math.h> // 산수
#include <algorithm>         // 정렬
#include <functional>          // greater 사용 위해 필요
#include <fstream> // 결과를 파일에 저장
#include <time.h>

using namespace std;

#define NUMBER_OF_DOCS 10
#define NUMBER_OF_KEYWORDS 10

int freq[NUMBER_OF_KEYWORDS][NUMBER_OF_DOCS] =  {{0,1,0,0,0,2,0,3,1,0},
{0,3,0,8,1,0,0,0,0,0},
  {7,2,2,0,0,0,1,0,0,6},
{0,0,1,0,3,1,3,0,0,1},
{0,0,3,2,0,0,1,0,0,2},
{3,0,0,0,0,4,0,1,4,1},
{0,0,8,2,0,0,0,0,2,0},
{0,0,1,0,7,0,0,1,0,0},
{0,6,0,0,0,2,0,0,5,1},
{1,0,0,0,0,3,0,9,0,2}};

double w[NUMBER_OF_KEYWORDS][NUMBER_OF_DOCS]={0};//w 행렬
double f[NUMBER_OF_KEYWORDS][NUMBER_OF_DOCS]={0};//f 행렬

string match_value_func(string qry) //질의에 대한 백터 매칭 값
{
if (qry == "A" || qry == "a")
return "1000000000";
else if (qry == "B" || qry == "b")
return "0100000000";
else if (qry == "C" || qry == "c")
return "0010000000";
else if (qry == "D" || qry == "d")
return "0001000000";
else if (qry == "E" || qry == "e")
return "0000100000";
else if (qry == "F" || qry == "f")
return "0000010000";
else if (qry == "G" || qry == "g")
return "0000001000";
else if (qry == "H" || qry == "h")
return "0000000100";
else if (qry == "I" || qry == "i")
return "0000000010";
else if (qry == "J" || qry == "j")
return "0000000001";
else
return "0000000000";
}

void print_matrix(double arr[][NUMBER_OF_DOCS]) //더블형 행렬 출력(디버깅용)
{
int i,j;
for(i=0;i<NUMBER_OF_KEYWORDS;i++)
{
for(j=0;j<NUMBER_OF_KEYWORDS;j++)
{
cout << arr[i][j] << " ";
}

cout << endl;
}
}

void print_matrix(int arr[][NUMBER_OF_DOCS]) //인트형 행렬 출력(디버깅용)
{
int i,j;
for(i=0;i<NUMBER_OF_KEYWORDS;i++)
{
for(j=0;j<NUMBER_OF_KEYWORDS;j++)
{
cout << arr[i][j] << " ";
}

cout << endl;
}
}

void print_array(int arr[]) // 정수형 배열 출력 (디버깅용)
{
int i;
for(i=0;i<NUMBER_OF_KEYWORDS;i++)
{
cout << arr[i] << ", ";
}
}

void print_array(double arr[]) // 더블형 배열 출력(디버깅용)
{
int i;
for(i=0;i<NUMBER_OF_KEYWORDS;i++)
{
cout << arr[i] << ", ";
}
}

void maxfreq_func(int doc_number, int arr[]) // 빈도수가 가장큰 단어를 찾는다. N 찾음
{
int i;
int max=freq[0][doc_number];
for(i=0;i<NUMBER_OF_KEYWORDS;i++)
{
if(max < freq[i][doc_number])
{
max = freq[i][doc_number];
}
}
arr[doc_number] = max;
}

int maxfreq_func(int doc_number) // 리턴 전용 maxfreq_func
{
int i;
int max=freq[0][doc_number];
for(i=0;i<NUMBER_OF_KEYWORDS;i++)
{
if(max < freq[i][doc_number])
{
max = freq[i][doc_number];
}
}
return max;
}

void make_matrix_f() // f 행렬계산 함수
{
int i,j;
for(i=0;i<NUMBER_OF_KEYWORDS;i++)
{
for(j=0;j<NUMBER_OF_KEYWORDS;j++)
{
f[i][j]=0.5 + 0.5 * freq[i][j]/maxfreq_func(j);
}
}
}

void make_matrix_w(int number_of_detection[]) // w행렬 계산 함수, 파라메터는 스몰 n 참조 배열
{
int i,j;
for(i=0;i<NUMBER_OF_KEYWORDS;i++)
{
for(j=0;j<NUMBER_OF_KEYWORDS;j++)
{
w[i][j]=f[i][j]*log10((double)(NUMBER_OF_DOCS/number_of_detection[i]));
}
}
}

double vector_similarity_func(int doc_number, string matched_value) // 유사도 계산 함수
{
int k;
double sim_value=0;
double upvalue=0;
double downvalue=0;

for(k=0;k<NUMBER_OF_KEYWORDS;k++)
{
upvalue += w[k][doc_number]*(matched_value[k]-48);
downvalue += pow(w[k][doc_number],2);
}

downvalue = sqrt(downvalue);
sim_value = upvalue / downvalue;

return sim_value;
}

void number_of_detection_func(int A[]) //단어 k가 발견된 총 문서의 수(스몰 n을 구함)
{
int i,j;
int number_of_detection;
for(i=0;i<NUMBER_OF_KEYWORDS;i++) //단어
{
number_of_detection=0;//루프 처음에 0으로 초기화
for(j=0;j<NUMBER_OF_KEYWORDS;j++) //문서1부터 끝까지 검사
{
if(freq[i][j]!=0) // 문서에 단어가 있다면...
{
number_of_detection++;
}
A[i] = number_of_detection; // 카운터 증가
}
}
}

int main ()
{
int k,i; // 루프 카운터
int doc_count=0;         // 검색된 총 문서의 수
double theta; // 세타값(검색 커트라인)
string qry; // 입력받은 질의
string matched_qry;    // 질의를 변경한 값
int sim_value; // 유사도 결과
int number_of_detection[NUMBER_OF_KEYWORDS]={0}; // n 배열
int maxfreq[NUMBER_OF_KEYWORDS]={0}; // max 배열
double sim[NUMBER_OF_KEYWORDS]; // sim 배열
int rank[NUMBER_OF_KEYWORDS]={0}; // rank 배열
double temp[NUMBER_OF_KEYWORDS]; // temp 배열
time_t   current_time;         // 검색 시간
ofstream OutFile; // 결과를 파일에 저장
    OutFile.open( "test.txt", ios::app );// 파일 오픈
time( &current_time);


cout << "질의 입력 : ";
getline( cin, qry );
cout << "세타 입력 : ";
cin >> theta;

OutFile << "*************************************"<<endl<<endl;
OutFile << ctime( &current_time)<<endl;
OutFile << "질의:" <<qry<<", 세타:"<<theta<<endl<<endl;

matched_qry=match_value_func(qry);
cout << endl<< "입력 질의 " << qry<<"의 매칭값은 "<<match_value_func(qry)<< "이고, 세타값은 " << theta <<"입니다." <<endl<<endl;

//출현한 문헌의 수(스몰 n)
number_of_detection_func(number_of_detection);

//각 문서 마다 가장 많이 출현하는 단어의 갯수를 저장 maxfreq
for(k=0;k<NUMBER_OF_KEYWORDS;k++)
{
maxfreq_func(k,maxfreq);
}

// f 행렬 생성
make_matrix_f();

//w 행렬 생성
make_matrix_w(number_of_detection);

//for문을 돌려서 유사도를 구함
for(k=0;k<NUMBER_OF_KEYWORDS;k++)
{
sim[k]=vector_similarity_func(k,matched_qry);
temp[k]=vector_similarity_func(k,matched_qry);
}

//구해진 유사도를 내림차순으로 정렬, temp배열이 정렬되어있음
sort(temp,temp+NUMBER_OF_DOCS, greater<double>());

//랭크에 해당하는 문서알려주기, 즉, 배열의 앞에 있을때 랭크가 높음
for(k=0;k<NUMBER_OF_KEYWORDS;k++)
{
for(i=0;i<NUMBER_OF_KEYWORDS;i++)
{
if(temp[k]==sim[i]) //이때 i값이 문서 번호임
{
if(rank[k]==0)
{
rank[k]=i;
}
else
{
rank[k+1]=i;
k++;
}
}
}
}

/* 배열 검사(디버깅용)
cout <<endl<< "sim배열"<<endl;
print_array(sim);
cout <<endl<< "temp배열"<<endl;
print_array(temp);
cout <<endl<< "rank배열"<<endl;
print_array(rank);
cout<<endl<<endl;

/* 행렬 검사(디버깅용)
print_matrix(freq);
cout <<endl;cout <<endl;
print_matrix(f);
cout <<endl;cout <<endl;
print_matrix(w);
cout <<endl;cout <<endl;
*/

if(match_value_func(qry) == "0000000000")
{
cout << "<<입력 질의 " << qry << "가 들어있는 문서를 찾을수 없습니다.>>"<<endl;
OutFile << "<<입력 질의 " << qry << "가 들어있는 문서를 찾을수 없습니다.>>"<<endl;

}
else
{
cout << "<<입력 질의 " << qry << "로 조회된 문서 리스트>>"<<endl;
OutFile << "<<입력 질의 " << qry << "로 조회된 문서 리스트>>"<<endl;

for(k=0;k<NUMBER_OF_KEYWORDS;k++) // 세타값보다 큰 문서를 출력
{
if(sim[rank[k]]>theta)
{
cout <<"RANK["<<k<<"] : "<<"문서"<< rank[k]+1 <<", 유사도 : "<<sim[rank[k]]<<endl;
OutFile << "RANK["<<k<<"] : "<<"문서"<< rank[k]+1 <<", 유사도 : "<<sim[rank[k]]<<endl;


doc_count++;
}
}
}

cout <<endl <<"총 "<< doc_count <<"건의 문서가 조회되었습니다."<<endl<<endl;
OutFile <<endl <<"총 "<< doc_count <<"건의 문서가 조회되었습니다."<<endl<<endl;
OutFile << "*************************************"<<endl<<endl;
OutFile.close();

fflush(stdin);
return main();
}