<jupyter_start><jupyter_text>MeCab & CaboCha  CONTENTS* [MeCab](MeCabによる形態素解析)* [CaboCha](CaboChaによる係り受け解析)  MeCabによる形態素解析  形態素解析とは文法的な情報の注記の無い自然言語の文から、対象言語の文法や、辞書と呼ばれる単語の品詞等の情報にもとづき、  形態素(おおまかにいえば、言語で意味を持つ最小単位)に分割し、それぞれの形態素の品詞等を判別する作業。  [MeCab(和布蕪)](https://taku910.github.io/mecab/)オープンソース形態素解析エンジン<jupyter_code>import MeCab<jupyter_output><empty_output><jupyter_text>とりあえず解析 `MeCab.Tagger` クラスインスタンスを生成して、 `parse` というメソッドを用いて、形態素解析の結果を文字列として得ることができる。  MeCabでは、一行一文を前提に解析が行われる。<jupyter_code>tagger = MeCab.Tagger()
sentence = 'いま働いている会社は最悪な会社だと思う'
parse = tagger.parse(sentence)
print(parse)
type(parse)<jupyter_output><empty_output><jupyter_text>各形態素の詳細情報の取得 `MeCab.Tagger` クラスインスタンスの `parseToNode` というメソッドにより、  **文頭**という特別な形態素が、 `MeCab.Node` クラスインスタンスとして取得できる。<jupyter_code>tagger = MeCab.Tagger()
tagger.parse('') # MeCabのバグ対応
node = tagger.parseToNode(sentence)
type(node)<jupyter_output><empty_output><jupyter_text>MeCab.Node クラスインスタンスは、双方向リストとして表現されていて、 `next` 、 `prev` という属性がある。  それぞれ、次の形態素、前の形態素を `MeCab.Node` クラスインスタンスとして取得できる。  また、形態素の文字列情報と素性情報は、`MeCab.Node` クラスインスタンスの `surface` 、 `feature` という属性により取得できる。<jupyter_code>print(node.next.surface)<jupyter_output>いま<jupyter_text>ここで、 `parseToNode` で取得した初めの `node` は、 BOS(beginning of sentence) として空文字列('') として取得されるので、注意。  行末の `node` も、EOS(end of sentence)として空文字列('') として取得される。<jupyter_code>node = node.next.next
print(f'1:{node.prev.surface} 2:{node.surface} 3:{node.next.surface}')<jupyter_output>1:いま 2:働い 3:て<jupyter_text>一文の全形態素の文字列情報と素性情報を取得したい場合は、以下の様にするとよい。<jupyter_code>node = tagger.parseToNode(sentence)

surface_list = list()
feature_list = list()

while node:
    surface_list.append(node.surface)
    feature_list.append(node.feature)
    node = node.next
surface_list
feature_list<jupyter_output><empty_output><jupyter_text>形態素の品詞を抜き出したければ、以下のようにする。<jupyter_code>[ feature.split(',')[0] for feature in feature_list]<jupyter_output><empty_output><jupyter_text>`MeCab.Tagger`   **クラスのコンストラクタの引数**全ての引数は、公式の[こちら](https://taku910.github.io/mecab/mecab.html)を参照のこと。  基本的には、コマンドライン実行形式の引数に同じ。  以下には、よく使うものを列挙 * `-r`, `--rcfile=FILE`  mecabの設定ファイルとして使用するものを指定する* `-d`, `--dicdir=DIR`  システムディクショナリのディレクトリを指定する。    ```    tagger = MeCab.Tagger('-d /usr/local/lib/mecab/dic/ipadic')    ```* `-u`, `--userdic=FILE`  ユーザーディクショナリのファイルを指定する。    ```    tagger = MeCab.Tagger('-u ./usr-mecab-ipadic-neologd.dic')    ```  **method/attribute**MeCab.Tagger クラスのは[こちら](https://taku910.github.io/mecab/bindings.html)を参照のこと  CaboChaによる係り受け解析  係り受け解析とは文法的な情報の注記の無い自然言語の文から、対象言語の文法や、辞書と呼ばれる単語の品詞等の情報にもとづき、  文節 (日本語の文法においては、文を細かく区切った際に不自然にならない最小単位。単語よりは大きい)に分割し、  それぞれの修飾・被修飾関係を判別する作業。  [CaboCha(南瓜)](http://taku910.github.io/cabocha/)CaboChaは、日本語係り受け解析器<jupyter_code>import CaboCha<jupyter_output><empty_output><jupyter_text>とりあえず係り受け解析`CaboCha.Parser` クラスインスタンスを生成して、`parse` というメソッドを用いて、係り受け解析の結果を `CaboCha.Tree` クラスインスタンスとして得ることができる。  `CaboCha.Tree` クラスインスタンスの `toString` というメソッドを用いて、解析結果を文字列として取得できる。<jupyter_code>parser = CaboCha.Parser()
sentence = 'いま働いている会社は最悪な会社だと思う'
tree = parser.parse(sentence)
result = tree.toString(CaboCha.FORMAT_TREE)
print(result)
type(result)<jupyter_output><empty_output><jupyter_text>各形態素の詳細情報の取得形態素のデータを取得するには、`parse` メソッドで得られた `CaboCha.Tree` クラスインスタンスの、 `token()` メソッドを用いれば良い。  このメソッドの引数は、int型で、何番目の**形態素**を取得するかの値をとる。  解析の結果得られた、全形態素数は、`CaboCha.Tree` クラスインスタンスの、 `token_size` メソッドにより取得できる。  形態素のデータは、 `CaboCha.Token` クラスインスタンスとして、以下のように取得できる。<jupyter_code>token_list = [ tree.token(n) for n in range(tree.token_size())]
type(token_list[0])<jupyter_output><empty_output><jupyter_text>`CaboCha.Token` クラスインスタンスの `surface` 、 `feature` という属性により形態素の文字列情報と素性情報を取得できる。<jupyter_code>surface_list = [ token.surface for token in token_list]
surface_list
feature_list = [ token.feature for token in token_list]
feature_list<jupyter_output><empty_output><jupyter_text>結果をみるとわかるように、CaboCha での係り受け解析には、形態素解析が実施されている。このとき MeCab が使用されている。  文節の詳細情報の取得係り受け解析の末得られた文節のデータを取得するには、`parse` メソッドで得られた `CaboCha.Tree` クラスインスタンスの、`chunk` メソッドを用いれば良い。  このメソッドの引数は、int型で、何番目の**文節**を取得するかの値をとる。  解析の結果得られた、全文節数は、`CaboCha.Tree` クラスインスタンスの、`chunk_size` メソッドにより取得できる。  文節のデータは、`CaboCha.Chunk` クラスインスタンスとして、以下のように取得できる。<jupyter_code>chunk_list = [ tree.chunk(n) for n in range(tree.chunk_size()) ]
type(chunk_list[0])<jupyter_output><empty_output><jupyter_text>とある文節がどの文節にかかっているかは、 `link` という属性により取得できる。<jupyter_code>chunk_list[0].link<jupyter_output><empty_output><jupyter_text>この場合、一番目の文節は、二番目の文節にかかっている事になる。どの文節にもかからない場合は、 0 が返る。 また、各文節の文字列情報と素性情報を取得するメソッドは、`CaboCha.Chunk` クラスインスタンスには用意されていない。  そのため、形態素のデータと組み合わせて取得することになる。各文節に含まれる形態素の数は、 `CaboCha.Chunk` クラスインスタンスの `token_size` という属性により取得できる。  また、ひとつの文節中の一番初めの形態素の全形態素中でのインデックスを `token_pos` という属性により取得できる。<jupyter_code>chunk_list[2].token_size
chunk_list[2].token_pos<jupyter_output><empty_output><jupyter_text>これらの値を用いて、以下のように文節を取得できる。<jupyter_code>paragraph = [ str().join(surface_list[chunk.token_pos:chunk.token_pos+chunk.token_size]) for chunk in chunk_list ]
paragraph<jupyter_output><empty_output><jupyter_text>係り受けの関係の取得係り受けの関係をまとめる方法の一例として以下の方法を挙げる。<jupyter_code>chunk_link_list = np.array([ chunk.link for chunk in chunk_list ])
paragraph = np.array(paragraph)
dependency = dict(zip(paragraph[chunk_link_list >= 0],paragraph[chunk_link_list[chunk_link_list >= 0]]))
for active, passive in dependency.items():
    print(f'{active} -> {passive}')<jupyter_output>いま -> 働いている
働いている -> 会社は
会社は -> 会社だと
最悪な -> 会社だと
会社だと -> 思う
{'fraction_non_alphanumeric': 0.13287998529682044, 'fraction_numerical': 0.004962323102370888, 'mean_word_length': 10.481012658227849, 'pattern_counts': {'":': 0, '<': 62, '<?xml version=': 0, '>': 70, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '587835', 'license': 'MIT', 'n_tokens_mistral': 3478, 'n_tokens_neox': 3339, 'n_words': 238, 'path': '001/mecab_cabocha.ipynb', 'repo_name': 'aYukiYoshida/nlp-notebook', 'size': '5441'}