형태소 분석기 은전한닢이 스칼라용이 있어서 시범삼아 돌려보았다.
실행방법은 너무나 간단하다.
참고 페이지
- https://bitbucket.org/eunjeon/seunjeon
build.sbt에 다음 내용 추가
libraryDependencies += "org.bitbucket.eunjeon" %% "seunjeon" % "1.1.1"
그리고 다음 코드 실행해봄
object Test extends App {
import org.bitbucket.eunjeon.seunjeon.Analyzer
// 형태소 분석
println( "@@ Step 1")
Analyzer.parse("아버지가방에들어가신다").foreach(println)
// 어절 분석
println( "@@ Step 2")
Analyzer.parseEojeol("아버지가방에들어가신다.").foreach(println)
// or
println( "@@ Step 3")
Analyzer.parseEojeol(Analyzer.parse("아버지가방에들어가신다.")).foreach(println)
/**
* 사용자 사전 추가
* surface,cost
* surface: 단어
* cost: 단어 출연 비용. 작을수록 출연할 확률이 높다.
*/
println( "@@ Step 4")
Analyzer.setUserDict(Seq("덕후", "버카충,-100", "낄끼빠빠").toIterator)
Analyzer.parse("덕후냄새가 난다.").foreach(println)
// 활용어 원형
println( "@@ Step 5")
Analyzer.parse("빨라짐").flatMap(_.deInflect()).foreach(println)
// 복합명사 분해
println( "@@ Step 6")
Analyzer.parse("삼성전자").flatMap(_.deCompound()).foreach(println)
}
실행결과 (가독성을 위해 일부 메시지 제거)
[info] Running Test
@@ Step 1
LNode(Morpheme(아버지,1784,3536,2818,WrappedArray(NNG, *, F, 아버지, *, *, *, *),COMMON,WrappedArray(N)),0,3,-1135)
LNode(Morpheme(가,490,1044,1501,WrappedArray(JKS, *, F, 가, *, *, *, *),COMMON,WrappedArray(J)),3,4,-738)
LNode(Morpheme(방,1784,3537,2975,WrappedArray(NNG, *, T, 방, *, *, *, *),COMMON,WrappedArray(N)),4,5,660)
LNode(Morpheme(에,356,307,1248,WrappedArray(JKB, *, F, 에, *, *, *, *),COMMON,WrappedArray(J)),5,6,203)
LNode(Morpheme(들어가,2421,3574,1648,WrappedArray(VV, *, F, 들어가, *, *, *, *),COMMON,WrappedArray(V)),6,9,583)
LNode(Morpheme(신다,5,4,3583,WrappedArray(EP+EC, *, F, 신다, Inflect, EP, EC, 시/EP/*+ㄴ다/EC/*),INFLECT,WrappedArray(EP, E)),9,11,-1256)
@@ Step 2
Eojeol(MutableList(LNode(Morpheme(아버지,1784,3536,2818,WrappedArray(NNG, *, F, 아버지, *, *, *, *),COMMON,WrappedArray(N)),0,3,-1135), LNode(Morpheme(가,490,1044,1501,WrappedArray(JKS, *, F, 가, *, *, *, *),COMMON,WrappedArray(J)),3,4,-738)))
Eojeol(MutableList(LNode(Morpheme(방,1784,3537,2975,WrappedArray(NNG, *, T, 방, *, *, *, *),COMMON,WrappedArray(N)),4,5,660), LNode(Morpheme(에,356,307,1248,WrappedArray(JKB, *, F, 에, *, *, *, *),COMMON,WrappedArray(J)),5,6,203)))
Eojeol(MutableList(LNode(Morpheme(들어가,2421,3574,1648,WrappedArray(VV, *, F, 들어가, *, *, *, *),COMMON,WrappedArray(V)),6,9,583), LNode(Morpheme(신다,5,6,3600,WrappedArray(EP+EF, *, F, 신다, Inflect, EP, EF, 시/EP/*+ᆫ다/EF/*),INFLECT,WrappedArray(EP, E)),9,11,-1256)))
Eojeol(MutableList(LNode(Morpheme(.,1794,3555,3559,WrappedArray(SF, *, *, *, *, *, *, *),COMMON,WrappedArray(S)),11,12,325)))
@@ Step 3
Eojeol(MutableList(LNode(Morpheme(아버지,1784,3536,2818,WrappedArray(NNG, *, F, 아버지, *, *, *, *),COMMON,WrappedArray(N)),0,3,-1135), LNode(Morpheme(가,490,1044,1501,WrappedArray(JKS, *, F, 가, *, *, *, *),COMMON,WrappedArray(J)),3,4,-738)))
Eojeol(MutableList(LNode(Morpheme(방,1784,3537,2975,WrappedArray(NNG, *, T, 방, *, *, *, *),COMMON,WrappedArray(N)),4,5,660), LNode(Morpheme(에,356,307,1248,WrappedArray(JKB, *, F, 에, *, *, *, *),COMMON,WrappedArray(J)),5,6,203)))
Eojeol(MutableList(LNode(Morpheme(들어가,2421,3574,1648,WrappedArray(VV, *, F, 들어가, *, *, *, *),COMMON,WrappedArray(V)),6,9,583), LNode(Morpheme(신다,5,6,3600,WrappedArray(EP+EF, *, F, 신다, Inflect, EP, EF, 시/EP/*+ᆫ다/EF/*),INFLECT,WrappedArray(EP, E)),9,11,-1256)))
Eojeol(MutableList(LNode(Morpheme(.,1794,3555,3559,WrappedArray(SF, *, *, *, *, *, *, *),COMMON,WrappedArray(S)),11,12,325)))
@@ Step 4
LNode(Morpheme(덕후,1784,3535,800,WrappedArray(NNG, *, F, 덕후, *, *, *, *),COMMON,WrappedArray(N)),0,2,-1135)
LNode(Morpheme(냄새,1784,3536,2123,WrappedArray(NNG, *, F, 냄새, *, *, *, *),COMMON,WrappedArray(N)),2,4,-139)
LNode(Morpheme(가,490,1044,1501,WrappedArray(JKS, *, F, 가, *, *, *, *),COMMON,WrappedArray(J)),4,5,-437)
LNode(Morpheme(난다,2421,6,1277,WrappedArray(VV+EF, *, F, 난다, Inflect, VV, EF, 나/VV/*+ᆫ다/EF/*),INFLECT,WrappedArray(V, E)),6,8,348)
LNode(Morpheme(.,1794,3555,3559,WrappedArray(SF, *, *, *, *, *, *, *),COMMON,WrappedArray(S)),8,9,-394)
@@ Step 5
LNode(Morpheme(빠르,-1,-1,0,WrappedArray(VA),COMMON,WrappedArray(V)),0,2,-1092)
LNode(Morpheme(지,-1,-1,0,WrappedArray(VX),COMMON,WrappedArray(V)),2,3,-1092)
LNode(Morpheme(ᄆ,-1,-1,0,WrappedArray(ETN),COMMON,WrappedArray(E)),2,3,-1092)
@@ Step 6
LNode(Morpheme(삼성,-1,-1,0,WrappedArray(NNG),COMMON,WrappedArray(N)),0,2,-2008)
LNode(Morpheme(전자,-1,-1,0,WrappedArray(NNG),COMMON,WrappedArray(N)),2,4,-2008)
내용 분석을 위한 사전 참고 사항
품사 태그 테이블 - https://docs.google.com/spreadsheets/d/1-9blXKjtjeKZqsf4NzHeYJCrr49-nXeRF6D80udfcwY/edit#gid=589544265
실질의미유무 | 대분류(5언 + 기타) | 세종 품사 태그 | mecab-ko-dic 품사 태그 | ||
태그 | 설명 | 태그 | 설명 | ||
실질형태소 | 체언 | NNG | 일반 명사 | NNG | 일반 명사 |
NNP | 고유 명사 | NNP | 고유 명사 | ||
NNB | 의존 명사 | NNB | 의존 명사 | ||
NNBC | 단위를 나타내는 명사 | ||||
NR | 수사 | NR | 수사 | ||
NP | 대명사 | NP | 대명사 | ||
용언 | VV | 동사 | VV | 동사 | |
VA | 형용사 | VA | 형용사 | ||
VX | 보조 용언 | VX | 보조 용언 | ||
VCP | 긍정 지정사 | VCP | 긍정 지정사 | ||
VCN | 부정 지정사 | VCN | 부정 지정사 | ||
수식언 | MM | 관형사 | MM | 관형사 | |
MAG | 일반 부사 | MAG | 일반 부사 | ||
MAJ | 접속 부사 | MAJ | 접속 부사 | ||
독립언 | IC | 감탄사 | IC | 감탄사 | |
형식형태소 | 관계언 | JKS | 주격 조사 | JKS | 주격 조사 |
JKC | 보격 조사 | JKC | 보격 조사 | ||
JKG | 관형격 조사 | JKG | 관형격 조사 | ||
JKO | 목적격 조사 | JKO | 목적격 조사 | ||
JKB | 부사격 조사 | JKB | 부사격 조사 | ||
JKV | 호격 조사 | JKV | 호격 조사 | ||
JKQ | 인용격 조사 | JKQ | 인용격 조사 | ||
JX | 보조사 | JX | 보조사 | ||
JC | 접속 조사 | JC | 접속 조사 | ||
선어말 어미 | EP | 선어말 어미 | EP | 선어말 어미 | |
어말 어미 | EF | 종결 어미 | EF | 종결 어미 | |
EC | 연결 어미 | EC | 연결 어미 | ||
ETN | 명사형 전성 어미 | ETN | 명사형 전성 어미 | ||
ETM | 관형형 전성 어미 | ETM | 관형형 전성 어미 | ||
접두사 | XPN | 체언 접두사 | XPN | 체언 접두사 | |
접미사 | XSN | 명사 파생 접미사 | XSN | 명사 파생 접미사 | |
XSV | 동사 파생 접미사 | XSV | 동사 파생 접미사 | ||
XSA | 형용사 파생 접미사 | XSA | 형용사 파생 접미사 | ||
어근 | XR | 어근 | XR | 어근 | |
부호 | SF | 마침표, 물음표, 느낌표 | SF | 마침표, 물음표, 느낌표 | |
SE | 줄임표 | SE | 줄임표 … | ||
SS | 따옴표,괄호표,줄표 | SSO | 여는 괄호 (, [ | ||
SSC | 닫는 괄호 ), ] | ||||
SP | 쉼표,가운뎃점,콜론,빗금 | SC | 구분자 , · / : | ||
SO | 붙임표(물결,숨김,빠짐) | SY | |||
SW | 기타기호 (논리수학기호,화폐기호) | ||||
한글 이외 | SL | 외국어 | SL | 외국어 | |
SH | 한자 | SH | 한자 | ||
SN | 숫자 | SN | 숫자 |
내용이 너무 많아서 다사 sbt console에서 하나씩 돌려봄
$ sbt console [info] Starting scala interpreter... [info] Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_91). Type in expressions for evaluation. Or try :help. scala> import org.bitbucket.eunjeon.seunjeon.Analyzer import org.bitbucket.eunjeon.seunjeon.Analyzer scala> Analyzer.parse("아버지가방에들어가신다.").foreach(println) LNode(Morpheme(아버지,1784,3536,2818,WrappedArray(NNG, *, F, 아버지, *, *, *, *),COMMON,WrappedArray(N)),0,3,-1135) LNode(Morpheme(가,490,1044,1501,WrappedArray(JKS, *, F, 가, *, *, *, *),COMMON,WrappedArray(J)),3,4,-738) LNode(Morpheme(방,1784,3537,2975,WrappedArray(NNG, *, T, 방, *, *, *, *),COMMON,WrappedArray(N)),4,5,660) LNode(Morpheme(에,356,307,1248,WrappedArray(JKB, *, F, 에, *, *, *, *),COMMON,WrappedArray(J)),5,6,203) LNode(Morpheme(들어가,2421,3574,1648,WrappedArray(VV, *, F, 들어가, *, *, *, *),COMMON,WrappedArray(V)),6,9,583) LNode(Morpheme(신다,5,6,3600,WrappedArray(EP+EF, *, F, 신다, Inflect, EP, EF, 시/EP/*+ᆫ다/EF/*),INFLECT,WrappedArray(EP, E)),9,11,-1256) LNode(Morpheme(.,1794,3555,3559,WrappedArray(SF, *, *, *, *, *, *, *),COMMON,WrappedArray(S)),11,12,325) scala>
|
결과를 보니 LNode, Morpheme라는 클래스들이 많이 보인다. 이게 뭔지 알아보자.
/** * Lattice 노드 * @param morpheme Morpheme * @param startPos 시작 offset * @param endPos 끝 offset * @param accumulatedCost 누적비용 */ case class LNode(morpheme:Morpheme, var startPos:Int, var endPos:Int, var accumulatedCost:Int = Int.MaxValue) {
/** * 형태소 * @param surface 표현층 * @param leftId 좌문맥ID * @param rightId 우문맥ID * @param cost Term 비용 * @param feature feature * @param poses 품사 */ @SerialVersionUID(1000L) case class Morpheme(var surface:String, var leftId:Short, var rightId:Short, var cost:Int, var feature:mutable.WrappedArray[String], var mType:MorphemeType, var poses:mutable.WrappedArray[Pos]) extends Serializable { |
샘플
// Lattice 노드
LNode(
// 형태소
Morpheme(
아버지, // surface - 표현층
1784, // leftId - 좌문맥Id
3536, // rightId - 우문맥Id
2818, // cost - 비용
WrappedArray(NNG, *, F, 아버지, *, *, *, *), // feature
COMMON, // morpheme type
WrappedArray(N) // poses - 품사
),
0, // 시작 offset
3, // 끝 offset
-1135 // 누적비용
)
위 예제를 변형해서 표현층만 추출해보자.
scala> Analyzer.parse("아버지가방에들어가신다.").toList.foreach( node => println(node.morpheme.surface )) 아버지 scala> |
사용자 사전을 추가해보자.
scala> Analyzer.setUserDict(Seq("아버지", "가방").toIterator) LNode(Morpheme(아버지,1784,3535,700,WrappedArray(NNG, *, F, 아버지, *, *, *, *),COMMON,WrappedArray(N)),0,3,-1135) scala> |
어절분석
scala> Analyzer.parseEojeol("아버지가방에들어가신다.").foreach(println) Eojeol( scala>
|
복합명사 분해
scala> Analyzer.parse("삼성전자").flatMap(_.deCompound()).foreach(println) LNode(Morpheme(삼성,-1,-1,0,WrappedArray(NNG),COMMON,WrappedArray(N)),0,2,-2008) LNode(Morpheme(전자,-1,-1,0,WrappedArray(NNG),COMMON,WrappedArray(N)),2,4,-2008)
|
'Scala' 카테고리의 다른 글
은전한닢 스칼라 버전 실행시 오류 발생시 해결법 (2) | 2016.09.28 |
---|---|
vim에서 Scala파일에 Syntax Highlight 사용하기 (0) | 2016.08.29 |
Scala-IDE Worksheet에서 한글이 깨지는 경우 (0) | 2016.02.29 |
jar를 하나로 합치기 - sbt assembly (0) | 2016.02.23 |
scala 스크립트 실행가능하게 만들기 (0) | 2016.02.18 |
sbt 버전 확인하기 (0) | 2016.02.18 |
sdk manager로 scala 설치하기 (0) | 2016.02.08 |