Skip to content

hyunwoongko/kss

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 Cannot retrieve latest commit at this time.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Kss: A Toolkit for Korean sentence segmentation

GitHub release Issues

This repository contains the source code of Kss, a representative Korean sentence segmentation toolkit. I also conduct ongoing research about Korean sentence segmentation algorithms and report the results to this repository. If you have some good ideas about Korean sentence segmentation, please feel free to talk through the issue.


What's New:

Installation

Install Kss

Kss can be easily installed using the pip package manager.

pip install kss

Install Mecab (Optional)

Please install mecab or konlpy.tag.Mecab to use Kss much faster.

Features

1) split_sentences: split text into sentences

from kss import split_sentences

split_sentences(
    text: Union[str, List[str], Tuple[str]],
    backend: str = "auto",
    num_workers: Union[int, str] = "auto" ,
    strip: bool = True,
)
Parameters
  • text: String or List/Tuple of strings
    • string: single text segmentation
    • list/tuple of strings: batch texts segmentation
  • backend: Morpheme analyzer backend
    • backend='auto': find mecab β†’ konlpy.tag.Mecab β†’ pecab and use first found analyzer (default)
    • backend='mecab': find mecab β†’ konlpy.tag.Mecab and use first found analyzer
    • backend='pecab': use pecab analyzer
  • num_workers: The number of multiprocessing workers
    • num_workers='auto': use multiprocessing with the maximum number of workers if possible (default)
    • num_workers=1: don't use multiprocessing
    • num_workers=2~N: use multiprocessing with the specified number of workers
  • strip: Whether it does strip() for all output sentences or not
    • strip=True: do strip() for all output sentences (default)
    • strip=False: do not strip() for all output sentences
Usages
  • Single text segmentation

    import kss
    
    text = "νšŒμ‚¬ λ™λ£Œ λΆ„λ“€κ³Ό λ‹€λ…€μ™”λŠ”λ° λΆ„μœ„κΈ°λ„ μ’‹κ³  μŒμ‹λ„ λ§›μžˆμ—ˆμ–΄μš” λ‹€λ§Œ, 강남 토끼정이 강남 쉑쉑버거 골λͺ©κΈΈλ‘œ μ­‰ μ˜¬λΌκ°€μ•Ό ν•˜λŠ”λ° λ‹€λ“€ μ‰‘μ‰‘λ²„κ±°μ˜ μœ ν˜Ήμ— λ„˜μ–΄κ°ˆ λ»” ν–ˆλ‹΅λ‹ˆλ‹€ 강남역 λ§›μ§‘ ν† λΌμ •μ˜ μ™ΈλΆ€ λͺ¨μŠ΅."
    
    kss.split_sentences(text)
    # ['νšŒμ‚¬ λ™λ£Œ λΆ„λ“€κ³Ό λ‹€λ…€μ™”λŠ”λ° λΆ„μœ„κΈ°λ„ μ’‹κ³  μŒμ‹λ„ λ§›μžˆμ—ˆμ–΄μš”', 'λ‹€λ§Œ, 강남 토끼정이 강남 쉑쉑버거 골λͺ©κΈΈλ‘œ μ­‰ μ˜¬λΌκ°€μ•Ό ν•˜λŠ”λ° λ‹€λ“€ μ‰‘μ‰‘λ²„κ±°μ˜ μœ ν˜Ήμ— λ„˜μ–΄κ°ˆ λ»” ν–ˆλ‹΅λ‹ˆλ‹€', '강남역 λ§›μ§‘ ν† λΌμ •μ˜ μ™ΈλΆ€ λͺ¨μŠ΅.']
  • Batch texts segmentation

    import kss
    
    texts = [
        "νšŒμ‚¬ λ™λ£Œ λΆ„λ“€κ³Ό λ‹€λ…€μ™”λŠ”λ° λΆ„μœ„κΈ°λ„ μ’‹κ³  μŒμ‹λ„ λ§›μžˆμ—ˆμ–΄μš” λ‹€λ§Œ, 강남 토끼정이 강남 쉑쉑버거 골λͺ©κΈΈλ‘œ μ­‰ μ˜¬λΌκ°€μ•Ό ν•˜λŠ”λ° λ‹€λ“€ μ‰‘μ‰‘λ²„κ±°μ˜ μœ ν˜Ήμ— λ„˜μ–΄κ°ˆ λ»” ν–ˆλ‹΅λ‹ˆλ‹€",
        "강남역 λ§›μ§‘ ν† λΌμ •μ˜ μ™ΈλΆ€ λͺ¨μŠ΅. 강남 토끼정은 4μΈ΅ 건물 λ…μ±„λ‘œ 이루어져 μžˆμŠ΅λ‹ˆλ‹€.",
        "μ—­μ‹œ 토끼정 λ³Έ 점 λ‹΅μ£ ?γ…Žγ……γ…Ž 건물은 ν¬μ§€λ§Œ κ°„νŒμ΄ μ—†κΈ° λ•Œλ¬Έμ— μ§€λ‚˜μΉ  수 μžˆμœΌλ‹ˆ μ‘°μ‹¬ν•˜μ„Έμš” 강남 ν† λΌμ •μ˜ λ‚΄λΆ€ μΈν…Œλ¦¬μ–΄.",
    ]
    
    kss.split_sentences(texts)
    # [['νšŒμ‚¬ λ™λ£Œ λΆ„λ“€κ³Ό λ‹€λ…€μ™”λŠ”λ° λΆ„μœ„κΈ°λ„ μ’‹κ³  μŒμ‹λ„ λ§›μžˆμ—ˆμ–΄μš”', 'λ‹€λ§Œ, 강남 토끼정이 강남 쉑쉑버거 골λͺ©κΈΈλ‘œ μ­‰ μ˜¬λΌκ°€μ•Ό ν•˜λŠ”λ° λ‹€λ“€ μ‰‘μ‰‘λ²„κ±°μ˜ μœ ν˜Ήμ— λ„˜μ–΄κ°ˆ λ»” ν–ˆλ‹΅λ‹ˆλ‹€']
    # ['강남역 λ§›μ§‘ ν† λΌμ •μ˜ μ™ΈλΆ€ λͺ¨μŠ΅.', '강남 토끼정은 4μΈ΅ 건물 λ…μ±„λ‘œ 이루어져 μžˆμŠ΅λ‹ˆλ‹€.']
    # ['μ—­μ‹œ 토끼정 λ³Έ 점 λ‹΅μ£ ?γ…Žγ……γ…Ž', '건물은 ν¬μ§€λ§Œ κ°„νŒμ΄ μ—†κΈ° λ•Œλ¬Έμ— μ§€λ‚˜μΉ  수 μžˆμœΌλ‹ˆ μ‘°μ‹¬ν•˜μ„Έμš”', '강남 ν† λΌμ •μ˜ λ‚΄λΆ€ μΈν…Œλ¦¬μ–΄.']]
  • Remain all prefixes/suffixes space characters for original text recoverability

    import kss
    
    text = "νšŒμ‚¬ λ™λ£Œ λΆ„λ“€κ³Ό λ‹€λ…€μ™”λŠ”λ° λΆ„μœ„κΈ°λ„ μ’‹κ³  μŒμ‹λ„ λ§›μžˆμ—ˆμ–΄μš”\nλ‹€λ§Œ, 강남 토끼정이 강남 쉑쉑버거 골λͺ©κΈΈλ‘œ μ­‰ μ˜¬λΌκ°€μ•Ό ν•˜λŠ”λ° λ‹€λ“€ μ‰‘μ‰‘λ²„κ±°μ˜ μœ ν˜Ήμ— λ„˜μ–΄κ°ˆ λ»” ν–ˆλ‹΅λ‹ˆλ‹€ 강남역 λ§›μ§‘ ν† λΌμ •μ˜ μ™ΈλΆ€ λͺ¨μŠ΅."
    
    kss.split_sentences(text)
    # ['νšŒμ‚¬ λ™λ£Œ λΆ„λ“€κ³Ό λ‹€λ…€μ™”λŠ”λ° λΆ„μœ„κΈ°λ„ μ’‹κ³  μŒμ‹λ„ λ§›μžˆμ—ˆμ–΄μš”\n', 'λ‹€λ§Œ, 강남 토끼정이 강남 쉑쉑버거 골λͺ©κΈΈλ‘œ μ­‰ μ˜¬λΌκ°€μ•Ό ν•˜λŠ”λ° λ‹€λ“€ μ‰‘μ‰‘λ²„κ±°μ˜ μœ ν˜Ήμ— λ„˜μ–΄κ°ˆ λ»” ν–ˆλ‹΅λ‹ˆλ‹€ ', '강남역 λ§›μ§‘ ν† λΌμ •μ˜ μ™ΈλΆ€ λͺ¨μŠ΅.']
Performance Analysis

1) Test Commands

You can reproduce all the following analyses using source code and datasets in ./bench/ directory and the source code was copied from here. Note that the Baseline is regex based segmentation method (re.split(r"(?<=[.!?])\s", text)).

