surprisoh / spark-nkp

Natural Korean Processor for Apache Spark

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Natural Korean Processor for Apache Spark Build Status Maven Central

For English, please go to README.eng.md

은전한닢 프로젝트의 형태소 분석기 seunjeonApache Spark에서 사용하기 쉽게 포장한 패키지입니다. spark-nkp는 다음과 같은 두 가지 Transformer를 제공합니다:

  • Tokenizer 문장을 형태소 단위로 쪼개는 transformer. 원하는 품사만을 걸러낼 수도 있습니다.
  • Analyzer 형태소 분석을 위한 transformer. 문장의 단어들에 대한 자세한 정보를 담은 DataFrame을 출력합니다.

사용법

spark-shell

spark-shell --packages com.github.uosdmlab:spark-nkp_2.11:0.2.1

Zeppelin

Interpreter Setting > Spark Interpreter > Edit > Dependencies

artifact com.github.uosdmlab:spark-nkp_2.11:0.2.1

예제

Tokenizer

import com.github.uosdmlab.nkp.Tokenizer

val df = spark.createDataset(
	Seq(
		"아버지가방에들어가신다.",
		"사랑해요 제플린!",
		"스파크는 재밌어",
		"나는야 데이터과학자",
		"데이터야~ 놀자~"
	)
).toDF("text")

val tokenizer = new Tokenizer()
	.setInputCol("text")
	.setOutputCol("words")

val result = tokenizer.transform(df)

result.show(truncate = false)

output:

+------------+--------------------------+
|text        |words                     |
+------------+--------------------------+
|아버지가방에들어가신다.|[아버지, 가, 방, 에, 들어가, 신다, .]|
|사랑해요 제플린!   |[사랑, 해요, 제플린, !]          |
|스파크는 재밌어    |[스파크, 는, 재밌, 어]           |
|나는야 데이터과학자  |[나, 는, 야, 데이터, 과학자]       |
|데이터야~ 놀자~   |[데이터, 야, ~, 놀자, ~]        |
+------------+--------------------------+

Analyzer

import org.apache.spark.sql.functions._
import com.github.uosdmlab.nkp.Analyzer

val df = spark.createDataset(
	Seq(
		"아버지가방에들어가신다.",
		"사랑해요 제플린!",
		"스파크는 재밌어",
		"나는야 데이터과학자",
		"데이터야~ 놀자~"
	)
).toDF("text")
	.withColumn("id", monotonically_increasing_id)

val analyzer = new Analyzer

val result = analyzer.transform(df)

result.show(truncate = false)

output:

+---+----+-------+-----------------------------------------------------+-----+---+
|id |word|pos    |char                                                 |start|end|
+---+----+-------+-----------------------------------------------------+-----+---+
|0  |아버지 |[N]    |[NNG, *, F, 아버지, *, *, *, *]                         |0    |3  |
|0  ||[J]    |[JKS, *, F, 가, *, *, *, *]                           |3    |4  |
|0  ||[N]    |[NNG, *, T, 방, *, *, *, *]                           |4    |5  |
|0  ||[J]    |[JKB, *, F, 에, *, *, *, *]                           |5    |6  |
|0  |들어가 |[V]    |[VV, *, F, 들어가, *, *, *, *]                          |6    |9  |
|0  |신다  |[EP, E]|[EP+EF, *, F, 신다, Inflect, EP, EF, 시/EP/*+ᆫ다/EF/*]   |9    |11 |
|0  |.   |[S]    |[SF, *, *, *, *, *, *, *]                            |11   |12 |
|1  |사랑  |[N]    |[NNG, *, T, 사랑, *, *, *, *]                          |0    |2  |
|1  |해요  |[XS, E]|[XSV+EF, *, F, 해요, Inflect, XSV, EF, 하/XSV/*+아요/EF/*]|2    |4  |
|1  |제플린 |[N]    |[NNP, *, T, 제플린, *, *, *, *]                         |5    |8  |
|1  |!   |[S]    |[SF, *, *, *, *, *, *, *]                            |8    |9  |
|2  |스파크 |[N]    |[NNG, *, F, 스파크, *, *, *, *]                         |0    |3  |
|2  ||[J]    |[JX, *, T, 는, *, *, *, *]                            |3    |4  |
|2  |재밌  |[V]    |[VA, *, T, 재밌, *, *, *, *]                           |5    |7  |
|2  ||[E]    |[EC, *, F, 어, *, *, *, *]                            |7    |8  |
|3  ||[N]    |[NP, *, F, 나, *, *, *, *]                            |0    |1  |
|3  ||[J]    |[JX, *, T, 는, *, *, *, *]                            |1    |2  |
|3  ||[I]    |[IC, *, F, 야, *, *, *, *]                            |2    |3  |
|3  |데이터 |[N]    |[NNG, *, F, 데이터, *, *, *, *]                         |4    |7  |
|3  |과학자 |[N]    |[NNG, *, F, 과학자, Compound, *, *, 과학/NNG/*+자/NNG/*]   |7    |10 |
+---+----+-------+-----------------------------------------------------+-----+---+
only showing top 20 rows

명사 단어 TF-IDF with Pipeline

import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.feature.{CountVectorizer, IDF}
import com.github.uosdmlab.nkp.Tokenizer

val df = spark.createDataset(
	Seq(
		"아버지가방에들어가신다.",
		"사랑해요 제플린!",
		"스파크는 재밌어",
		"나는야 데이터과학자",
		"데이터야~ 놀자~"
	)
).toDF("text")

val tokenizer = new Tokenizer()
	.setInputCol("text")
	.setOutputCol("words")
	.setFilter("N")

val cntVec = new CountVectorizer()
  .setInputCol("words")
  .setOutputCol("tf")

val idf = new IDF()
  .setInputCol("tf")
  .setOutputCol("tfidf")

val pipe = new Pipeline()
  .setStages(Array(tokenizer, cntVec, idf))

val pipeModel = pipe.fit(df)

val result = pipeModel.transform(df)

result.show

output:

+------------+-------------+--------------------+--------------------+
|        text|        words|                  tf|               tfidf|
+------------+-------------+--------------------+--------------------+
|아버지가방에들어가신다.|     [아버지, 방]| (9,[1,5],[1.0,1.0])|(9,[1,5],[1.09861...|
|   사랑해요 제플린!|    [사랑, 제플린]| (9,[3,8],[1.0,1.0])|(9,[3,8],[1.09861...|
|    스파크는 재밌어|        [스파크]|       (9,[6],[1.0])|(9,[6],[1.0986122...|
|  나는야 데이터과학자|[나, 데이터, 과학자]|(9,[0,2,7],[1.0,1...|(9,[0,2,7],[0.693...|
|   데이터야~ 놀자~|    [데이터, 놀자]| (9,[0,4],[1.0,1.0])|(9,[0,4],[0.69314...|
+------------+-------------+--------------------+--------------------+

API

Tokenizer

문장을 형태소 단위로 쪼개는 transformer 입니다. setFilter 함수로 원하는 품사에 해당하는 형태소만을 걸러낼 수도 있습니다. 품사 태그는 아래의 품사 태그 설명을 참고하세요.

Example

import com.github.uosdmlab.nkp.Tokenizer

val tokenizer = new Tokenizer()
	.setInputCol("text")
	.setOutputCol("words")
	.setFilter("N", "V", "SN")	// 체언, 용언, 숫자만을 출력

품사 태그 설명

  • EP 선어말어미
  • E 어미
  • I 독립언
  • J 관계언
  • M 수식언
  • N 체언(명사가 여기 속합니다)
  • S 부호
  • SL 외국어
  • SH 한자
  • SN 숫자
  • V 용언(동사가 여기 속합니다)
  • VCP 긍정지정사
  • XP 접두사
  • XS 접미사
  • XR 어근

Members

  • transform(dataset: Dataset[_]): DataFrame

Parameter Setters

  • setFilter(pos: String, poses: String*): Tokenizer
  • setInputCol(value: String): Tokenizer
  • setOutputCol(value: String): Tokenizer

Parameter Getters

  • getFilter: Array[String]
  • getInputCol: String
  • getOutputCol: String

Analyzer

형태소 분석을 위한 transformer 입니다. 분석할 문장들과 각 문장들을 구분할 id를 입력값으로 받습니다.

Example

import com.github.uosdmlab.nkp.Analyzer

val analyzer = new Analyzer

Analyzer DataFrame Schema

Input Schema

Input DataFrame은 다음과 같은 column들을 가져야 합니다. id column의 값들이 고유한(unique) 값이 아닐 경우 오류가 발생합니다. Unique ID는 상단의 Analyzer 예제와 같이 Spark의 SQL 함수 monotonically_increasing_id를 사용하면 쉽게 생성할 수 있습니다.

이름 설명
id 각 text를 구분할 unique ID
text 분석할 텍스트
Output Schema
이름 설명
id 각 text를 구분할 unique ID
word 단어
pos Part Of Speech; 품사
char characteristic; 특징, seunjeon의 feature
start 단어 시작 위치
end 단어 종료 위치

자세한 품사 태그 설명은 seunjeon의 품사 태그 설명 스프레드 시트를 참고하시기 바랍니다.

Members

  • transform(dataset: Dataset[_]): DataFrame

Parameter Setters

  • setIdCol(value: String)
  • setTextCol(value: String)
  • setWordCol(value: String)
  • setPosCol(value: String)
  • setCharCol(value: String)
  • setStartCol(value: String)
  • setEndCol(value: String)

Parameter Getters

  • getIdCol(value: String)
  • getTextCol(value: String)
  • getWordCol(value: String)
  • getPosCol(value: String)
  • getCharCol(value: String)
  • getStartCol(value: String)
  • getEndCol(value: String)

Test

sbt test

알림

본 패키지는 Spark 2.0 버전을 기준으로 만들어졌습니다.

감사의 글

은전한닢 프로젝트의 유영호님, 이용운님께 감사의 말씀 드립니다! 연구에 정말 큰 도움이 되었습니다.

About

Natural Korean Processor for Apache Spark

License:Apache License 2.0


Languages

Language:Scala 100.0%