
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 # チャンクのトークン数
)