Name Command (in root directory)
Baseline python3 ./bench/test_baseline.py ./bench/testset/*.txt
Kiwi python3 ./bench/test_kiwi.py ./bench/testset/*.txt
Koalanlp python3 ./bench/test_koalanlp.py ./bench/testset/*.txt --backend=OKT/HNN/KMR/RHINO/EUNJEON/ARIRANG/KKMA
Kss (ours) python3 ./bench/test_kss.py ./bench/testset/*.txt --backend=mecab/pecab

2) Evaluation datasets:

I used the following 6 evaluation datasets for analyses. Thanks to Minchul Lee for creating various sentence segmentation datasets.

Name Descriptions The number of sentences Creator
blogs_lee Dataset for testing blog style text segmentation 170 Minchul Lee
blogs_ko Dataset for testing blog style text segmentation, which is harder than Lee's blog dataset 336 Hyunwoong Ko
tweets Dataset for testing tweeter style text segmentation 178 Minchul Lee
nested Dataset for testing text which have parentheses and quotation marks segmentation 91 Minchul Lee
v_ending Dataset for testing difficult eomi segmentation, it contains various dialect sentences 30 Minchul Lee
sample An example used in README.md (강남 토끼정) 41 Isaac, modified by Hyunwoong Ko

Note that I modified labels of two sentences in sample.txt made by Issac because the original blog post was written like the following:

But Issac's labels were:

In fact, 사싀 μ „ κ³ κΈ°λ₯Ό μ•ˆ λ¨Ήμ–΄μ„œ 무슨 맛인지 λͺ¨λ₯΄κ² μ§€λ§Œ.. and (λ¬Όλ‘  μ „ μ•ˆ λ¨Ήμ—ˆμ§€λ§Œ are embraced sentences (μ•ˆκΈ΄λ¬Έμž₯), not independent sentences. So sentence segmentation tools should do not split that parts.


3) Sentence segmentation performance (Quantitative Analysis)

The following table shows the segmentation performance based on exact match (EM). If you are unfamilar with EM score and F1 score, please refer to this. Kss performed best in most cases, and Kiwi performed well. Both baseline and koalanlp performed poorly.

Name Library version Backend blogs_lee blogs_ko tweets nested v_ending sample Average
Baseline N/A N/A 0.53529 0.44940 0.51124 0.68132 0.00000 0.34146 0.41987
Koalanlp 2.1.7 OKT 0.53529 0.44940 0.53371 0.79121 0.00000 0.36585 0.44591
Koalanlp 2.1.7 HNN 0.54118 0.44345 0.54494 0.78022 0.00000 0.34146 0.44187
Koalanlp 2.1.7 KMR 0.51176 0.39583 0.42135 0.79121 0.00000 0.26829 0.39807
Koalanlp 2.1.7 RHINO 0.52941 0.40774 0.39326 0.79121 0.00000 0.29268 0.40238
Koalanlp 2.1.7 EUNJEON 0.51176 0.37500 0.38202 0.70330 0.00000 0.21951 0.36526
Koalanlp 2.1.7 ARIRANG 0.51176 0.41071 0.44382 0.79121 0.00000 0.29268 0.40836
Koalanlp 2.1.7 KKMA 0.52941 0.45238 0.38202 0.58242 0.06667 0.31707 0.38832
Kiwi 0.14.0 N/A 0.78235 0.60714 0.66292 0.83516 0.20000 0.90244 0.66500
Kss (ours) 4.0.0 pecab 0.86471 0.82440 0.71910 0.87912 0.36667 0.95122 0.76753
Kss (ours) 4.0.0 mecab 0.86471 0.82440 0.73034 0.87912 0.36667 0.95122 0.76941

You can also compare the performances with the following graphs.


4) Why don't I upload F1 score based results?

The evaluation source code which I copied from kiwipiepy also provides F1 score (dice similarity), and F1 scores of Kss are also best among the segmentation tools. but I don't believe this is proper metric to measure sentence segmentation performance. For example, EM score of text.split(" ") on tweets.txt is 0.06742. This means it's terrible sentence segmentation method on tweeter style text. However, F1 score of it on tweets.txt is 0.54083, and it is similar with the F1 score of Koalanlp KKMA backend (0.56832).

What I want to say is the actual performances of segmentation could be vastly different even if the F1 scores were similar. You can reproduce this with python3 ./bench/test_word_split.py ./bench/testset/tweets.txt, and here is one of the segmentation example of both method.

Input:

κΈ°μ–΅ν•΄. λ„Œ κ·Έ μ• μ˜ μΉœκ΅¬μ•Ό. λ„€κ°€ 죽으면 마 λ“€λ ˆ λŠκ°€ νŽ‘νŽ‘ 울 κ±°μ•Ό. λΉ„ μ²΄λŠ” μŠ¬νΌν•˜κ² μ§€. 이 μ•ˆμ€ ν™”λ₯Ό λ‚Ό κ±°μ•Ό. 메이 μ‹œλŠ” μ–΄μ©Œλ©΄ μ‘°κΈˆμ€ 생각 ν•΄ μ£Όμ§€ μ•Šμ„κΉŒ. μ€‘μš”ν•œ 건 그건 λ„€κ°€ μ§€ν‚€κ³  μ‹Άμ–΄ ν–ˆλ˜ μ‚¬λžŒλ“€μ΄μž–μ•„. μ–΄μ„œ κ°€.
Method: Koalanlp KKMA backend
EM score: 0.38202
F1 score: 0.56832

Output:
κΈ°μ–΅ν•΄. λ„Œ κ·Έ μ• μ˜ μΉœκ΅¬μ•Ό.
λ„€κ°€ 죽으면 마 λ“€λ ˆ λŠκ°€ νŽ‘νŽ‘ 울 κ±°μ•Ό.
λΉ„ μ²΄λŠ” μŠ¬νΌν•˜κ² μ§€.
이 μ•ˆμ€ ν™”λ₯Ό λ‚Ό κ±°μ•Ό.
메이 μ‹œλŠ” μ–΄μ©Œλ©΄ μ‘°κΈˆμ€ 생각 ν•΄ μ£Όμ§€ μ•Šμ„κΉŒ.
μ€‘μš”ν•œ 건 그건 λ„€κ°€ μ§€ν‚€κ³  μ‹Άμ–΄ ν–ˆλ˜ μ‚¬λžŒλ“€μ΄μž–μ•„.
μ–΄μ„œ κ°€.
Method: text.split(" ")
EM score: 0.06742
F1 score: 0.54083

Output:
κΈ°μ–΅ν•΄.
λ„Œ
κ·Έ
μ• μ˜
μΉœκ΅¬μ•Ό.
λ„€κ°€
죽으면
λ§ˆλ“€λ ˆλŠκ°€
νŽ‘νŽ‘
μšΈκ±°μ•Ό.
λΉ„μ²΄λŠ”
μŠ¬νΌν•˜κ² μ§€.
μ΄μ•ˆμ€
ν™”λ₯Ό
λ‚Όκ±°μ•Ό.
λ©”μ΄μ‹œλŠ”
μ–΄μ©Œλ©΄
μ‘°κΈˆμ€
생각
ν•΄μ£Όμ§€
μ•Šμ„κΉŒ.
μ€‘μš”ν•œκ±΄
그건
λ„€κ°€
μ§€ν‚€κ³ 
μ‹Άμ–΄ν–ˆλ˜
μ‚¬λžŒλ“€μ΄μž–μ•„.
μ–΄μ„œ
κ°€.

This means that the F1 score has the huge advantages for method that cut sentences too finely. Of course, measuring the performance of the sentence segmentation algorithm is difficult, and we need to think more about metrics. However, the character level F1 score may cause users to misunderstand the tool's real performance. So I have more confidence in the EM score, which is a somewhat clunky but safe metric.


5) Where does the difference in performance come from? (Qualitative Analysis)

It is meaningless to simply compare them by number. I definitely want you to see the segmentation results. Let's take blogs_ko samples as examples, and compare performance of each library. For this, I will take the best backend of each library (Kss=mecab, Koalanlp=KKMA), because looking results of all backends may make you tired.

Example 1

  • Input text
거제 λ‚΄λ €κ°€λŠ” 길에 νœ΄κ²Œμ†Œλ₯Ό λ“€λ ΈλŠ”λ° μƒˆλ‘œ μƒκ²Όλ‚˜λ³΄λ”λΌκ΅¬μš”!? λ‚¨νŽΈκ³Ό μ €, λ‘˜ λ‹€ λΉ΅λŸ¬λ²„λΌ μ§€λ‚˜μΉ  수 μ—†μ–΄ ꡬ맀해 λ¨Ήμ–΄λ΄€λ‹΅λ‹ˆλ‹ΉπŸ˜Š λ³΄μ„±λ…Ήμ°¨νœ΄κ²Œμ†Œ μ•ˆμœΌλ‘œ λ“€μ–΄μ˜€μ‹œλ©΄ λ”± κ°€μš΄λ° μœ„μΉ˜ν•΄ μžˆμ–΄μš”γ…Žγ…Ž κ·Έλž˜μ„œ μ–΄λŠ λ¬ΈμœΌλ‘œλΌλ„ λ“€μ–΄μ˜€μ…”λ„ κ°€κΉλ‹΅λ‹ˆλ‹€πŸ˜‰ λ©”λ‰΄νŒμ„ 이렇고, 가격은 2000원~3000원 사이에 ν˜•μ„± λ˜μ–΄ μžˆμ–΄μš”! 이런거 ν•˜λ‚˜ν•˜λ‚˜ λ§›λ³΄λŠ”κ±° λ„ˆλ¬΄ μ’‹μ•„ν•˜λŠ”λ°... μ§„μ •ν•˜κ³  μ†Œλ―Έλ―Έ 단νŒ₯λΉ΅ ν•˜λ‚˜, μ˜₯수수 치즈빡 ν•˜λ‚˜, ꡬ리볼 ν•˜λ‚˜ κ³¨λžμŠ΅λ‹ˆλ‹€! λ‹€μŒμ— κ°€λ©΄ κ°•λ‚­μ½©μ΄λž‘ λ°€ κΌ­ λ¨Ήμ–΄λ΄μ•Όκ² μ–΄μš”πŸ˜™
  • Label
거제 λ‚΄λ €κ°€λŠ” 길에 νœ΄κ²Œμ†Œλ₯Ό λ“€λ ΈλŠ”λ° μƒˆλ‘œ μƒκ²Όλ‚˜λ³΄λ”λΌκ΅¬μš”!?
λ‚¨νŽΈκ³Ό μ €, λ‘˜ λ‹€ λΉ΅λŸ¬λ²„λΌ μ§€λ‚˜μΉ  수 μ—†μ–΄ ꡬ맀해 λ¨Ήμ–΄λ΄€λ‹΅λ‹ˆλ‹ΉπŸ˜Š
λ³΄μ„±λ…Ήμ°¨νœ΄κ²Œμ†Œ μ•ˆμœΌλ‘œ λ“€μ–΄μ˜€μ‹œλ©΄ λ”± κ°€μš΄λ° μœ„μΉ˜ν•΄ μžˆμ–΄μš”γ…Žγ…Ž
κ·Έλž˜μ„œ μ–΄λŠ λ¬ΈμœΌλ‘œλΌλ„ λ“€μ–΄μ˜€μ…”λ„ κ°€κΉλ‹΅λ‹ˆλ‹€πŸ˜‰
λ©”λ‰΄νŒμ„ 이렇고, 가격은 2000원~3000원 사이에 ν˜•μ„± λ˜μ–΄ μžˆμ–΄μš”!
이런거 ν•˜λ‚˜ν•˜λ‚˜ λ§›λ³΄λŠ”κ±° λ„ˆλ¬΄ μ’‹μ•„ν•˜λŠ”λ°... μ§„μ •ν•˜κ³  μ†Œλ―Έλ―Έ 단νŒ₯λΉ΅ ν•˜λ‚˜, μ˜₯수수 치즈빡 ν•˜λ‚˜, ꡬ리볼 ν•˜λ‚˜ κ³¨λžμŠ΅λ‹ˆλ‹€!
λ‹€μŒμ— κ°€λ©΄ κ°•λ‚­μ½©μ΄λž‘ λ°€ κΌ­ λ¨Ήμ–΄λ΄μ•Όκ² μ–΄μš”πŸ˜™
  • Source

https://hi-e2e2.tistory.com/193

  • Output texts
Baseline:

거제 λ‚΄λ €κ°€λŠ” 길에 νœ΄κ²Œμ†Œλ₯Ό λ“€λ ΈλŠ”λ° μƒˆλ‘œ μƒκ²Όλ‚˜λ³΄λ”λΌκ΅¬μš”!?
λ‚¨νŽΈκ³Ό μ €, λ‘˜ λ‹€ λΉ΅λŸ¬λ²„λΌ μ§€λ‚˜μΉ  수 μ—†μ–΄ ꡬ맀해 λ¨Ήμ–΄λ΄€λ‹΅λ‹ˆλ‹ΉπŸ˜Š λ³΄μ„±λ…Ήμ°¨νœ΄κ²Œμ†Œ μ•ˆμœΌλ‘œ λ“€μ–΄μ˜€μ‹œλ©΄ λ”± κ°€μš΄λ° μœ„μΉ˜ν•΄ μžˆμ–΄μš”γ…Žγ…Ž κ·Έλž˜μ„œ μ–΄λŠ λ¬ΈμœΌλ‘œλΌλ„ λ“€μ–΄μ˜€μ…”λ„ κ°€κΉλ‹΅λ‹ˆλ‹€πŸ˜‰ λ©”λ‰΄νŒμ„ 이렇고, 가격은 2000원~3000원 사이에 ν˜•μ„± λ˜μ–΄ μžˆμ–΄μš”!
이런거 ν•˜λ‚˜ν•˜λ‚˜ λ§›λ³΄λŠ”κ±° λ„ˆλ¬΄ μ’‹μ•„ν•˜λŠ”λ°...
μ§„μ •ν•˜κ³  μ†Œλ―Έλ―Έ 단νŒ₯λΉ΅ ν•˜λ‚˜, μ˜₯수수 치즈빡 ν•˜λ‚˜, ꡬ리볼 ν•˜λ‚˜ κ³¨λžμŠ΅λ‹ˆλ‹€!
λ‹€μŒμ— κ°€λ©΄ κ°•λ‚­μ½©μ΄λž‘ λ°€ κΌ­ λ¨Ήμ–΄λ΄μ•Όκ² μ–΄μš”πŸ˜™

Baseline separates input text into 5 sentences. First of all, the first sentence was separated well because it has final symbols. However, since these final symbols don't appear from the second sentence, you can see that these sentences were not separated well.

Koalanlp (KKMA):

거제 λ‚΄λ €κ°€λŠ” 길에 휴게 μ†Œλ₯Ό λ“€λ ΈλŠ”λ° μƒˆλ‘œ μƒκ²Όλ‚˜
λ³΄λ”λΌκ΅¬μš”!?
λ‚¨νŽΈκ³Ό μ €, λ‘˜ λ‹€ λΉ΅ λŸ¬λ²„λΌ μ§€λ‚˜μΉ  수 μ—†μ–΄ ꡬ맀해 λ¨Ήμ–΄ λ΄€λ‹΅λ‹ˆλ‹Ή
😊 보성 λ…Ήμ°¨ νœ΄κ²Œμ†Œ μ•ˆμœΌλ‘œ λ“€μ–΄μ˜€μ‹œλ©΄ λ”± κ°€μš΄λ° μœ„μΉ˜ν•΄ μžˆμ–΄μš”
γ…Žγ…Ž κ·Έλž˜μ„œ μ–΄λŠ 문으둜 라도 λ“€μ–΄μ˜€μ…”λ„ κ°€κΉλ‹΅λ‹ˆλ‹€
πŸ˜‰ λ©”λ‰΄νŒμ„ 이렇고, 가격은 2000원 ~3000 원 사이에 ν˜•μ„± λ˜μ–΄ μžˆμ–΄μš”!
이런 κ±° ν•˜λ‚˜ν•˜λ‚˜ λ§›λ³΄λŠ” κ±° λ„ˆλ¬΄ μ’‹μ•„ν•˜λŠ”λ°... μ§„μ •ν•˜κ³  μ†Œλ―Έ λ―Έ 단νŒ₯λΉ΅ ν•˜λ‚˜, μ˜₯수수 치즈 λΉ΅ ν•˜λ‚˜, ꡬ리 λ³Ό ν•˜λ‚˜ κ³¨λžμŠ΅λ‹ˆλ‹€!
λ‹€μŒμ— κ°€λ©΄ κ°•λ‚­μ½©μ΄λž‘ λ°€ κΌ­ λ¨Ήμ–΄λ΄μ•Όκ² μ–΄μš”πŸ˜™

Koalanlp splits sentences better than baseline because it uses morphological information. It splits input text into 8 sentences in total. But many mispartitions still exist. The first thing that catches your eye is the immature emoji handling. People usually put emojis at the end of a sentence, and in this case, the emojis should be included in the sentence. The second thing is the mispartition between μƒκ²Όλ‚˜ and λ³΄λ”λΌκ΅¬μš”!?. Probably this is because the KKMA morpheme analyzer recognized μƒκ²Όλ‚˜ as a final eomi (μ’…κ²°μ–΄λ―Έ). but it's a connecting eomi (μ—°κ²°μ–΄λ―Έ). This is because the performance of the morpheme analyzer. Rather, the baseline is a little safer in this area.

Kiwi:

거제 λ‚΄λ €κ°€λŠ” 길에 νœ΄κ²Œμ†Œλ₯Ό λ“€λ ΈλŠ”λ° μƒˆλ‘œ μƒκ²Όλ‚˜λ³΄λ”λΌκ΅¬μš”!?
λ‚¨νŽΈκ³Ό μ €, λ‘˜ λ‹€ λΉ΅λŸ¬λ²„λΌ μ§€λ‚˜μΉ  수 μ—†μ–΄ ꡬ맀해 λ¨Ήμ–΄λ΄€λ‹΅λ‹ˆλ‹ΉπŸ˜Š
λ³΄μ„±λ…Ήμ°¨νœ΄κ²Œμ†Œ μ•ˆμœΌλ‘œ λ“€μ–΄μ˜€μ‹œλ©΄ λ”± κ°€μš΄λ° μœ„μΉ˜ν•΄ μžˆμ–΄μš”γ…Žγ…Ž
κ·Έλž˜μ„œ μ–΄λŠ λ¬ΈμœΌλ‘œλΌλ„ λ“€μ–΄μ˜€μ…”λ„ κ°€κΉλ‹΅λ‹ˆλ‹€πŸ˜‰ λ©”λ‰΄νŒμ„ 이렇고, 가격은 2000원~3000원 사이에 ν˜•μ„± λ˜μ–΄ μžˆμ–΄μš”!
이런거 ν•˜λ‚˜ν•˜λ‚˜ λ§›λ³΄λŠ”κ±° λ„ˆλ¬΄ μ’‹μ•„ν•˜λŠ”λ°...
μ§„μ •ν•˜κ³  μ†Œλ―Έλ―Έ 단νŒ₯λΉ΅ ν•˜λ‚˜, μ˜₯수수 치즈빡 ν•˜λ‚˜, ꡬ리볼 ν•˜λ‚˜ κ³¨λžμŠ΅λ‹ˆλ‹€!
λ‹€μŒμ— κ°€λ©΄ κ°•λ‚­μ½©μ΄λž‘ λ°€ κΌ­ λ¨Ήμ–΄λ΄μ•Όκ² μ–΄μš”πŸ˜™

Kiwi shows better performance than Koalanlp. It splits input text into 7 sentences. Most sentences are pretty good, but it doesn't split κ°€κΉλ‹΅λ‹ˆλ‹€πŸ˜‰ and λ©”λ‰΄νŒμ„. The second thing is it separates μ’‹μ•„ν•˜λŠ”λ°... and μ§„μ •ν•˜κ³ . This part may be recognized as an independent sentence depending on the viewer, but the author of the original article didn't write this as an independent sentence, but an embraced sentence (μ•ˆκΈ΄λ¬Έμž₯).

The original article was written like:

Kss (mecab):

거제 λ‚΄λ €κ°€λŠ” 길에 νœ΄κ²Œμ†Œλ₯Ό λ“€λ ΈλŠ”λ° μƒˆλ‘œ μƒκ²Όλ‚˜λ³΄λ”λΌκ΅¬μš”!?
λ‚¨νŽΈκ³Ό μ €, λ‘˜ λ‹€ λΉ΅λŸ¬λ²„λΌ μ§€λ‚˜μΉ  수 μ—†μ–΄ ꡬ맀해 λ¨Ήμ–΄λ΄€λ‹΅λ‹ˆλ‹ΉπŸ˜Š
λ³΄μ„±λ…Ήμ°¨νœ΄κ²Œμ†Œ μ•ˆμœΌλ‘œ λ“€μ–΄μ˜€μ‹œλ©΄ λ”± κ°€μš΄λ° μœ„μΉ˜ν•΄ μžˆμ–΄μš”γ…Žγ…Ž
κ·Έλž˜μ„œ μ–΄λŠ λ¬ΈμœΌλ‘œλΌλ„ λ“€μ–΄μ˜€μ…”λ„ κ°€κΉλ‹΅λ‹ˆλ‹€πŸ˜‰
λ©”λ‰΄νŒμ„ 이렇고, 가격은 2000원~3000원 사이에 ν˜•μ„± λ˜μ–΄ μžˆμ–΄μš”!
이런거 ν•˜λ‚˜ν•˜λ‚˜ λ§›λ³΄λŠ”κ±° λ„ˆλ¬΄ μ’‹μ•„ν•˜λŠ”λ°... μ§„μ •ν•˜κ³  μ†Œλ―Έλ―Έ 단νŒ₯λΉ΅ ν•˜λ‚˜, μ˜₯수수 치즈빡 ν•˜λ‚˜, ꡬ리볼 ν•˜λ‚˜ κ³¨λžμŠ΅λ‹ˆλ‹€!
λ‹€μŒμ— κ°€λ©΄ κ°•λ‚­μ½©μ΄λž‘ λ°€ κΌ­ λ¨Ήμ–΄λ΄μ•Όκ² μ–΄μš”πŸ˜™

The result of Kss is same with gold label. Especially it succesfully separates κ°€κΉλ‹΅λ‹ˆλ‹€πŸ˜‰ and λ©”λ‰΄νŒμ„. In fact, this part is the final eomi (μ’…κ²°μ–΄λ―Έ), but many morpheme analyzers confuse the final eomi (μ’…κ²°μ–΄λ―Έ) with the connecting eomi (μ—°κ²°μ–΄λ―Έ). Actually, mecab and pecab morpheme analyzers which are backend of Kss also recognizes that part as a connecting eomi (μ—°κ²°μ–΄λ―Έ). For this reason, Kss has a feature to recognize wrongly recognized connecting eomi (μ—°κ²°μ–΄λ―Έ) and to correct those eomis. Thus, it is able to separate this part effectively. Next, Kss doesn't split μ’‹μ•„ν•˜λŠ”λ°... and μ§„μ •ν•˜κ³  becuase μ’‹μ•„ν•˜λŠ”λ°... is not an independent sentence, but an embraced sentence (μ•ˆκΈ΄λ¬Έμž₯). This means Kss doesn't split sentences simply because . appears, unlike baseline. In most cases, . could be the delimiter of sentences, actually there are many exceptions about this.

Example 2

  • Input text
μ–΄λŠν™”μ°½ν•œλ‚  μΆœκ·Όμ „μ— λ„ˆλ¬΄μΌμ°μΌμ–΄λ‚˜ λ²„λ ΈμŒ (μΆœκ·Όμ‹œκ°„ 19μ‹œ) ν• κΊΌλ„μ—†κ³ ν•΄μ„œ 카페λ₯Ό μ°Ύμ•„ μ‹œλ‚΄λ‘œ λ‚˜κ°”μŒ μƒˆλ‘œμƒκΈ΄κ³³μ— 사μž₯λ‹˜μ΄ μ»€ν”Όμ„ μˆ˜μΈμ§€ 컀피박사라고 ν•΄μ„œ κ°”μŒ μ˜€ν”ˆν•œμ§€ μ–Όλ§ˆμ•ˆλ˜μ„œ κ·ΈλŸ°μ§€ μ†λ‹˜μ΄ μ–Όλ§ˆμ—†μ—ˆμŒ μ‘°μš©ν•˜κ³  μ’‹λ‹€λ©° μ’‹μ•„ν•˜λŠ”κ±Έμ‹œμΌœμ„œ ν…ŒλΌμŠ€μ— μ•‰μŒ 근데 μ‘°μš©ν•˜λ˜ μΉ΄νŽ˜κ°€ μ‚°λ§Œν•΄μ§ μ†Œλ¦¬μ˜ μΆœμ²˜λŠ” μΉ΄μš΄ν„°μ˜€μŒ(ν…ŒλΌμŠ€κ°€ μΉ΄μš΄ν„° λ°”λ‘œμ˜†) 듀을라고 λ“€μ€κ²Œ μ•„λ‹ˆλΌ κ·€λŠ” μ—΄λ €μžˆμœΌλ‹ˆ λ“£κ²Œλœ λŒ€μ‚¬.
  • Label
μ–΄λŠν™”μ°½ν•œλ‚  μΆœκ·Όμ „μ— λ„ˆλ¬΄μΌμ°μΌμ–΄λ‚˜ λ²„λ ΈμŒ (μΆœκ·Όμ‹œκ°„ 19μ‹œ)
ν• κΊΌλ„μ—†κ³ ν•΄μ„œ 카페λ₯Ό μ°Ύμ•„ μ‹œλ‚΄λ‘œ λ‚˜κ°”μŒ
μƒˆλ‘œμƒκΈ΄κ³³μ— 사μž₯λ‹˜μ΄ μ»€ν”Όμ„ μˆ˜μΈμ§€ 컀피박사라고 ν•΄μ„œ κ°”μŒ
μ˜€ν”ˆν•œμ§€ μ–Όλ§ˆμ•ˆλ˜μ„œ κ·ΈλŸ°μ§€ μ†λ‹˜μ΄ μ–Όλ§ˆμ—†μ—ˆμŒ
μ‘°μš©ν•˜κ³  μ’‹λ‹€λ©° μ’‹μ•„ν•˜λŠ”κ±Έμ‹œμΌœμ„œ ν…ŒλΌμŠ€μ— μ•‰μŒ
근데 μ‘°μš©ν•˜λ˜ μΉ΄νŽ˜κ°€ μ‚°λ§Œν•΄μ§
μ†Œλ¦¬μ˜ μΆœμ²˜λŠ” μΉ΄μš΄ν„°μ˜€μŒ(ν…ŒλΌμŠ€κ°€ μΉ΄μš΄ν„° λ°”λ‘œμ˜†)
듀을라고 λ“€μ€κ²Œ μ•„λ‹ˆλΌ κ·€λŠ” μ—΄λ €μžˆμœΌλ‹ˆ λ“£κ²Œλœ λŒ€μ‚¬.
  • Source

https://mrsign92.tistory.com/6099371

  • Output texts
Baseline:

μ–΄λŠν™”μ°½ν•œλ‚  μΆœκ·Όμ „μ— λ„ˆλ¬΄μΌμ°μΌμ–΄λ‚˜ λ²„λ ΈμŒ (μΆœκ·Όμ‹œκ°„ 19μ‹œ) ν• κΊΌλ„μ—†κ³ ν•΄μ„œ 카페λ₯Ό μ°Ύμ•„ μ‹œλ‚΄λ‘œ λ‚˜κ°”μŒ μƒˆλ‘œμƒκΈ΄κ³³μ— 사μž₯λ‹˜μ΄ μ»€ν”Όμ„ μˆ˜μΈμ§€ 컀피박사라고 ν•΄μ„œ κ°”μŒ μ˜€ν”ˆν•œμ§€ μ–Όλ§ˆμ•ˆλ˜μ„œ κ·ΈλŸ°μ§€ μ†λ‹˜μ΄ μ–Όλ§ˆμ—†μ—ˆμŒ μ‘°μš©ν•˜κ³  μ’‹λ‹€λ©° μ’‹μ•„ν•˜λŠ”κ±Έμ‹œμΌœμ„œ ν…ŒλΌμŠ€μ— μ•‰μŒ 근데 μ‘°μš©ν•˜λ˜ μΉ΄νŽ˜κ°€ μ‚°λ§Œν•΄μ§ μ†Œλ¦¬μ˜ μΆœμ²˜λŠ” μΉ΄μš΄ν„°μ˜€μŒ(ν…ŒλΌμŠ€κ°€ μΉ΄μš΄ν„° λ°”λ‘œμ˜†) 듀을라고 λ“€μ€κ²Œ μ•„λ‹ˆλΌ κ·€λŠ” μ—΄λ €μžˆμœΌλ‹ˆ λ“£κ²Œλœ λŒ€μ‚¬.

Baseline doesn't split any sentences because there's no .!? in the input text.

Koalanlp (KKMA)

μ–΄λŠ ν™”μ°½ν•œ λ‚  좜근 전에 λ„ˆλ¬΄ 일찍 μΌμ–΄λ‚˜ λ²„λ ΈμŒ ( μΆœκ·Όμ‹œκ°„ 19μ‹œ) ν•  꺼도 μ—†κ³  ν•΄μ„œ 카페λ₯Ό μ°Ύμ•„ μ‹œλ‚΄λ‘œ λ‚˜κ°”μŒ μƒˆλ‘œ 생긴 곳에 사μž₯λ‹˜μ΄ μ»€ν”Όμ„ μˆ˜μΈμ§€ 컀피박사라고 ν•΄μ„œ κ°”μŒ μ˜€ν”ˆν•œμ§€ μ–Όλ§ˆ μ•ˆ 되 μ„œ κ·ΈλŸ°μ§€ μ†λ‹˜μ΄ μ–Όλ§ˆ μ—†μ—ˆμŒ μ‘°μš©ν•˜κ³  μ’‹λ‹€λ©° μ’‹μ•„ν•˜λŠ” κ±Έ μ‹œμΌœμ„œ ν…ŒλΌμŠ€μ— μ•‰μŒ 근데 μ‘°μš©ν•˜λ˜ μΉ΄νŽ˜κ°€ μ‚°λ§Œ 해짐 μ†Œλ¦¬μ˜ μΆœμ²˜λŠ” μΉ΄μš΄ν„°μ˜€μŒ( ν…ŒλΌμŠ€κ°€ μΉ΄μš΄ν„° λ°”λ‘œ μ˜†) 듀을라고
듀은 게 μ•„λ‹ˆλΌ κ·€λŠ” μ—΄λ € μžˆμœΌλ‹ˆ λ“£κ²Œ 된 λŒ€μ‚¬.

Koalanlp separates 듀을라고 and 듀은 but it is not correct split point. And I think it doesn't consider predicative use of eomi transferred from noun (λͺ…μ‚¬ν˜• μ „μ„±μ–΄λ―Έμ˜ μ„œμˆ μ  μš©λ²•).

Kiwi

μ–΄λŠν™”μ°½ν•œλ‚  μΆœκ·Όμ „μ— λ„ˆλ¬΄μΌμ°μΌμ–΄λ‚˜ λ²„λ ΈμŒ (μΆœκ·Όμ‹œκ°„ 19μ‹œ) ν• κΊΌλ„μ—†κ³ ν•΄μ„œ 카페λ₯Ό μ°Ύμ•„ μ‹œλ‚΄λ‘œ λ‚˜κ°”μŒ μƒˆλ‘œμƒκΈ΄κ³³μ— 사μž₯λ‹˜μ΄ μ»€ν”Όμ„ μˆ˜μΈμ§€ 컀피박사라고 ν•΄μ„œ κ°”μŒ μ˜€ν”ˆν•œμ§€ μ–Όλ§ˆμ•ˆλ˜μ„œ κ·ΈλŸ°μ§€ μ†λ‹˜μ΄ μ–Όλ§ˆμ—†μ—ˆμŒ μ‘°μš©ν•˜κ³  μ’‹λ‹€λ©° μ’‹μ•„ν•˜λŠ”κ±Έμ‹œμΌœμ„œ ν…ŒλΌμŠ€μ— μ•‰μŒ 근데 μ‘°μš©ν•˜λ˜ μΉ΄νŽ˜κ°€ μ‚°λ§Œν•΄μ§ μ†Œλ¦¬μ˜ μΆœμ²˜λŠ” μΉ΄μš΄ν„°μ˜€μŒ(ν…ŒλΌμŠ€κ°€ μΉ΄μš΄ν„° λ°”λ‘œμ˜†) 듀을라고 λ“€μ€κ²Œ μ•„λ‹ˆλΌ κ·€λŠ” μ—΄λ €μžˆμœΌλ‹ˆ λ“£κ²Œλœ λŒ€μ‚¬.

Kiwi doesn't separate any sentence, similar with baseline. Similarly, it doesn't consider predicative use of eomi transferred from noun (λͺ…μ‚¬ν˜• μ „μ„±μ–΄λ―Έμ˜ μ„œμˆ μ  μš©λ²•).

Kss (Mecab)

μ–΄λŠν™”μ°½ν•œλ‚  μΆœκ·Όμ „μ— λ„ˆλ¬΄μΌμ°μΌμ–΄λ‚˜ λ²„λ ΈμŒ (μΆœκ·Όμ‹œκ°„ 19μ‹œ)
ν• κΊΌλ„μ—†κ³ ν•΄μ„œ 카페λ₯Ό μ°Ύμ•„ μ‹œλ‚΄λ‘œ λ‚˜κ°”μŒ
μƒˆλ‘œμƒκΈ΄κ³³μ— 사μž₯λ‹˜μ΄ μ»€ν”Όμ„ μˆ˜μΈμ§€ 컀피박사라고 ν•΄μ„œ κ°”μŒ
μ˜€ν”ˆν•œμ§€ μ–Όλ§ˆμ•ˆλ˜μ„œ κ·ΈλŸ°μ§€ μ†λ‹˜μ΄ μ–Όλ§ˆμ—†μ—ˆμŒ
μ‘°μš©ν•˜κ³  μ’‹λ‹€λ©° μ’‹μ•„ν•˜λŠ”κ±Έμ‹œμΌœμ„œ ν…ŒλΌμŠ€μ— μ•‰μŒ
근데 μ‘°μš©ν•˜λ˜ μΉ΄νŽ˜κ°€ μ‚°λ§Œν•΄μ§ μ†Œλ¦¬μ˜ μΆœμ²˜λŠ” μΉ΄μš΄ν„°μ˜€μŒ(ν…ŒλΌμŠ€κ°€ μΉ΄μš΄ν„° λ°”λ‘œμ˜†)
듀을라고 λ“€μ€κ²Œ μ•„λ‹ˆλΌ κ·€λŠ” μ—΄λ €μžˆμœΌλ‹ˆ λ“£κ²Œλœ λŒ€μ‚¬.

The result of Kss is very similar with gold label, Kss considers predicative use of eomi transferred from noun (λͺ…μ‚¬ν˜• μ „μ„±μ–΄λ―Έμ˜ μ„œμˆ μ  μš©λ²•). But Kss couldn't split μ‚°λ§Œν•΄μ§ and μ†Œλ¦¬μ˜. That part is a correct split point, but it was blocked by one of the exceptions which I built to prevent wrong segmentation. Splitting eomi transferred from noun (λͺ…μ‚¬ν˜• μ „μ„±μ–΄λ―Έ) is one of the unsafe and difficult tasks, so Kss has many exceptions to prevent wrong segmentation.

Example 3

  • Input text
μ±…μ†Œκ°œμ— 이건 μ†Œμ„€μΈκ°€ μ‹€μ œμΈκ°€λΌλŠ” 문ꡬλ₯Ό 보고 μž¬λ°Œκ² λ‹€ μ‹Άμ–΄ 보게 λ˜μ—ˆλ‹€. '바카라'λΌλŠ” 도박은 2μž₯의 μΉ΄λ“œ 합이 높은 μ‚¬λžŒμ΄ μ΄κΈ°λŠ” κ²Œμž„μœΌλ‘œ μ•„μ£Ό λ‹¨μˆœν•œ κ²Œμž„μ΄λ‹€. 이런게 쀑독이 λ˜λ‚˜? μ‹Άμ—ˆλŠ”λ° 이 책이 바카라와 λΉ„μŠ·ν•œ λ§€λ ₯이 μžˆλ‹€ μƒκ°λ“€μ—ˆλ‹€. λ‚΄μš©μ΄ μŠ€ν”Όλ“œν•˜κ²Œ μ§„ν–‰λ˜κ³  λ§‰νžˆλŠ” ꡬ간없이 μ½νžˆλŠ”κ²Œ λ‚˜λ„ λͺ¨λ₯΄κ²Œ νŽ˜μ΄μ§€λ₯Ό μŠ₯μŠ₯ λ„˜κΈ°κ³  μžˆμ—ˆλ‹€. λ¬Όλ‘  읽음으둜써 큰 λˆμ„ λ²Œμ§„ μ•Šμ§€λ§Œ 이런 μŠ€ν”Όλ“œν•¨μ— λ‚˜λ„ λͺ¨λ₯΄κ²Œ 계속 κ²Œμž„μ— μ°Έμ—¬ν•˜κ²Œ 되고 λ‚˜μ˜€λŠ” 타이밍을 μž‘μ§€ λͺ»ν•΄ λΉ μ§€μ§€ μ•Šμ•˜μ„κΉŒ? λΌλŠ” 생각을 ν•˜κ²Œ 됐닀. 이 μ±…μ—μ„œ ν˜„μ§€μ˜ κΏˆμ€ κ°€κ²©ν‘œλ₯Ό 보지 μ•ŠλŠ” 삢이라 ν•œλ‹€. 이 뢀뢄을 읽고 λ‚˜λˆλ°! λΌλŠ” μƒκ°ν•˜λ©΄μ„œ μˆœκ°„ λ„λ°•μ΄λΌλŠ”κ±Έλ‘œλΌλ„ λˆμ„ 많이 λ²Œμ—ˆλ˜ ν˜„μ§€κ°€ λΆ€λŸ¬μ› λ‹€. κ·ΈλŸ¬λ©΄μ„œ λ‚΄κ°€ 도박을 ν–ˆλ‹€λ©΄?λΌλŠ” 상상을 ν•΄λ΄€λ‹€. 그리고 이런 상상을 ν•  수 있게 λ§Œλ“€μ–΄μ€˜μ„œ 이 책이 더 재밌게 λ‹€κ°€μ™”λ‹€. 일상에 지루함을 느껴 도박같은 삢을 μ‚΄κ³ μ‹Άλ‹€λ©΄ λ„λ°•ν•˜μ§€λ§κ³  차라리 이 책을 보길^^γ…‹ 
  • Label
μ±…μ†Œκ°œμ— 이건 μ†Œμ„€μΈκ°€ μ‹€μ œμΈκ°€λΌλŠ” 문ꡬλ₯Ό 보고 μž¬λ°Œκ² λ‹€ μ‹Άμ–΄ 보게 λ˜μ—ˆλ‹€.
'바카라'λΌλŠ” 도박은 2μž₯의 μΉ΄λ“œ 합이 높은 μ‚¬λžŒμ΄ μ΄κΈ°λŠ” κ²Œμž„μœΌλ‘œ μ•„μ£Ό λ‹¨μˆœν•œ κ²Œμž„μ΄λ‹€.
이런게 쀑독이 λ˜λ‚˜? μ‹Άμ—ˆλŠ”λ° 이 책이 바카라와 λΉ„μŠ·ν•œ λ§€λ ₯이 μžˆλ‹€ μƒκ°λ“€μ—ˆλ‹€.
λ‚΄μš©μ΄ μŠ€ν”Όλ“œν•˜κ²Œ μ§„ν–‰λ˜κ³  λ§‰νžˆλŠ” ꡬ간없이 μ½νžˆλŠ”κ²Œ λ‚˜λ„ λͺ¨λ₯΄κ²Œ νŽ˜μ΄μ§€λ₯Ό μŠ₯μŠ₯ λ„˜κΈ°κ³  μžˆμ—ˆλ‹€.
λ¬Όλ‘  읽음으둜써 큰 λˆμ„ λ²Œμ§„ μ•Šμ§€λ§Œ 이런 μŠ€ν”Όλ“œν•¨μ— λ‚˜λ„ λͺ¨λ₯΄κ²Œ 계속 κ²Œμž„μ— μ°Έμ—¬ν•˜κ²Œ 되고 λ‚˜μ˜€λŠ” 타이밍을 μž‘μ§€ λͺ»ν•΄ λΉ μ§€μ§€ μ•Šμ•˜μ„κΉŒ? λΌλŠ” 생각을 ν•˜κ²Œ 됐닀.
이 μ±…μ—μ„œ ν˜„μ§€μ˜ κΏˆμ€ κ°€κ²©ν‘œλ₯Ό 보지 μ•ŠλŠ” 삢이라 ν•œλ‹€.
이 뢀뢄을 읽고 λ‚˜λˆλ°! λΌλŠ” μƒκ°ν•˜λ©΄μ„œ μˆœκ°„ λ„λ°•μ΄λΌλŠ”κ±Έλ‘œλΌλ„ λˆμ„ 많이 λ²Œμ—ˆλ˜ ν˜„μ§€κ°€ λΆ€λŸ¬μ› λ‹€.
κ·ΈλŸ¬λ©΄μ„œ λ‚΄κ°€ 도박을 ν–ˆλ‹€λ©΄?λΌλŠ” 상상을 ν•΄λ΄€λ‹€.
그리고 이런 상상을 ν•  수 있게 λ§Œλ“€μ–΄μ€˜μ„œ 이 책이 더 재밌게 λ‹€κ°€μ™”λ‹€.
일상에 지루함을 느껴 도박같은 삢을 μ‚΄κ³ μ‹Άλ‹€λ©΄ λ„λ°•ν•˜μ§€λ§κ³  차라리 이 책을 보길^^γ…‹ 
  • Source

https://hi-e2e2.tistory.com/63

  • Output texts
Baseline:

μ±…μ†Œκ°œμ— 이건 μ†Œμ„€μΈκ°€ μ‹€μ œμΈκ°€λΌλŠ” 문ꡬλ₯Ό 보고 μž¬λ°Œκ² λ‹€ μ‹Άμ–΄ 보게 λ˜μ—ˆλ‹€.
'바카라'λΌλŠ” 도박은 2μž₯의 μΉ΄λ“œ 합이 높은 μ‚¬λžŒμ΄ μ΄κΈ°λŠ” κ²Œμž„μœΌλ‘œ μ•„μ£Ό λ‹¨μˆœν•œ κ²Œμž„μ΄λ‹€.
이런게 쀑독이 λ˜λ‚˜?
μ‹Άμ—ˆλŠ”λ° 이 책이 바카라와 λΉ„μŠ·ν•œ λ§€λ ₯이 μžˆλ‹€ μƒκ°λ“€μ—ˆλ‹€.
λ‚΄μš©μ΄ μŠ€ν”Όλ“œν•˜κ²Œ μ§„ν–‰λ˜κ³  λ§‰νžˆλŠ” ꡬ간없이 μ½νžˆλŠ”κ²Œ λ‚˜λ„ λͺ¨λ₯΄κ²Œ νŽ˜μ΄μ§€λ₯Ό μŠ₯μŠ₯ λ„˜κΈ°κ³  μžˆμ—ˆλ‹€.
λ¬Όλ‘  읽음으둜써 큰 λˆμ„ λ²Œμ§„ μ•Šμ§€λ§Œ 이런 μŠ€ν”Όλ“œν•¨μ— λ‚˜λ„ λͺ¨λ₯΄κ²Œ 계속 κ²Œμž„μ— μ°Έμ—¬ν•˜κ²Œ 되고 λ‚˜μ˜€λŠ” 타이밍을 μž‘μ§€ λͺ»ν•΄ λΉ μ§€μ§€ μ•Šμ•˜μ„κΉŒ?
λΌλŠ” 생각을 ν•˜κ²Œ 됐닀.
이 μ±…μ—μ„œ ν˜„μ§€μ˜ κΏˆμ€ κ°€κ²©ν‘œλ₯Ό 보지 μ•ŠλŠ” 삢이라 ν•œλ‹€.
이 뢀뢄을 읽고 λ‚˜λˆλ°!
λΌλŠ” μƒκ°ν•˜λ©΄μ„œ μˆœκ°„ λ„λ°•μ΄λΌλŠ”κ±Έλ‘œλΌλ„ λˆμ„ 많이 λ²Œμ—ˆλ˜ ν˜„μ§€κ°€ λΆ€λŸ¬μ› λ‹€.
κ·ΈλŸ¬λ©΄μ„œ λ‚΄κ°€ 도박을 ν–ˆλ‹€λ©΄?λΌλŠ” 상상을 ν•΄λ΄€λ‹€.
그리고 이런 상상을 ν•  수 있게 λ§Œλ“€μ–΄μ€˜μ„œ 이 책이 더 재밌게 λ‹€κ°€μ™”λ‹€.
일상에 지루함을 느껴 도박같은 삢을 μ‚΄κ³ μ‹Άλ‹€λ©΄ λ„λ°•ν•˜μ§€λ§κ³  차라리 이 책을 보길^^γ…‹ 

Baseline separates input text into 13 sentences. You can see it can't distinguish final eomi(μ’…κ²°μ–΄λ―Έ) and connecting eomi(μ—°κ²°μ–΄λ―Έ), for example it splits 이런게 쀑독이 λ˜λ‚˜? and μ‹Άμ—ˆλŠ”λ°. But λ˜λ‚˜? is connecting eomi (μ—°κ²°μ–΄λ―Έ). And here's one more problem. It doesn't recognize embraced sentences (μ•ˆκΈ΄λ¬Έμž₯). For example it splits λͺ»ν•΄ λΉ μ§€μ§€ μ•Šμ•˜μ„κΉŒ? and λΌλŠ” 생각을 ν•˜κ²Œ 됐닀..

Koalanlp (KKMA)

μ±… μ†Œκ°œμ— 이건 μ†Œμ„€μΈκ°€ μ‹€μ œ μΈκ°€λΌλŠ” 문ꡬλ₯Ό 보고 μž¬λ°Œκ² λ‹€ μ‹Άμ–΄ 보게 λ˜μ—ˆλ‹€.
' 바카라' λΌλŠ” 도박은 2 μž₯의 μΉ΄λ“œ 합이 높은 μ‚¬λžŒμ΄ μ΄κΈ°λŠ” κ²Œμž„μœΌλ‘œ μ•„μ£Ό λ‹¨μˆœν•œ κ²Œμž„μ΄λ‹€.
이런 게 쀑독이 λ˜λ‚˜?
μ‹Άμ—ˆλŠ”λ° 이 책이 바카라와 λΉ„μŠ·ν•œ λ§€λ ₯이 μžˆλ‹€ 생각 λ“€μ—ˆλ‹€.
λ‚΄μš©μ΄ μŠ€ν”Όλ“œν•˜κ²Œ μ§„ν–‰λ˜κ³  λ§‰νžˆλŠ” ꡬ간 없이 μ½νžˆλŠ” 게 λ‚˜λ„ λͺ¨λ₯΄κ²Œ νŽ˜μ΄μ§€λ₯Ό μŠ₯μŠ₯ λ„˜κΈ°κ³  μžˆμ—ˆλ‹€.
λ¬Όλ‘  읽음으둜써 큰 λˆμ„ λ²Œμ§„ μ•Šμ§€λ§Œ 이런 μŠ€ν”Όλ“œν•¨μ— λ‚˜λ„ λͺ¨λ₯΄κ²Œ 계속 κ²Œμž„μ— μ°Έμ—¬ν•˜κ²Œ 되고 λ‚˜μ˜€λŠ” 타이밍을 μž‘μ§€ λͺ»ν•΄ λΉ μ§€μ§€ μ•Šμ•˜μ„κΉŒ?
λΌλŠ” 생각을 ν•˜κ²Œ 됐닀.
이 μ±…μ—μ„œ ν˜„μ§€μ˜ κΏˆμ€ κ°€κ²©ν‘œλ₯Ό 보지 μ•ŠλŠ” 삢이라 ν•œλ‹€.
이 뢀뢄을 읽고 λ‚˜λˆλ°!
λΌλŠ” μƒκ°ν•˜λ©΄μ„œ μˆœκ°„ λ„λ°•μ΄λΌλŠ” κ±Έλ‘œλΌλ„ λˆμ„ 많이 λ²Œμ—ˆλ˜ ν˜„μ§€κ°€ λΆ€λŸ¬μ› λ‹€.
κ·ΈλŸ¬λ©΄μ„œ λ‚΄κ°€ 도박을 ν–ˆλ‹€λ©΄? λΌλŠ” 상상을 ν•΄λ΄€λ‹€.
그리고 이런 상상을 ν•  수 있게 λ§Œλ“€μ–΄ μ€˜μ„œ 이 책이 더 재밌게 λ‹€κ°€μ™”λ‹€.
일상에 지루함을 느껴 도박 같은 삢을 μ‚΄κ³  μ‹Άλ‹€λ©΄ λ„λ°•ν•˜μ§€ 말고 차라리 이 책을 보길 ^^ γ…‹

The result of Koalanlp was really similar with baseline, the two problems (final-connecting eomi distinction, embracing sentences recognization) still exist.

Kiwi

μ±…μ†Œκ°œμ— 이건 μ†Œμ„€μΈκ°€ μ‹€μ œμΈκ°€
λΌλŠ” 문ꡬλ₯Ό 보고 μž¬λ°Œκ² λ‹€ μ‹Άμ–΄ 보게 λ˜μ—ˆλ‹€.
'바카라'λΌλŠ” 도박은 2μž₯의 μΉ΄λ“œ 합이 높은 μ‚¬λžŒμ΄ μ΄κΈ°λŠ” κ²Œμž„μœΌλ‘œ μ•„μ£Ό λ‹¨μˆœν•œ κ²Œμž„μ΄λ‹€.
이런게 쀑독이 λ˜λ‚˜?
μ‹Άμ—ˆλŠ”λ° 이 책이 바카라와 λΉ„μŠ·ν•œ λ§€λ ₯이 μžˆλ‹€ μƒκ°λ“€μ—ˆλ‹€.
λ‚΄μš©μ΄ μŠ€ν”Όλ“œν•˜κ²Œ μ§„ν–‰λ˜κ³  λ§‰νžˆλŠ” ꡬ간없이 μ½νžˆλŠ”κ²Œ λ‚˜λ„ λͺ¨λ₯΄κ²Œ νŽ˜μ΄μ§€λ₯Ό μŠ₯μŠ₯ λ„˜κΈ°κ³  μžˆμ—ˆλ‹€.
λ¬Όλ‘  읽음으둜써 큰 λˆμ„ λ²Œμ§„ μ•Šμ§€λ§Œ 이런 μŠ€ν”Όλ“œν•¨μ— λ‚˜λ„ λͺ¨λ₯΄κ²Œ 계속 κ²Œμž„μ— μ°Έμ—¬ν•˜κ²Œ 되고 λ‚˜μ˜€λŠ” 타이밍을 μž‘μ§€ λͺ»ν•΄ λΉ μ§€μ§€ μ•Šμ•˜μ„κΉŒ?
λΌλŠ” 생각을 ν•˜κ²Œ 됐닀.
이 μ±…μ—μ„œ ν˜„μ§€μ˜ κΏˆμ€ κ°€κ²©ν‘œλ₯Ό 보지 μ•ŠλŠ” 삢이라 ν•œλ‹€.
이 뢀뢄을 읽고 λ‚˜λˆλ°!
λΌλŠ” μƒκ°ν•˜λ©΄μ„œ μˆœκ°„ λ„λ°•μ΄λΌλŠ”κ±Έλ‘œλΌλ„ λˆμ„ 많이 λ²Œμ—ˆλ˜ ν˜„μ§€κ°€ λΆ€λŸ¬μ› λ‹€.
κ·ΈλŸ¬λ©΄μ„œ λ‚΄κ°€ 도박을 ν–ˆλ‹€λ©΄?
λΌλŠ” 상상을 ν•΄λ΄€λ‹€.
그리고 이런 상상을 ν•  수 있게 λ§Œλ“€μ–΄μ€˜μ„œ 이 책이 더 재밌게 λ‹€κ°€μ™”λ‹€.
일상에 지루함을 느껴 도박같은 삢을 μ‚΄κ³ μ‹Άλ‹€λ©΄ λ„λ°•ν•˜μ§€λ§κ³  차라리 이 책을 보길^^γ…‹

The two problems are also shown in result of Kiwi. And it additionally splits μ‹€μ œμΈκ°€ and λΌλŠ”, but 이건 μ†Œμ„€μΈκ°€ μ‹€μ œμΈκ°€ is not an independent sentence, but an embraced sentence (μ•ˆκΈ΄λ¬Έμž₯).

Kss (Mecab)

μ±…μ†Œκ°œμ— 이건 μ†Œμ„€μΈκ°€ μ‹€μ œμΈκ°€λΌλŠ” 문ꡬλ₯Ό 보고 μž¬λ°Œκ² λ‹€ μ‹Άμ–΄ 보게 λ˜μ—ˆλ‹€.
'바카라'λΌλŠ” 도박은 2μž₯의 μΉ΄λ“œ 합이 높은 μ‚¬λžŒμ΄ μ΄κΈ°λŠ” κ²Œμž„μœΌλ‘œ μ•„μ£Ό λ‹¨μˆœν•œ κ²Œμž„μ΄λ‹€.
이런게 쀑독이 λ˜λ‚˜? μ‹Άμ—ˆλŠ”λ° 이 책이 바카라와 λΉ„μŠ·ν•œ λ§€λ ₯이 μžˆλ‹€ μƒκ°λ“€μ—ˆλ‹€.
λ‚΄μš©μ΄ μŠ€ν”Όλ“œν•˜κ²Œ μ§„ν–‰λ˜κ³  λ§‰νžˆλŠ” ꡬ간없이 μ½νžˆλŠ”κ²Œ λ‚˜λ„ λͺ¨λ₯΄κ²Œ νŽ˜μ΄μ§€λ₯Ό μŠ₯μŠ₯ λ„˜κΈ°κ³  μžˆμ—ˆλ‹€.
λ¬Όλ‘  읽음으둜써 큰 λˆμ„ λ²Œμ§„ μ•Šμ§€λ§Œ 이런 μŠ€ν”Όλ“œν•¨μ— λ‚˜λ„ λͺ¨λ₯΄κ²Œ 계속 κ²Œμž„μ— μ°Έμ—¬ν•˜κ²Œ 되고 λ‚˜μ˜€λŠ” 타이밍을 μž‘μ§€ λͺ»ν•΄ λΉ μ§€μ§€ μ•Šμ•˜μ„κΉŒ? λΌλŠ” 생각을 ν•˜κ²Œ 됐닀.
이 μ±…μ—μ„œ ν˜„μ§€μ˜ κΏˆμ€ κ°€κ²©ν‘œλ₯Ό 보지 μ•ŠλŠ” 삢이라 ν•œλ‹€.
이 뢀뢄을 읽고 λ‚˜λˆλ°! λΌλŠ” μƒκ°ν•˜λ©΄μ„œ μˆœκ°„ λ„λ°•μ΄λΌλŠ”κ±Έλ‘œλΌλ„ λˆμ„ 많이 λ²Œμ—ˆλ˜ ν˜„μ§€κ°€ λΆ€λŸ¬μ› λ‹€.
κ·ΈλŸ¬λ©΄μ„œ λ‚΄κ°€ 도박을 ν–ˆλ‹€λ©΄?λΌλŠ” 상상을 ν•΄λ΄€λ‹€.
그리고 이런 상상을 ν•  수 있게 λ§Œλ“€μ–΄μ€˜μ„œ 이 책이 더 재밌게 λ‹€κ°€μ™”λ‹€.
일상에 지루함을 느껴 도박같은 삢을 μ‚΄κ³ μ‹Άλ‹€λ©΄ λ„λ°•ν•˜μ§€λ§κ³  차라리 이 책을 보길^^γ…‹

The result of Kss is same with gold label. This means that Kss considers the two problems. Of course, it's not easy to detect that parts while splitting sentences, so Kss has one more step after splitting sentences. It's postprocessing step which corrects some problems in segmenration results. For example, Korean sentence doesn't start from josa (쑰사) in general. Therefore if segmented results (sentences) started from josa (쑰사), Kss recognizes them as embraced sentences (μ•ˆκΈ΄λ¬Έμž₯), and attaches them to their previous sentence. For your information, Kss has many more powerful postprocessing algorithms which correct wrong segmentation results like this.

In conclusion, Kss considers more than other libraries in Korean sentences. And these considerations led to difference in performance.

6) Speed analysis

I also measured speed of tools to compare their computation efficiency. The following table shows computation time of each tool when it splits sample.txt (41 sentences). It is a single blog post, so you can expect the following time when you split a blog post into sentences. Since the computation time may vary depending on the current CPU status, so I measured 5 times and calculated the average. Note that every experiment was conducted on single thread / process environment with my M1 macbook pro (2021, 13'inch).

Name Library version Backend Average time (msec)
Baseline N/A N/A 0.22
koalanlp 2.1.7 OKT 27.37
koalanlp 2.1.7 HNN 50.39
koalanlp 2.1.7 KMR 757.08
koalanlp 2.1.7 RHINO 978.53
koalanlp 2.1.7 EUNJEON 881.24
koalanlp 2.1.7 ARIRANG 1415.53
koalanlp 2.1.7 KKMA 1971.31
Kiwi 0.14.0 N/A 36.41
Kss (ours) 4.0.0 pecab 6929.27
Kss (ours) 4.0.0 mecab 43.80

You can also compare the speed of tools with the following graphs.

You can also compare the speed of faster tools the following graphs (under 100 msec).

The baseline was fastest (because it's a just regex function), and Koalanlp (OKT backend), Kiwi, Kss (mecab backend) followed. The slowest library was Kss (pecab backend) and it was about 160 times slower than its mecab backend. Mecab and Kiwi were written in C++, All Koalanlp backends were written in Java and Pecab was written in pure python. I think this difference was caused by speed of each language. Therefore, if you can install mecab, it makes most sense to use Kss Mecab backend.

  • For Linux/MacOS users: Kss tries to install python-mecab-kor when you install kss. so you can use mecab backend very easily. But if it was failed, please install mecab yourself to use mecab backend.

  • For Windows users: Kss supports mecab-ko-msvc (mecab for Microsoft Visual C++), and its konlpy wrapper. To use mecab backend, you need to install one of mecab and konlpy.tag.Mecab on your machine. There are much information about mecab installing on Windows machine in internet like the following.


7) Conclusion

I've measured the performance of Kss and other libraries using 6 evaluation datasets, and also measured their speed. In terms of segmentation performance, Kss performed best on most datasets. In terms of speed, baseline was the fastest, and Koalanlp (OKT backend) and Kiwi followed. but Kss (mecab backend) also showed a speed that could compete with others.

Although much progress has been made by Kiwi and Kss, there are still many difficulties and limitations in Korean sentence segmentation libraries. In fact, it's also because very few people attack this task. If anyone wants to discuss Korean sentence segmentation algorithms with me or contribute to my work, feel free to send an email to kevin.ko@tunib.ai or let me know on the Github issue page.


2) split_morphemes: split text into morphemes

from kss import split_morphemes

split_morphemes(
    text: Union[str, List[str], Tuple[str]],
    backend: str = "auto",
    num_workers: Union[int, str] = "auto",
    drop_space: bool = True,
)
Parameters
  • text: String or List/Tuple of strings
    • string: single text segmentation
    • list/tuple of strings: batch texts segmentation
  • backend: Morpheme analyzer backend.
    • backend='auto': find mecab β†’ konlpy.tag.Mecab β†’ pecab and use first found analyzer (default)
    • backend='mecab': find mecab β†’ konlpy.tag.Mecab and use first found analyzer
    • backend='pecab': use pecab analyzer
  • num_workers: The number of multiprocessing workers
    • num_workers='auto': use multiprocessing with the maximum number of workers if possible (default)
    • num_workers=1: don't use multiprocessing
    • num_workers=2~N: use multiprocessing with the specified number of workers
  • drop_space: Whether it drops all space characters or not
    • drop_space=True: drop all space characters from output (default)
    • drop_space=False: remain all space characters from output
Usages
  • Single text segmentation

    import kss
    
    text = "νšŒμ‚¬ λ™λ£Œ λΆ„λ“€κ³Ό λ‹€λ…€μ™”λŠ”λ° λΆ„μœ„κΈ°λ„ μ’‹κ³  μŒμ‹λ„ λ§›μžˆμ—ˆμ–΄μš” λ‹€λ§Œ, 강남 토끼정이 강남 쉑쉑버거 골λͺ©κΈΈλ‘œ μ­‰ μ˜¬λΌκ°€μ•Ό ν•˜λŠ”λ° λ‹€λ“€ μ‰‘μ‰‘λ²„κ±°μ˜ μœ ν˜Ήμ— λ„˜μ–΄κ°ˆ λ»” ν–ˆλ‹΅λ‹ˆλ‹€ 강남역 λ§›μ§‘ ν† λΌμ •μ˜ μ™ΈλΆ€ λͺ¨μŠ΅."
    
    kss.split_morphemes(text)
    # [('νšŒμ‚¬', 'NNG'), ('λ™λ£Œ', 'NNG'), ('λΆ„', 'NNB'), ('λ“€', 'XSN'), ('κ³Ό', 'JKB'), ('λ‹€λ…€μ™”', 'VV+EP'), ('λŠ”λ°', 'EC'), ('λΆ„μœ„κΈ°', 'NNG'), ('도', 'JX'), ('μ’‹', 'VA'), ('κ³ ', 'EC'), ('μŒμ‹', 'NNG'), ('도', 'JX'), ('λ§›μžˆ', 'VA'), ('μ—ˆ', 'EP'), ('μ–΄μš”', 'EF'), ('λ‹€λ§Œ', 'MAJ'), (',', 'SC'), ('강남', 'NNP'), ('토끼', 'NNG'), ('μ •', 'NNG'), ('이', 'JKS'), ('강남', 'NNP'), ('쉑쉑', 'MAG'), ('버거', 'NNG'), ('골λͺ©κΈΈ', 'NNG'), ('둜', 'JKB'), ('μ­‰', 'MAG'), ('μ˜¬λΌκ°€', 'VV'), ('μ•Ό', 'EC'), ('ν•˜', 'VV'), ('λŠ”λ°', 'EC'), ('λ‹€', 'MAG'), ('λ“€', 'XSN'), ('쉑쉑', 'MAG'), ('버거', 'NNG'), ('의', 'JKG'), ('유혹', 'NNG'), ('에', 'JKB'), ('λ„˜μ–΄κ°ˆ', 'VV+ETM'), ('λ»”', 'NNB'), ('ν–ˆ', 'VV+EP'), ('λ‹΅λ‹ˆλ‹€', 'EC'), ('강남역', 'NNP'), ('λ§›μ§‘', 'NNG'), ('토끼', 'NNG'), ('μ •μ˜', 'NNG'), ('μ™ΈλΆ€', 'NNG'), ('λͺ¨μŠ΅', 'NNG'), ('.', 'SF')]
  • Batch texts segmentation

    import kss
    
    texts = [
        "νšŒμ‚¬ λ™λ£Œ λΆ„λ“€κ³Ό λ‹€λ…€μ™”λŠ”λ° λΆ„μœ„κΈ°λ„ μ’‹κ³  μŒμ‹λ„ λ§›μžˆμ—ˆμ–΄μš” λ‹€λ§Œ, 강남 토끼정이 강남 쉑쉑버거 골λͺ©κΈΈλ‘œ μ­‰ μ˜¬λΌκ°€μ•Ό ν•˜λŠ”λ° λ‹€λ“€ μ‰‘μ‰‘λ²„κ±°μ˜ μœ ν˜Ήμ— λ„˜μ–΄κ°ˆ λ»” ν–ˆλ‹΅λ‹ˆλ‹€",
        "강남역 λ§›μ§‘ ν† λΌμ •μ˜ μ™ΈλΆ€ λͺ¨μŠ΅. 강남 토끼정은 4μΈ΅ 건물 λ…μ±„λ‘œ 이루어져 μžˆμŠ΅λ‹ˆλ‹€.",
        "μ—­μ‹œ 토끼정 λ³Έ 점 λ‹΅μ£ ?γ…Žγ……γ…Ž 건물은 ν¬μ§€λ§Œ κ°„νŒμ΄ μ—†κΈ° λ•Œλ¬Έμ— μ§€λ‚˜μΉ  수 μžˆμœΌλ‹ˆ μ‘°μ‹¬ν•˜μ„Έμš” 강남 ν† λΌμ •μ˜ λ‚΄λΆ€ μΈν…Œλ¦¬μ–΄.",
    ]
    
    kss.split_morphemes(texts)
    # [[('νšŒμ‚¬', 'NNG'), ('λ™λ£Œ', 'NNG'), ('λΆ„', 'NNB'), ('λ“€', 'XSN'), ('κ³Ό', 'JKB'), ('λ‹€λ…€μ™”', 'VV+EP'), ('λŠ”λ°', 'EC'), ('λΆ„μœ„κΈ°', 'NNG'), ('도', 'JX'), ('μ’‹', 'VA'), ('κ³ ', 'EC'), ('μŒμ‹', 'NNG'), ('도', 'JX'), ('λ§›μžˆ', 'VA'), ('μ—ˆ', 'EP'), ('μ–΄μš”', 'EF'), ('λ‹€λ§Œ', 'MAJ'), (',', 'SC'), ('강남', 'NNP'), ('토끼', 'NNG'), ('μ •', 'NNG'), ('이', 'JKS'), ('강남', 'NNP'), ('쉑쉑', 'MAG'), ('버거', 'NNG'), ('골λͺ©κΈΈ', 'NNG'), ('둜', 'JKB'), ('μ­‰', 'MAG'), ('μ˜¬λΌκ°€', 'VV'), ('μ•Ό', 'EC'), ('ν•˜', 'VV'), ('λŠ”λ°', 'EC'), ('λ‹€', 'MAG'), ('λ“€', 'XSN'), ('쉑쉑', 'MAG'), ('버거', 'NNG'), ('의', 'JKG'), ('유혹', 'NNG'), ('에', 'JKB'), ('λ„˜μ–΄κ°ˆ', 'VV+ETM'), ('λ»”', 'NNB'), ('ν–ˆ', 'VV+EP'), ('λ‹΅λ‹ˆλ‹€', 'EC')], 
    # [('강남역', 'NNP'), ('λ§›μ§‘', 'NNG'), ('토끼', 'NNG'), ('μ •μ˜', 'NNG'), ('μ™ΈλΆ€', 'NNG'), ('λͺ¨μŠ΅', 'NNG'), ('.', 'SF'), ('강남', 'NNP'), ('토끼', 'NNG'), ('정은', 'NNP'), ('4', 'SN'), ('μΈ΅', 'NNG'), ('건물', 'NNG'), ('독채', 'NNG'), ('둜', 'JKB'), ('이루어져', 'VV+EC'), ('있', 'VX'), ('μŠ΅λ‹ˆλ‹€', 'EF'), ('.', 'SF')], 
    # [('μ—­μ‹œ', 'MAJ'), ('토끼', 'NNG'), ('μ •', 'NNG'), ('λ³Έ', 'VV+ETM'), ('점', 'NNB'), ('λ‹΅', 'MAG+VCP'), ('μ£ ', 'EF'), ('?', 'SF'), ('γ…Ž', 'IC'), ('γ……', 'NNG'), ('γ…Ž', 'IC'), ('건물', 'NNG'), ('은', 'JX'), ('크', 'VA'), ('μ§€λ§Œ', 'EC'), ('κ°„νŒ', 'NNG'), ('이', 'JKS'), ('μ—†', 'VA'), ('κΈ°', 'ETN'), ('λ•Œλ¬Έ', 'NNB'), ('에', 'JKB'), ('μ§€λ‚˜μΉ ', 'VV+ETM'), ('수', 'NNB'), ('있', 'VV'), ('μœΌλ‹ˆ', 'EC'), ('쑰심', 'NNG'), ('ν•˜', 'XSV'), ('μ„Έμš”', 'EP+EF'), ('강남', 'NNP'), ('토끼', 'NNG'), ('μ •μ˜', 'NNG'), ('λ‚΄λΆ€', 'NNG'), ('μΈν…Œλ¦¬μ–΄', 'NNG'), ('.', 'SF')]]
  • Remain space characters for original text recoverability

    import kss
    
    text = "νšŒμ‚¬ λ™λ£Œ λΆ„λ“€κ³Ό λ‹€λ…€μ™”λŠ”λ° λΆ„μœ„κΈ°λ„ μ’‹κ³  μŒμ‹λ„ λ§›μžˆμ—ˆμ–΄μš”\nλ‹€λ§Œ,\t강남 토끼정이 강남 쉑쉑버거 골λͺ©κΈΈλ‘œ μ­‰ μ˜¬λΌκ°€μ•Ό ν•˜λŠ”λ° λ‹€λ“€ μ‰‘μ‰‘λ²„κ±°μ˜ μœ ν˜Ήμ— λ„˜μ–΄κ°ˆ λ»” ν–ˆλ‹΅λ‹ˆλ‹€ 강남역 λ§›μ§‘ ν† λΌμ •μ˜ μ™ΈλΆ€ λͺ¨μŠ΅."
    
    kss.split_morphemes(text, drop_space=False)
    # [('νšŒμ‚¬', 'NNG'), (' ', 'SP'), ('λ™λ£Œ', 'NNG'), (' ', 'SP'), ('λΆ„', 'NNB'), ('λ“€', 'XSN'), ('κ³Ό', 'JKB'), (' ', 'SP'), ('λ‹€λ…€μ™”', 'VV+EP'), ('λŠ”λ°', 'EC'), (' ', 'SP'), ('λΆ„μœ„κΈ°', 'NNG'), ('도', 'JX'), (' ', 'SP'), ('μ’‹', 'VA'), ('κ³ ', 'EC'), (' ', 'SP'), ('μŒμ‹', 'NNG'), ('도', 'JX'), (' ', 'SP'), ('λ§›μžˆ', 'VA'), ('μ—ˆ', 'EP'), ('μ–΄μš”', 'EF'), ('\n', 'SP'), ('λ‹€λ§Œ', 'MAJ'), (',', 'SC'), ('\t', 'SP'), ('강남', 'NNP'), (' ', 'SP'), ('토끼', 'NNG'), ('μ •', 'NNG'), ('이', 'JKS'), (' ', 'SP'), ('강남', 'NNP'), (' ', 'SP'), ('쉑쉑', 'MAG'), ('버거', 'NNG'), (' ', 'SP'), ('골λͺ©κΈΈ', 'NNG'), ('둜', 'JKB'), (' ', 'SP'), ('μ­‰', 'MAG'), (' ', 'SP'), ('μ˜¬λΌκ°€', 'VV'), ('μ•Ό', 'EC'), (' ', 'SP'), ('ν•˜', 'VV'), ('λŠ”λ°', 'EC'), (' ', 'SP'), ('λ‹€', 'MAG'), ('λ“€', 'XSN'), (' ', 'SP'), ('쉑쉑', 'MAG'), ('버거', 'NNG'), ('의', 'JKG'), (' ', 'SP'), ('유혹', 'NNG'), ('에', 'JKB'), (' ', 'SP'), ('λ„˜μ–΄κ°ˆ', 'VV+ETM'), (' ', 'SP'), ('λ»”', 'NNB'), (' ', 'SP'), ('ν–ˆ', 'VV+EP'), ('λ‹΅λ‹ˆλ‹€', 'EC'), (' ', 'SP'), ('강남역', 'NNP'), (' ', 'SP'), ('λ§›μ§‘', 'NNG'), (' ', 'SP'), ('토끼', 'NNG'), ('μ •μ˜', 'NNG'), (' ', 'SP'), ('μ™ΈλΆ€', 'NNG'), (' ', 'SP'), ('λͺ¨μŠ΅', 'NNG'), ('.', 'SF')]

Kss in various programming languages

Kss is available in various programming languages.

Citation

If you find this toolkit useful, please consider citing:

@misc{kss,
  author       = {Ko, Hyunwoong and Park, Sang-kil},
  title        = {Kss: A Toolkit for Korean sentence segmentation},
  howpublished = {\url{https://github.com/hyunwoongko/kss}},
  year         = {2021},
}

License

Kss project is licensed under the terms of the BSD 3-Clause "New" or "Revised" License.

Copyright 2021 Hyunwoong Ko and Sang-kil Park. All Rights Reserved.