Skip to content

Commit d92016c

Browse files
김봉환김봉환
authored andcommitted
docs: add Korean README (README-ko.md)
- Full Korean translation of README.md - Architecture diagram, feature tables, usage examples - Test results, performance benchmarks - Project structure, implementation notes
1 parent 51629d0 commit d92016c

1 file changed

Lines changed: 238 additions & 0 deletions

File tree

README-ko.md

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
# 한국어 Stemmer (Snowball 기반)
2+
3+
[Snowball](https://snowballstem.org/) stemming 프레임워크를 기반으로 구축된 프로덕션 레벨 한국어 stemmer. 사전 기반 하이브리드 접근 방식으로 정확도를 대폭 개선했습니다.
4+
5+
## 개요
6+
7+
이 프로젝트는 Snowball의 한국어 stemmer에 다음 기능을 추가합니다:
8+
9+
1. **불규칙 용언 사전** — 1,097개 활용형 → 어근 매핑 (151개 어근 커버리지)
10+
2. **용언 접미사 제거** — 규칙 기반 한국어 용언 접미사 제거 (과거형, 연결 어미 등)
11+
3. **격 조사 제거** — 규칙 기반 한국어 격 조사 제거 (주격, 목적격, 부사격 등)
12+
4. **사전 기반 lookup 레이어** — 사전 등재어는 O(1) 즉시 반환, 미등재어는 Snowball stemmer로 폴백
13+
14+
## 아키텍처
15+
16+
```
17+
입력 단어
18+
19+
20+
┌─────────────────────┐
21+
│ 격 조사 제거 │ ← 불규칙 사전 충돌 방지를 위해 가장 먼저 검사
22+
│ (에서, 을/를, 와, │ (예: '와'가 조사 vs 불규칙 활용형 충돌)
23+
│ 이라도, 등) │
24+
└─────────┬───────────┘
25+
│ (조사 아님)
26+
27+
┌─────────────────────┐
28+
│ 불규칙 용언 사전 │ ← O(1) 해시 테이블 lookup
29+
│ lookup │ 1,097개 활용형 → 어근 매핑
30+
└─────────┬───────────┘
31+
│ (사전 없음)
32+
33+
┌─────────────────────┐
34+
│ 용언 접미사 제거 │ ← 긴 접미사부터 매칭 (최장 일치)
35+
│ │ 다, 았/었/였, 랐, 랐다, 습니다,어요, 등
36+
└─────────┬───────────┘
37+
│ (접미사 없음)
38+
39+
┌─────────────────────┐
40+
│ 내장 사전 lookup │ ← 사전 등재어는 원형 즉시 반환
41+
└─────────┬───────────┘
42+
│ (사전 없음)
43+
44+
┌─────────────────────┐
45+
│ Snowball stemmer │ ← 폴백: 기존 Snowball stemmer 처리
46+
└─────────────────────┘
47+
```
48+
49+
## 주요 기능
50+
51+
### 불규칙 용언 사전
52+
53+
주요 한국어 불규칙 용언 패턴 전체 커버리지:
54+
55+
| 패턴 | 설명 | 예시 |
56+
|------|------|------|
57+
| ㅂ-불규칙 | ㅂ consonant shift | 갚다 → 갚 |
58+
| ㄷ-불규칙 | ㄷ consonant shift | 듣다 → 듣, 걷다 → 걷 |
59+
| ㄹ-불규칙 | ㄹ consonant shift | 올리다 → 올, 마다 → 마 |
60+
| ㅅ-불규칙 | ㅅ consonant shift | 짓다 → 짓 |
61+
| ㅆ-불규칙 | ㅆ consonant shift | 바쁘다 → 바쁘 |
62+
| ㅎ-불규칙 | ㅎ consonant shift | 귀찮다 → 귀찮 |
63+
| ㄴ-불규칙 | ㄴ consonant shift | 낫다 → 낫 |
64+
| 특수 | 하다, 크다, 좋다 | 합니다 → 하, 크다 → 크 |
65+
66+
### 용언 접미사 제거
67+
68+
| 접미사 | 유형 | 예시 |
69+
|--------|------|------|
70+
|| 동사/형용사 종결 | 먹다 → 먹, 좋다 → 좋 |
71+
| 았/었/였 | 과거 시제 | 먹었다 → 먹, 했다 → 하 |
72+
|| 과거 시제 (ㄹ-불규칙) | 올랐다 → 올 |
73+
| 랐다 | 과거 시제 (+다) | 올랐다 → 올 |
74+
| 습니다 | 겸양체 | 합니다 → 하 |
75+
| 어요 | 해요체 | 먹어요 → 먹 |
76+
| 고, 니, 니까, 에서 | 연결 어미 | 먹고 → 먹, 가니 → 가 |
77+
78+
### 격 조사 제거
79+
80+
| 조사 | 유형 | 예시 |
81+
|------|------|------|
82+
| 에서 | 장소를 나타내는 조사 | 학교에서 → 학교 |
83+
| 을/를 | 목적격을 나타내는 조사 | 책을 → 책 |
84+
|| 소유를 나타내는 조사 | 사람의 → 사람 |
85+
| 와/과 | 동시를 나타내는 조사 | 친구와 → 친구 |
86+
| 에, 로, 으로 | 방향/장소를 나타내는 조사 | 학교에 → 학교 |
87+
| 도, 만 | 강조 조사 | 가족도 → 가족, 일만 → 일 |
88+
| 이라도,조차도 | 복합 격 조사 | 가족이라도 → 가족 |
89+
| 까지, 부터, 처럼 | 범위/비교 조사 | 물건까지 → 물건 |
90+
91+
## 사용법
92+
93+
```python
94+
from snowballstemmer.korean_stemmer_dict import KoreanStemmerDict
95+
96+
# 내장 사전 (119개 단어)으로 초기화
97+
stemmer = KoreanStemmerDict(dict_source='builtin')
98+
99+
# 단일 단어 stem
100+
print(stemmer.stem('학교에서')) # 학교
101+
print(stemmer.stem('받았습니다')) #
102+
print(stemmer.stem('올랐다')) #
103+
print(stemmer.stem('짓다')) #
104+
print(stemmer.stem('가족이라도')) # 가족
105+
106+
# 배치 stem
107+
words = ['학교에서', '책을', '친구와', '했습니다']
108+
print(stemmer.stemWords(words)) # ['학교', '책', '친구', '했']
109+
```
110+
111+
## 테스트 결과
112+
113+
### 전체: 20/20 통과 (100%) ✅
114+
115+
| 항목 | 결과 |
116+
|------|------|
117+
| 내장 사전 (동사/형용사/명사/부사/조사) | 100% |
118+
| kiwipiepy 사전 | 통과 |
119+
| 성능 벤치마크 | 334,031 words/sec |
120+
121+
### 용언 접미사 제거 (23/23 통과)
122+
123+
| 입력 | 출력 | 상태 |
124+
|------|------|------|
125+
| 받았다 |||
126+
| 올랐다 |||
127+
| 짓다 |||
128+
| 놀다 |||
129+
| 했습니다 |||
130+
| 했어요 |||
131+
| 좋아요 |||
132+
133+
### 격 조사 제거 (13/13 통과)
134+
135+
| 입력 | 출력 | 상태 |
136+
|------|------|------|
137+
| 학교에서 | 학교 ||
138+
| 가족도 | 가족 ||
139+
| 학교를 | 학교 ||
140+
| 사람의 | 사람 ||
141+
| 친구와 | 친구 ||
142+
| 가족이라도 | 가족 ||
143+
144+
## 성능
145+
146+
| 방법 | 속도 |
147+
|------|------|
148+
| 사전 lookup stemmer | **334,031 words/sec** |
149+
| 기존 Snowball stemmer | 211,817 words/sec |
150+
| **속도 향상** | **1.58x** |
151+
152+
사전 등재어가 높은 텍스트에서 사전 lookup 레이어가 상당한 속도 향상을 제공합니다. 사전에 등재된 단어는 Snowball stemmer를 호출하지 않고 즉시 반환됩니다.
153+
154+
## 프로젝트 구조
155+
156+
```
157+
snowball-korean/
158+
├── python/
159+
│ └── snowballstemmer/
160+
│ ├── korean_stemmer.py # 컴파일된 Snowball stemmer (korean.sbl → Python)
161+
│ ├── korean_stemmer_dict.py # 사전 기반 stemmer (본 프로젝트)
162+
│ └── generate_irregular_dict.py # 불규칙 용언 사전 생성 스크립트
163+
├── data/
164+
│ ├── irregular_verb_dict.json # 1,097개 활용형 → 어근 매핑
165+
│ ├── korean_dict.json # 병합된 내장 + kiwipiepy 사전
166+
│ └── korean_dict.pkl # 병합된 사전 pickle 형식
167+
├── tests/
168+
│ ├── test_korean_stemmer_dict.py # 사전 stemmer 단위 테스트
169+
│ ├── korean/
170+
│ │ ├── voc.txt # 테스트 어휘 (32개 단어)
171+
│ │ └── expected_output.txt # 기대 stemmer 출력
172+
│ └── benchmark_korean_stemmer.py # 성능 벤치마크
173+
├── scripts/
174+
│ └── load_dict.py # kiwipiepy 사전 → JSON/Pickle 변환
175+
├── IMPLEMENT-v2.md # 상세 구현 노트
176+
├── README.md # English documentation
177+
└── README-ko.md # 이 파일
178+
```
179+
180+
## 구현 노트
181+
182+
### 인코딩 고려사항
183+
184+
원본 Snowball stemmer는 among 테이블에서 jamo-level stringdef를 사용하지만, 한국어 텍스트는 일반적으로 합성 Hangul 음절을 사용합니다. 이 프로젝트는 다음 방식으로 이를 처리합니다:
185+
186+
1. **사전 기반 접근**: 사전 등재어는 사전에서 직접 매칭하여 among 테이블을 우회
187+
2. **규칙 기반 접미사 제거**: 접미사 패턴을 문자 수준에서 정의하여 합성/분해 형태 모두 처리
188+
3. **불규칙 용언 사전**: 활용형 → 어근 매핑을 사전 계산하여 among 테이블 매칭 불필요
189+
190+
### 설계 결정
191+
192+
1. **불규칙 사전보다 격 조사 먼저 검사**: 격 조사(`` 등)가 불규칙 활용형으로 잘못 매칭되는 충돌 방지
193+
2. **긴 매칭 우선**: 접미사/조사를 길이 내림차순으로 검사하여 부분 매칭 방지 (예: `에서```보다 먼저)
194+
3. **Snowball로 폴백**: 사전/규칙으로 커버되지 않는 단어는 기존 Snowball stemmer로 처리하여 최대 커버리지 확보
195+
196+
### 불규칙 용언 사전 생성
197+
198+
불규칙 용언 사전은 `generate_irregular_dict.py`로 프로그램적으로 생성됩니다. 각 불규칙 용언 패턴은 어근과 변환 규칙으로 정의되며, 스크립트가 모든 가능한 활용형을 자동 생성합니다.
199+
200+
```python
201+
# 패턴 정의 예시
202+
{
203+
'verb': '올리다',
204+
'root': '',
205+
'pattern': 'ㄹ-불규칙',
206+
'conjugations': {
207+
'올랐다': '',
208+
'올랐어요': '',
209+
'올랐습니다': '',
210+
# ... 더 많은 활용형
211+
}
212+
}
213+
```
214+
215+
## 테스트 실행
216+
217+
테스트 스위트 실행:
218+
219+
```bash
220+
cd tests
221+
python3 -m unittest test_korean_stemmer_dict -v
222+
```
223+
224+
성능 벤치마크 실행:
225+
226+
```bash
227+
python3 tests/benchmark_korean_stemmer.py
228+
```
229+
230+
## 관련 링크
231+
232+
- [Snowball](https://snowballstem.org/) — 원본 stemming 프레임워크
233+
- [KiwiPy](https://github.com/bab2min/kiwipy) — 한국어 형태소 분석기 (사전 소스)
234+
- [PR #1](https://github.com/nethippo/snowball/pull/1) — upstream 제출용 Pull Request
235+
236+
## 라이선스
237+
238+
이 프로젝트는 부모 Snowball 프로젝트의 라이선스를 따릅니다.

0 commit comments

Comments
 (0)