본문 바로가기
data science/python

(python) text 를 길이 단위로 분리

by 꼰대코더 2023. 12. 6.

OpenAI Embedding 기능을 사용하기 위해 PDF 에서 Text를 추출하여 특정 길이로 분리할 필요가 있었어 langchain 의 CharacterTextSplitter 를 사용하였다.

인스톨

pip install langchain

 

CharacterTextSplitter

 

from langchain.text_splitter import CharacterTextSplitter


story = '어느 마을에 양치기 소년이 하나 있었는데,\n 늑대들이 나타나 양을 물어간다느니 잡아먹는다느니 식으로 수시로 장난삼아 소리치곤 했다. 두세 번 정도는 마을 사람들이 놀라 부리나케 달려왔다. 하지만 그 때마다 골탕을 먹고 바보가 된 기분으로 화를 내거나 투덜거리며 돌아갔다.\n 그러던 어느 날 진짜로 늑대가 나타나서 양들을 잡아먹거나 물어가기 시작했다. 양치기는 이번엔 절대로 거짓말이 아니고 진짜라면서 마을 사람들에게 도와 달라고 호소했으나, 마을 사람들은 이번에도 절대로 속지 않을 것이며, 설령 진짜로 늑대가 나타났다 한들 다 저 녀석의 업보라고 칠 것이라면서 한 명도 도와주러 오지 않았다. 결국 양치기는 그렇게 양떼를 모두 잃고 말았다.'

text_splitter = CharacterTextSplitter(
        separator = "\n",
        chunk_size = 100,
        chunk_overlap = 20,
        length_function = len,
)
    
 chunks = text_splitter.split_text(text)

 

결과

--------------
[0] 분리 길이 : 23
--------------
어느 마을에 양치기 소년이 하나 있었는데,

--------------
[1] 분리 길이 : 126
--------------
늑대들이 나타나 양을 물어간다느니 잡아먹는다느니 식으로 수시로 장난삼아 소리치곤 했다. 두세 번 정도는 마을 사람들이 놀라 부리나케 달려왔다. 하지만 그 때마다 골탕을 먹고 바보가 된 기분으로 화를 내거나 투덜거리며 돌아갔다.

--------------
[2] 분리 길이 : 206
--------------
그러던 어느 날 진짜로 늑대가 나타나서 양들을 잡아먹거나 물어가기 시작했다. 양치기는 이번엔 절대로 거짓말이 아니고 진짜라면서 마을 사람들에게 도와 달라고 호소했으나, 마을 사람들은 이번에도 절대로 속지 않을 것이며, 설령 진짜로 늑대가 나타났다 한들 다 저 녀석의 업보라고 칠 것이라면서 한 명도 도와주러 오지 않았다. 결국 양치기는 그렇게 양떼를 모두 잃고 말았다.

chunk_size 설정과 관계없이 분리자(separator) 단위로 분리하는 결과가 나왔다. 또한 chunk_overlap 설정도 무시하는 결과도 나왔다.  

여러 chunk_size 로 테스트해 본 결과 아래와 같은 동작이 일어남을 파악했다.
(1) 일단 분리자로 각 패러그래프를 만듦

(2) 맨 마지막 패러그래프는 길이에 관계없이 절대 건들지 않음

(3) 나머지 패러그래프의 길이를 가지고  전후 패러그래프의 길이를 조사를 해서 길이의 합이 chunk_size 를 넘지 않는다면 합치고        넘는다면 두 패러그래프를 그대로 둚.

 

RecursiveCharacterTextSplitter

from langchain.text_splitter import RecursiveCharacterTextSplitter


story = '어느 마을에 양치기 소년이 하나 있었는데,\n 늑대들이 나타나 양을 물어간다느니 잡아먹는다느니 식으로 수시로 장난삼아 소리치곤 했다. 두세 번 정도는 마을 사람들이 놀라 부리나케 달려왔다. 하지만 그 때마다 골탕을 먹고 바보가 된 기분으로 화를 내거나 투덜거리며 돌아갔다.\n 그러던 어느 날 진짜로 늑대가 나타나서 양들을 잡아먹거나 물어가기 시작했다. 양치기는 이번엔 절대로 거짓말이 아니고 진짜라면서 마을 사람들에게 도와 달라고 호소했으나, 마을 사람들은 이번에도 절대로 속지 않을 것이며, 설령 진짜로 늑대가 나타났다 한들 다 저 녀석의 업보라고 칠 것이라면서 한 명도 도와주러 오지 않았다. 결국 양치기는 그렇게 양떼를 모두 잃고 말았다.'

text_splitter = RecursiveCharacterTextSplitter(
        chunk_size = 100,
        chunk_overlap = 20,
        length_function = len,
)
    
 chunks = text_splitter.split_text(text)

 

결과

문장길이 : 358
--------------
[0] 분리 길이 : 23
--------------
어느 마을에 양치기 소년이 하나 있었는데,

--------------
[1] 분리 길이 : 96
--------------
늑대들이 나타나 양을 물어간다느니 잡아먹는다느니 식으로 수시로 장난삼아 소리치곤 했다. 두세 번 정도는 마을 사람들이 놀라 부리나케 달려왔다. 하지만 그 때마다 골탕을 먹고

--------------
[2] 분리 길이 : 46
--------------
하지만 그 때마다 골탕을 먹고 바보가 된 기분으로 화를 내거나 투덜거리며 돌아갔다.

--------------
[3] 분리 길이 : 96
--------------
그러던 어느 날 진짜로 늑대가 나타나서 양들을 잡아먹거나 물어가기 시작했다. 양치기는 이번엔 절대로 거짓말이 아니고 진짜라면서 마을 사람들에게 도와 달라고 호소했으나, 마을

--------------
[4] 분리 길이 : 99
--------------
도와 달라고 호소했으나, 마을 사람들은 이번에도 절대로 속지 않을 것이며, 설령 진짜로 늑대가 나타났다 한들 다 저 녀석의 업보라고 칠 것이라면서 한 명도 도와주러 오지 않았다.

--------------
[5] 분리 길이 : 44
--------------
한 명도 도와주러 오지 않았다. 결국 양치기는 그렇게 양떼를 모두 잃고 말았다.

(1) 일단 분리자로 각 패러그래프를 만듦

(2) chunk_size 보다 짧은 패러그래프는 그대로 둠

(3) chunk_size 보다 긴 패러그래프를 대상으로 chunk_size 로 분리를 함

(4) 분리 대상인 긴 패러그래프에서 분리되는 2번째 문장부터는 앞의 문장으로부터 chunk_overlap 만큼 가져와서 합친다.

 

이상으로 부터 엄밀히 길이 단위로 문장을 분리하고자 한다면 RecursiveCharacterTextSplitter 가 적합하다.