複合名詞の周辺の情報、複合名詞の先頭と末尾の情報

この前やったSVMに使った素性は考えられる中では相当単純なものを使ったので、(悪くはなかったけど)改善の余地がありまくっている。というわけで

  • 複合名詞の先頭の単語
  • 複合名詞の末尾の単語
  • 複合名詞の前後の単語

を集めてくるためのコードを書いた。条件分岐のところでやたらと時間を食う結果となった。。。

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <set>
#include <map>
#include <vector>
#include <algorithm>
#include <boost/filesystem/operations.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
#include <mecab.h>

class Word {
public:
  std::string word;
  std::string pos;
  Word(std::string word, std::string pos){
	this->word = word;
	this->pos = pos;
  };
  virtual ~Word(){
  };
};

class Context {
public:
  std::vector<std::string> words; // 考える中心となる複合名詞
  std::string head; // 複合名詞の先頭語  
  std::string tail; // 複合名詞の末尾
  std::vector<Word> prefix; // 複合名詞の前にある単語群
  std::vector<Word> suffix; // 複合名詞の後にある単語群
  Context(){
  };
  void clear(){
	words.clear();
	head.erase();
	tail.erase();
	prefix.clear();
	suffix.clear();
  };
  std::ostream& print(std::ostream& os) {
	for (std::vector<Word>::iterator it = prefix.begin(); it != prefix.end(); ++it) {
	  os << "\t" << (*it).word << "(" << (*it).pos << ")";
	  os << std::endl;
	}
	for (std::vector<std::string>::iterator it = words.begin(); it != words.end(); ++it) {
	  os << *it;
	}
	os << "(" << head << ", " << tail << ")";
	os << std::endl;
	for (std::vector<Word>::iterator it = suffix.begin(); it != suffix.end(); ++it) {
	  os << "\t" << (*it).word << "(" << (*it).pos << ")";
	  os << std::endl;
	}
	os << std::endl;
	return os;
  }
  virtual ~Context(){ 
  };
};

class CompoundNounList {
public:
  std::set<std::string> accept_pos_vec; // sequenceとして許容する品詞の集合
  CompoundNounList(){
	accept_pos_vec.insert("名詞");
	accept_pos_vec.insert("接頭詞");
	accept_pos_vec.insert("記号");
  };
  void add_text(std::string text) {
	MeCab::Tagger *tagger = MeCab::createTagger("-O wakati");
	const MeCab::Node *node = tagger->parseToNode(text.c_str());
	std::string prev_pos; // 前の単語の品詞
	Context prev_context;
	Context current_context;
	Context next_context;
	for( node=node->next; node->next; node=node->next ){ 
	  char *s = new char [node->length + 1]; // 形態素解析されて出てきた文字列(品詞の情報ではなく)
	  strncpy(s, node->surface, node->length);
	  s[node->length] = '\0';
	  std::vector<std::string> strvec;
	  boost::algorithm::split(strvec, node->feature, boost::algorithm::is_any_of(","));
	  // strvec[0]は形態素解析された結果
	  if (accept_pos_vec.find(strvec[0]) != accept_pos_vec.end()){ // 今の単語の品詞が名詞である場合
		current_context.words.push_back(s);
		if (accept_pos_vec.find(prev_pos) == accept_pos_vec.end()) { // 前の単語の品詞が名詞ではない場合
		  current_context.head = s;
		  if (!prev_context.words.empty()) {
			list.push_back(prev_context);
		  }
		}
	  } else { // 今の単語の品詞が名詞ではない場合
		if (accept_pos_vec.find(prev_pos) != accept_pos_vec.end()) { // が、前の単語の品詞は名詞である場合
		  Word w(std::string(s), strvec[0]);
		  current_context.suffix.push_back(w);
		  next_context.prefix.push_back(w);
		  current_context.tail = current_context.words.at(current_context.words.size()-1);

		  // contextを一つづつずらしていく
		  prev_context.clear();
		  prev_context = current_context;
		  current_context.clear();
		  current_context = next_context;
		  next_context.clear();
		} else { // 前も今の単語も名詞でない場合
		  Word w(std::string(s), strvec[0]);
		  prev_context.suffix.push_back(w);
		  current_context.prefix.push_back(w);
		}
	  }
	  prev_pos = strvec[0];
	}
	if (!current_context.words.empty()) { // 最後の文字が名詞の場合
	  list.push_back(current_context);
	}
	delete tagger;
  };
  std::ostream& print(std::ostream& os) {
	for (std::vector<Context>::iterator it = list.begin(); it != list.end(); ++it) {
	  (*it).print(os);
	  os << std::endl;
	}
	return os;
  }
  virtual ~CompoundNounList(){
  };
private:
  std::vector<Context> list;
};

int main(int argc, char *argv[]) {
  CompoundNounList cl;
  cl.add_text("たとえば, アクチン重合阻害剤であるラトランキュリンをごくうすい濃度で含む培養液中に細胞を入れると, ");
   //  cl.add_text("抗IQGAP1抗体を用いて内在性のIQGAP1の免疫染色 (青色) を行ったところ");
  cl.print(std::cout);
  return 0;
}

実行結果。しめしめ、来週はこの辺も素性に組み込んで色々やってみようと思う。

/Users/syou6162/dbcls/src/cpp% ./a.out
	たとえば(接続詞)
,アクチン重合阻害剤(,, 剤)
	で(助動詞)
	ある(助動詞)


	で(助動詞)
	ある(助動詞)
ラトランキュリン(ラトランキュリン, ラトランキュリン)
	を(助詞)
	ごく(副詞)
	うすい(形容詞)


	を(助詞)
	ごく(副詞)
	うすい(形容詞)
濃度(濃度, 濃度)
	で(助詞)
	含む(動詞)


	で(助詞)
	含む(動詞)
培養液中(培養, 中)
	に(助詞)


	に(助詞)
細胞(細胞, 細胞)
	を(助詞)
	入れる(動詞)
	と(助詞)


	を(助詞)
	入れる(動詞)
	と(助詞)
,(,, )