見出し画像

LangChainのTextSplitterを試す

「LangChain」の「TextSplitter」がテキストをどのように分割するかをまとめました。

前回

1. TextSplitter

「TextSplitter」は長いテキストをチャンクに分割するためのクラスです。
処理の流れは、次のとおりです。

(1) セパレータ(デフォルトは"\n\n")で、テキストを小さなチャンクに分割。
(2) 小さなチャンクを特定サイズになるまでマージし、大きなチャンクを作成。

2. CharacterTextSplitter

セパレータで分割して、文字数でマージするTextSplitterです。

from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(
    separator = "\n\n",  # セパレータ
    chunk_size = 11,  # チャンクの文字数
    chunk_overlap = 0,  # チャンクオーバーラップの文字数
)

セパレータなしのテキストは分割されません。

print(text_splitter.split_text("あいうえおかきくけこさしすせそやゆよわをん"))
['あいうえおかきくけこさしすせそやゆよわをん']

セパレータのありでチャンクの文字数を11にすると、次のように分割されます。
10にすると「あいうえお\n\nかきくけこ」がセットになりません。
(セパレータは1文字とカウントされてる?)

print(text_splitter.split_text("あいうえお\n\nかきくけこ\n\nさしすせそ\n\nやゆよ\n\nわをん"))
['あいうえお\n\nかきくけこ', 'さしすせそ\n\nやゆよ\n\nわをん']

チャンクオーバーラップの文字数を5にすると、次のように分割されます。
「かきくけこ」などチャンク単位でオーバーラップされています。

print(text_splitter.split_text("あいうえお\n\nかきくけこ\n\nさしすせそ\n\nやゆよ\n\nわをん"))
['あいうえお\n\nかきくけこ', 'かきくけこ\n\nさしすせそ', 'さしすせそ\n\nやゆよ', 'やゆよ\n\nわをん']

3. RecursiveCharacterTextSplitter

チャンクサイズの制限を下回るまで再帰的に分割するTextSplitterです。

from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = 11,   # チャンクの文字数
    chunk_overlap  = 0,  # チャンクオーバーラップの文字数
)

セパレータのないテキストも分割できます。
(チャンクの文字数11だけど9文字で分割?)

print(text_splitter.split_text("あいうえおかきくけこさしすせそやゆよわをん"))
['あいうえおかきくけ', 'こさしすせそやゆよ', 'わをん']

チャンクオーバーラップの文字数を5にすると、次のように分割されます。
「かきくけこ」など5文字単位でオーバーラップされています。

print(text_splitter.split_text("あいうえおかきくけこさしすせそやゆよわをん"))
['あいうえおかきくけこ', 'かきくけこさしすせそ', 'さしすせそやゆよわを', 'やゆよわをん']

4. tiktoken (OpenAI) Length Function

OpenAIのトークナイザーによるTextSplitterです。

text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
    separator = "\n\n",  # セパレータ
    chunk_size=14,  # チャンクのトークン数
    chunk_overlap=0  # チャンクオーバーラップのトークン数
)

はじめに、セパレータ分割した小さいチャンクのトークン数を確認します。

import tiktoken
enc = tiktoken.get_encoding("gpt2")

print(len(enc.encode("あいうえお")))
print(len(enc.encode("かきくけこ")))
print(len(enc.encode("さしすせそ")))
print(len(enc.encode("やゆよ")))
print(len(enc.encode("わをん")))
7
6
7
6
4

セパレータなしのテキストは分割されません。

print(text_splitter.split_text("あいうえおかきくけこさしすせそやゆよわをん"))
['あいうえおかきくけこさしすせそやゆよわをん']

セパレータのありでチャンクのトークン数を11にすると、次のように分割されます。

print(text_splitter.split_text("あいうえお\n\nかきくけこ\n\nさしすせそ\n\nやゆよ\n\nわをん"))
['あいうえお\n\nかきくけこ', 'さしすせそ\n\nやゆよ', 'わをん']

チャンクオーバーラップの文字数を6にすると、次のように分割されます。
「かきくけこ」は6トークンなのでオーバーラップされ、「さしすせそ」は7トークンなのでオーバーラップされません。

print(text_splitter.split_text("あいうえお\n\nかきくけこ\n\nさしすせそ\n\nやゆよ\n\nわをん"))
['あいうえお\n\nかきくけこ', 'かきくけこ\n\nさしすせそ', 'やゆよ\n\nわをん']

その他のTextSplitter

その他のTextSplitterは、次のとおりです。

4.1 HuggingFace Length Function

HuggingFaceのトークナイザーによるTextSplitterです。

text_splitter = CharacterTextSplitter.from_huggingface_tokenizer(
    GPT2TokenizerFast.from_pretrained("gpt2"),
    chunk_size=100,  # チャンクのトークン数
    chunk_overlap=0  # チャンクオーバーラップのトークン数
)

4.2 NLTKTextSplitter

NLTKによるTextSplitterです。

from langchain.text_splitter import NLTKTextSplitter
text_splitter = NLTKTextSplitter(
    chunk_size=1000  # チャンクのトークン数
)

4.3 SpacyTextSplitter

SpacyによるTextSplitterです。

from langchain.text_splitter import SpacyTextSplitter
text_splitter = SpacyTextSplitter(
    chunk_size=1000  # チャンクのトークン数
)

関連

次回



この記事が気に入ったらサポートをしてみませんか?