ݺߣ

ݺߣShare a Scribd company logo
Jak zacząć przetwarzanie
małych i dużych danych
tekstowych?
Łukasz Kobyliński i Jakub Nowacki
Confitura 2016
Prelegenci
Łukasz Kobyliński (@lkobylinski)
● Chief Science Officer w Sages (@sagespl)
● Adiunkt w Instytucie Podstaw Informatyki
PAN - Zespół Inżynierii Lingwistycznej
● #MachineLearning, #NLProc
Jakub Nowacki
● Trener @sagespl
● Senior Software Engineer w nowym
ekscytującym startupie :)
● #BigData, #MachineLearning
Jesteś studentem lub doktorantem i chcesz wziąć udział w ciekawych projektach badawczych
w zakresie NLP w IPI PAN? Napisz do mnie: lkobylinski_AT_ipipan.waw.pl
Na czym polega problem?
● Tekst w języku naturalnym to typowy przykład danych nieustrukturyzowanych
○ nie ma narzuconej organizacji informacji (jak np. tabela),
○ potrzebne jest (najczęściej wieloetapowe) przetwarzanie wstępne, aby możliwe było
analizowanie i wnioskowanie na podstawie tego typu danych.
● Wieloznaczość występuje na wszystkich poziomach analizy lingwistycznej,
przykład: I made her duck
○ I cooked waterfowl for her.
○ I cooked waterfowl belonging to her.
○ I created the (plaster?) duck she owns.
○ I caused her to quickly lower her head or body.
○ I waved my magic wand and turned her into waterfowl.
O czym będziemy mówić dzisiaj
1. Podstawowy ciąg przetwarzania tekstu dla języka polskiego.
a. Segmentacja - tokenizacja i podział na zdania.
b. Analiza morfosyntaktyczna.
c. Tagowanie.
d. Analiza składniowa.
e. Dalsze etapy przetwarzania.
2. Narzędzia i zasoby dla języka angielskiego.
3. Przetwarzanie tekstu w dużej skali - Apache Spark.
4. Dyskusja i pytania.
Tokenizacja i podział na zdania
Jak podzielić tekst na poszczególne tokeny (~słowa) i zdania?
● “Trzeba to skonfigurować w XML-u. W wierszach 10. i 15.”
○ |'Trzeba'(newline),'to'(space),'skonfigurować'(space),'w'(space),'XML-u'(space),'.'(none)
○ |'W'(space),'wierszach'(space),'10'(space),'.'(none),'i'(space),'15'(space),'.'(none)
● "At eight o'clock on Thursday morning Arthur didn't feel very good."
○ ['At', 'eight', "o'clock", 'on', 'Thursday', 'morning', 'Arthur', 'did', "n't", 'feel', 'very', 'good', '.']
● Problemy:
○ spacja - najczęściej rozdziela tokeny, ale np.: 25 000 000 (25 milionów)?
○ przecinek - podobnie, czasem stosowany do rozdzielania cyfr
○ myślnik/dywiz - najczęściej rozdziela tokeny, ale por. XML-u powyżej?
○ apostrof - rozdziela w przypadku he’s, ale nie rozdziela dla don’t, didn’t, itp.
○ kropka - czy rozdziela zdania? co ze skrótami, np. dr hab.
○ wielka litera - czy rozpoczyna zdanie?
Jak to zrobić w praktyce?
● Segment - segmentacja na podstawie reguł SRX (Java)
● Toki - tokenizator regułowy (C++)
echo "Holding Alphabet zaprezentował wyniki spółki Google za III kwartał 2015 roku. Zysk
netto Google wyniósł w III kwartale 2015 roku 3,98 miliarda dolarów." | toki-app -q -f "
$bs|'$orth', "
|'Holding', 'Alphabet', 'zaprezentował', 'wyniki', 'spółki', 'Google', 'za', 'III',
'kwartał', '2015', 'roku', '.',
|'Zysk', 'netto', 'Google', 'wyniósł', 'w', 'III', 'kwartale', '2015', 'roku', '3,98',
'miliarda', 'dolarów', '.'
Tokenizacja i podział na zdania (cd.)
Dla języka polskiego jest to jeszcze trudniejsze…
● Dlaczegoś to zrobił?
Dlaczego / ś / to / zrobił / ?
● Pojechałbym tam.
Pojechał / by / m / tam / .
Okazuje się, że:
● do przeprowadzenia poprawnej tokenizacji potrzebne są dane słownikowe,
● segmentacji mogą podlegać ciągi znaków nierozdzielone spacją.
Analiza morfosyntaktyczna
Pozwala opisać tokeny w tekście częściami mowy (czasownik, rzeczownik), wraz
z ich kategoriami gramatycznymi (liczba, rodzaj, przypadek).
● Ile jest części mowy?
○ po szkolnemu: 10?
○ w Narodowym Korpusie Języka Polskiego: ponad 30 różnych fleksemów, np. liczebnik główny
(sześć, dużo), liczebnik zbiorowy (sześcioro, trojga)
● Ile jest rodzajów?
○ po szkolnemu: męski, żeński, nijaki, męskoosobowy, niemęskoosobowy
○ w Narodowym Korpusie Języka Polskiego: męski osobowy (facet), męski zwierzęcy (koń),
męski rzeczowy (stół), …
● Tagset (zbiór tagów opisujących części mowy tokenów) dla polskiego
○ np.: subst:sg:nom:m1
○ zawiera ponad 1000 możliwych tagów.
Jak to zrobić w praktyce?
● Tokenizacja i analiza morfologiczna
○ Morfeusz - analiza morfologiczna (C++, binding Python i Java),
○ Maca - biblioteka opakowująca Toki i Morfeusza (C++, binding Python).
Morfeusz morfeusz = Morfeusz.createInstance();
String s = "Holding Alphabet zaprezentował wyniki spółki Google za III kwartał 2015 roku. "
+ "Zysk netto Google wyniósł w III kwartale 2015 roku 3,98 miliarda dolarów.";
ResultsIterator it = morfeusz.analyseAsIterator(s);
while (it.hasNext()) {
MorphInterpretation mi = it.next();
System.out.println(MorfeuszUtils.getInterpretationString(mi, morfeusz));
}
0 1 Holding holding subst:sg:acc:m3 nazwa pospolita
0 1 Holding holding subst:sg:nom:m3 nazwa pospolita
1 2 Alphabet Alphabet ign
2 3 zaprezentował zaprezentować praet:sg:m1.m2.m3:perf
Tagowanie
Ujednoznacznienie listy możliwych interpretacji morfosyntaktycznych dla tokenów
w tekście, np.:
Jak to zrobić w praktyce?
● Tagery języka polskiego:
○ Concraft (Haskell),
○ WCRFT (C++),
○ PANTERA (C++).
echo "Holding Alphabet zaprezentował wyniki spółki Google za III kwartał 2015 roku. Zysk
netto Google wyniósł w III kwartale 2015 roku 3,98 miliarda dolarów." | ./concraft-pl tag
~/dane/nkjp-1.2/model/concraft/model.gz
Holding none
holding subst:sg:acc:m3
holding subst:sg:nom:m3 disamb
Alphabet space
Alphabet ign
Alphabet subst:sg:gen:n
Alphabet subst:sg:nom:m1
Alphabet subst:sg:nom:m2
Alphabet subst:sg:nom:m3 disamb
...
Analiza składniowa
Istnieją zjawiska, których opis możliwy jest na poziomie większych jednostek, niż
pojedyncze segmenty
● formy analityczne czasowników, np. będzie śpiewał;
● opisowe formy stopnia wyższego przymiotników, np. bardziej pracowity;
● czasowniki zwrotne, np. opalać się;
● jednostki wielowyrazowe, np. kopnąć w kalendarz.
Spejd - płytki parser składniowy
Rule "Adj: opisowy stopień wyższy"
Match: [orth~"[Bb]ardziej"] [pos~"adj"];
Eval: word(2, Adj:com, 2.base);
Dalsze etapy przetwarzania
● Rozpoznawanie jednostek nazewnicznych
Jak to zrobić w praktyce?
● Rozpoznawanie jednostek nazewniczych
○ Liner2 (C++)
○ NERF (Haskell)
● Podejścia najczęsciej oparte na paradygmacie uczenia maszynowego
(np. CRF - Conditional Random Fields)
○ uczymy model na podstawie przykładów - tekstu oznaczonego wcześniej ręcznie
odpowiednimi znacznikami (np. nam_org_company - nazwa firmy),
○ model uczy się jakie segmenty i w jakim kontekście należy oznaczać odpowiednim
znacznikiem,
○ tekst reprezentowany jest przez cechy - formy ortograficzne segmentów, ich lematy, tagi
morfosyntaktyczne i inne,
○ wyuczony model można zastosować na nowych danych.
Czy dla języka angielskiego jest łatwiej?
● Biblioteki realizujące podstawowy ciąg przetwarzania tekstu
○ Stanford CoreNLP (Java)
○ Apache OpenNLP (Java)
○ GATE (Java)
○ NLTK (Python)
<dependency>
<groupId>edu.stanford.nlp</groupId>
<artifactId>stanford-corenlp</artifactId>
<version>3.6.0</version>
</dependency>
[...] <classifier>models</classifier> [...]
Document doc
= new Document("At eight o'clock on Thursday morning Arthur didn't feel very good. " +
"It was raining.");
for (Sentence sent : doc.sentences()) {
System.out.println(sent.text()); // At eight o'clock on Thursday morning Arthur ...
System.out.println(sent.lemmas()); // [at, eight, o'clock, on, Thursday, morning, Arthur
System.out.println(sent.nerTags()); // [O, TIME, TIME, O, DATE, TIME, PERSON, ...
}
Przetwarzanie tekstu w dużej skali
● Sporo problemów wymaga skali
wykraczającej poza możliwości
pojedynczej maszyny (Big Data?)
● Wiele algorytmów nie koniecznie
przystosowanych jest do wykorzystania w
systemach Big Data
● Ze względu na popularność Spark
powstało wiele narzędzi wspomagających
NLP
● Pozostaje jednak problem wielu języków
Źródło: http://www.business2community.com
Machine Learning w Spark
W Spark można wyróżnić trzy
podejścia do ML:
● Przeprowadzić kroswalidację
tradycyjnego modelu na klastrze
● Użyć tradycyjnego modelu
uczonego na małych danych
● Użyć biblioteki Spark Machine
Learning
Machine Learning w Spark
Dwa warianty do wyboru:
● Spark MLlib - wykorzystuje
RDDs
● Spark ML - wykorzystuje
DataFrames
Spark ML i DataFrames są zalecaną
metodą pracy obecnie gdyż są one
najbardziej rozwijane.
Źródło: https://www.coursera.org/learn/machine-learning
Spark ML pipeline
Źródło: http://spark.apache.org/docs/latest/ml-guide.html#pipeline
Spark ML pipeline
Transformer:
● Implementuje metodę transform()
● Bierze wejściowy DataFrame i produkuje
nowy przez dodanie odpowiednich kolumn
Estymator:
● Implementuje metodę fit()
● Bierze wejściowy DataFrame i trenuje
model
● Wytrenowany estymator staje się
modelem
● Metoda transform() wykonuje predykcję
import org.apache.spark.ml.feature.Word2Vec
val documentDF = sqlContext.createDataFrame(Seq(
"Hi I heard about Spark".split(" "),
"I wish Java could use case classes".split(" "),
"Logistic regression models are neat".split(" ")
).map(Tuple1.apply)).toDF("text")
val word2Vec = new Word2Vec()
.setInputCol("text")
.setOutputCol("result")
.setVectorSize(3)
.setMinCount(0)
val model = word2Vec.fit(documentDF)
val result = model.transform(documentDF)
result.select("result").take(3).foreach(println)
Źródło: https://spark.apache.org/docs/latest/ml-features.html#word2vec
Spark ML pipeline
val regexTokenizer = { new RegexTokenizer()
.setPattern("[a-zA-Z']+").setGaps(false).setInputCol("text")
}
val remover = { new StopWordsRemover()
.setInputCol(regexTokenizer.getOutputCol)
}
val ngram2 = { new NGram()
.setInputCol(remover.getOutputCol.setN(2)
}
val removerHashingTF = { new HashingTF()
.setInputCol(remover.getOutputCol)
}
val ngram2HashingTF = { new HashingTF()
.setInputCol(ngram2.getOutputCol)
}
val assembler = { new VectorAssembler()
.setInputCols(Array(removerHashingTF.getOutputCol,
ngram2HashingTF.getOutputCol))
}
val lr = { new LogisticRegression()
.setMaxIter(10).setRegParam(0.3).setElasticNetParam(0.8)
.setLabelCol("label").setFeaturesCol(assembler.getOutputCol)
}
val pipeline = {new Pipeline()
.setStages(Array(
regexTokenizer, remover, removerHashingTF, ngram2,
ngram2HashingTF, assembler,lr))
}
val modelPipeline = pipeline.fit(data)
Data
Stop Word
Remover
TF Hashing TF Hashing
2-Gram
Vector
Assembler
Logistic
Regression
Spark CoreNLP
Databricks przygotowało Spark CoreNLP - zestaw funkcji do pracy z danymi tekstowymi w oparciu o
Stanford CoreNLP Simple API.
Można zarówno używać funkcji na kolumnach jak i używać w transformatorach pipelinach.
Obsługuje wiele języków z angielskim na czele, ale nie ma polskiego bezpośrednio.
Stanford CoreNLP jest na licencji GPL 3.
Źródło: https://github.com/databricks/spark-corenlp
df.withColumn("tokens", tokenize('text)).withColumn("lemma", lemma('text)).show()
+------------+------------------+------------------+
| text| tokens| lemma|
+------------+------------------+------------------+
|Ala ma kota.|[Ala, ma, kota, .]|[Ala, ma, kota, .]|
+------------+------------------+------------------+
Co z językiem polskim?
Obecnie nie ma wiele dedykowanych narzędzi
do NLP w języku polskim dla Spark.
Można używać korpusów do trenowania np
Word2Vec i innych algorytmów dostępnych w
Spark ML.
Można opakować istniejące narzędzia w User
Defined Functions (UDF), które są podstawą
transformatorów.
// Prosty
def simpleAddOne = sqlContext.udf.register
(“simpleAddOne”,
(s: String) => s + “one”)
// df - DataFrame z textem “Ala ma kota.”
df.select(simpleAddOne(‘text).show()
// +-------------+
// | UDF(text)|
// +-------------+
// |Ala ma kota.1|
// +-------------+
// Złożony
def myTokenize = sqlContext.udf.register("myTokenize",
(s: String) => {
val sentence = new Sentence(s)
sentence.words().asScala
})
df.select(myTokenize(‘text).show()
// +------------------+
// | UDF(text)|
// +------------------+
// |[Ala, ma, kota, .]|
// +------------------+
Stworzenie własnego transformera
class MyTokenizer( override val uid: String ) extends
UnaryTransformer[String, Seq[String], MyTokenizer] {
def this() = this( s"stok_${UUID.randomUUID().toString.takeRight(12)}" )
override protected def createTransformFunc: String => Seq[String] = {
(s: String) => {
val sentence = new Sentence(s)
sentence.words().asScala
}
}
override protected def validateInputType( inputType: DataType ): Unit = {
require(inputType == StringType, s"Input type must be string type but got $inputType.")
}
override protected def outputDataType: DataType = new ArrayType(StringType, false)
}
Stworzenie własnego transformera
val myTokenizer = {
new MyTokenizer()
.setInputCol("text")
.setOutputCol("my_tokenizer_out")
}
myTokenizer.transform(df).show()
+------------+------------------+
| text| my_tokenizer_out|
+------------+------------------+
|Ala ma kota.|[Ala, ma, kota, .]|
+------------+------------------+
Dzięki za uwagę!
Pytania?
Odnośniki do oprogramowania i zasobów
1. Segmentacja
○ Segment: https://github.com/loomchild/segment
○ Toki: http://nlp.pwr.wroc.pl/redmine/projects/toki/wiki
2. Analiza morfologiczna
○ Morfeusz: http://sgjp.pl/morfeusz/
○ Maca: http://nlp.pwr.wroc.pl/redmine/projects/libpltagger/wiki
3. Tagowanie
○ Concraft: http://zil.ipipan.waw.pl/Concraft
○ WCRFT: http://nlp.pwr.wroc.pl/redmine/projects/wcrft/wiki
○ Pantera: http://zil.ipipan.waw.pl/PANTERA
4. Płytkie parsowanie
○ Spejd: http://zil.ipipan.waw.pl/Spejd
Odnośniki do oprogramowania i zasobów (cd.)
1. Rozpoznawanie jednostek identyfikacyjnych
○ Liner2: http://www.nlp.pwr.wroc.pl/narzedzia-i-zasoby/narzedzia/liner2
○ NERF: http://zil.ipipan.waw.pl/Nerf
2. Narzędzia i zasoby w postaci webserwisów
○ Clarin2: http://clarin-pl.eu/pl/uslugi/
○ Multiserwis: http://multiservice.nlp.ipipan.waw.pl/pl/
3. Inne odnośniki
○ CLIP: http://clip.ipipan.waw.pl/LRT
Odnośniki do oprogramowania i zasobów
(język angielski)
1. Biblioteki
○ Stanford CoreNLP: http://stanfordnlp.github.io/CoreNLP/
○ Apache OpenNLP: https://opennlp.apache.org/
○ GATE: https://gate.ac.uk/

More Related Content

Jak zacząć przetwarzanie małych i dużych danych tekstowych?

  • 1. Jak zacząć przetwarzanie małych i dużych danych tekstowych? Łukasz Kobyliński i Jakub Nowacki Confitura 2016
  • 2. Prelegenci Łukasz Kobyliński (@lkobylinski) ● Chief Science Officer w Sages (@sagespl) ● Adiunkt w Instytucie Podstaw Informatyki PAN - Zespół Inżynierii Lingwistycznej ● #MachineLearning, #NLProc Jakub Nowacki ● Trener @sagespl ● Senior Software Engineer w nowym ekscytującym startupie :) ● #BigData, #MachineLearning Jesteś studentem lub doktorantem i chcesz wziąć udział w ciekawych projektach badawczych w zakresie NLP w IPI PAN? Napisz do mnie: lkobylinski_AT_ipipan.waw.pl
  • 3. Na czym polega problem? ● Tekst w języku naturalnym to typowy przykład danych nieustrukturyzowanych ○ nie ma narzuconej organizacji informacji (jak np. tabela), ○ potrzebne jest (najczęściej wieloetapowe) przetwarzanie wstępne, aby możliwe było analizowanie i wnioskowanie na podstawie tego typu danych. ● Wieloznaczość występuje na wszystkich poziomach analizy lingwistycznej, przykład: I made her duck ○ I cooked waterfowl for her. ○ I cooked waterfowl belonging to her. ○ I created the (plaster?) duck she owns. ○ I caused her to quickly lower her head or body. ○ I waved my magic wand and turned her into waterfowl.
  • 4. O czym będziemy mówić dzisiaj 1. Podstawowy ciąg przetwarzania tekstu dla języka polskiego. a. Segmentacja - tokenizacja i podział na zdania. b. Analiza morfosyntaktyczna. c. Tagowanie. d. Analiza składniowa. e. Dalsze etapy przetwarzania. 2. Narzędzia i zasoby dla języka angielskiego. 3. Przetwarzanie tekstu w dużej skali - Apache Spark. 4. Dyskusja i pytania.
  • 5. Tokenizacja i podział na zdania Jak podzielić tekst na poszczególne tokeny (~słowa) i zdania? ● “Trzeba to skonfigurować w XML-u. W wierszach 10. i 15.” ○ |'Trzeba'(newline),'to'(space),'skonfigurować'(space),'w'(space),'XML-u'(space),'.'(none) ○ |'W'(space),'wierszach'(space),'10'(space),'.'(none),'i'(space),'15'(space),'.'(none) ● "At eight o'clock on Thursday morning Arthur didn't feel very good." ○ ['At', 'eight', "o'clock", 'on', 'Thursday', 'morning', 'Arthur', 'did', "n't", 'feel', 'very', 'good', '.'] ● Problemy: ○ spacja - najczęściej rozdziela tokeny, ale np.: 25 000 000 (25 milionów)? ○ przecinek - podobnie, czasem stosowany do rozdzielania cyfr ○ myślnik/dywiz - najczęściej rozdziela tokeny, ale por. XML-u powyżej? ○ apostrof - rozdziela w przypadku he’s, ale nie rozdziela dla don’t, didn’t, itp. ○ kropka - czy rozdziela zdania? co ze skrótami, np. dr hab. ○ wielka litera - czy rozpoczyna zdanie?
  • 6. Jak to zrobić w praktyce? ● Segment - segmentacja na podstawie reguł SRX (Java) ● Toki - tokenizator regułowy (C++) echo "Holding Alphabet zaprezentował wyniki spółki Google za III kwartał 2015 roku. Zysk netto Google wyniósł w III kwartale 2015 roku 3,98 miliarda dolarów." | toki-app -q -f " $bs|'$orth', " |'Holding', 'Alphabet', 'zaprezentował', 'wyniki', 'spółki', 'Google', 'za', 'III', 'kwartał', '2015', 'roku', '.', |'Zysk', 'netto', 'Google', 'wyniósł', 'w', 'III', 'kwartale', '2015', 'roku', '3,98', 'miliarda', 'dolarów', '.'
  • 7. Tokenizacja i podział na zdania (cd.) Dla języka polskiego jest to jeszcze trudniejsze… ● Dlaczegoś to zrobił? Dlaczego / ś / to / zrobił / ? ● Pojechałbym tam. Pojechał / by / m / tam / . Okazuje się, że: ● do przeprowadzenia poprawnej tokenizacji potrzebne są dane słownikowe, ● segmentacji mogą podlegać ciągi znaków nierozdzielone spacją.
  • 8. Analiza morfosyntaktyczna Pozwala opisać tokeny w tekście częściami mowy (czasownik, rzeczownik), wraz z ich kategoriami gramatycznymi (liczba, rodzaj, przypadek). ● Ile jest części mowy? ○ po szkolnemu: 10? ○ w Narodowym Korpusie Języka Polskiego: ponad 30 różnych fleksemów, np. liczebnik główny (sześć, dużo), liczebnik zbiorowy (sześcioro, trojga) ● Ile jest rodzajów? ○ po szkolnemu: męski, żeński, nijaki, męskoosobowy, niemęskoosobowy ○ w Narodowym Korpusie Języka Polskiego: męski osobowy (facet), męski zwierzęcy (koń), męski rzeczowy (stół), … ● Tagset (zbiór tagów opisujących części mowy tokenów) dla polskiego ○ np.: subst:sg:nom:m1 ○ zawiera ponad 1000 możliwych tagów.
  • 9. Jak to zrobić w praktyce? ● Tokenizacja i analiza morfologiczna ○ Morfeusz - analiza morfologiczna (C++, binding Python i Java), ○ Maca - biblioteka opakowująca Toki i Morfeusza (C++, binding Python). Morfeusz morfeusz = Morfeusz.createInstance(); String s = "Holding Alphabet zaprezentował wyniki spółki Google za III kwartał 2015 roku. " + "Zysk netto Google wyniósł w III kwartale 2015 roku 3,98 miliarda dolarów."; ResultsIterator it = morfeusz.analyseAsIterator(s); while (it.hasNext()) { MorphInterpretation mi = it.next(); System.out.println(MorfeuszUtils.getInterpretationString(mi, morfeusz)); } 0 1 Holding holding subst:sg:acc:m3 nazwa pospolita 0 1 Holding holding subst:sg:nom:m3 nazwa pospolita 1 2 Alphabet Alphabet ign 2 3 zaprezentował zaprezentować praet:sg:m1.m2.m3:perf
  • 10. Tagowanie Ujednoznacznienie listy możliwych interpretacji morfosyntaktycznych dla tokenów w tekście, np.:
  • 11. Jak to zrobić w praktyce? ● Tagery języka polskiego: ○ Concraft (Haskell), ○ WCRFT (C++), ○ PANTERA (C++). echo "Holding Alphabet zaprezentował wyniki spółki Google za III kwartał 2015 roku. Zysk netto Google wyniósł w III kwartale 2015 roku 3,98 miliarda dolarów." | ./concraft-pl tag ~/dane/nkjp-1.2/model/concraft/model.gz Holding none holding subst:sg:acc:m3 holding subst:sg:nom:m3 disamb Alphabet space Alphabet ign Alphabet subst:sg:gen:n Alphabet subst:sg:nom:m1 Alphabet subst:sg:nom:m2 Alphabet subst:sg:nom:m3 disamb ...
  • 12. Analiza składniowa Istnieją zjawiska, których opis możliwy jest na poziomie większych jednostek, niż pojedyncze segmenty ● formy analityczne czasowników, np. będzie śpiewał; ● opisowe formy stopnia wyższego przymiotników, np. bardziej pracowity; ● czasowniki zwrotne, np. opalać się; ● jednostki wielowyrazowe, np. kopnąć w kalendarz. Spejd - płytki parser składniowy Rule "Adj: opisowy stopień wyższy" Match: [orth~"[Bb]ardziej"] [pos~"adj"]; Eval: word(2, Adj:com, 2.base);
  • 13. Dalsze etapy przetwarzania ● Rozpoznawanie jednostek nazewnicznych
  • 14. Jak to zrobić w praktyce? ● Rozpoznawanie jednostek nazewniczych ○ Liner2 (C++) ○ NERF (Haskell) ● Podejścia najczęsciej oparte na paradygmacie uczenia maszynowego (np. CRF - Conditional Random Fields) ○ uczymy model na podstawie przykładów - tekstu oznaczonego wcześniej ręcznie odpowiednimi znacznikami (np. nam_org_company - nazwa firmy), ○ model uczy się jakie segmenty i w jakim kontekście należy oznaczać odpowiednim znacznikiem, ○ tekst reprezentowany jest przez cechy - formy ortograficzne segmentów, ich lematy, tagi morfosyntaktyczne i inne, ○ wyuczony model można zastosować na nowych danych.
  • 15. Czy dla języka angielskiego jest łatwiej? ● Biblioteki realizujące podstawowy ciąg przetwarzania tekstu ○ Stanford CoreNLP (Java) ○ Apache OpenNLP (Java) ○ GATE (Java) ○ NLTK (Python) <dependency> <groupId>edu.stanford.nlp</groupId> <artifactId>stanford-corenlp</artifactId> <version>3.6.0</version> </dependency> [...] <classifier>models</classifier> [...] Document doc = new Document("At eight o'clock on Thursday morning Arthur didn't feel very good. " + "It was raining."); for (Sentence sent : doc.sentences()) { System.out.println(sent.text()); // At eight o'clock on Thursday morning Arthur ... System.out.println(sent.lemmas()); // [at, eight, o'clock, on, Thursday, morning, Arthur System.out.println(sent.nerTags()); // [O, TIME, TIME, O, DATE, TIME, PERSON, ... }
  • 16. Przetwarzanie tekstu w dużej skali ● Sporo problemów wymaga skali wykraczającej poza możliwości pojedynczej maszyny (Big Data?) ● Wiele algorytmów nie koniecznie przystosowanych jest do wykorzystania w systemach Big Data ● Ze względu na popularność Spark powstało wiele narzędzi wspomagających NLP ● Pozostaje jednak problem wielu języków Źródło: http://www.business2community.com
  • 17. Machine Learning w Spark W Spark można wyróżnić trzy podejścia do ML: ● Przeprowadzić kroswalidację tradycyjnego modelu na klastrze ● Użyć tradycyjnego modelu uczonego na małych danych ● Użyć biblioteki Spark Machine Learning
  • 18. Machine Learning w Spark Dwa warianty do wyboru: ● Spark MLlib - wykorzystuje RDDs ● Spark ML - wykorzystuje DataFrames Spark ML i DataFrames są zalecaną metodą pracy obecnie gdyż są one najbardziej rozwijane. Źródło: https://www.coursera.org/learn/machine-learning
  • 19. Spark ML pipeline Źródło: http://spark.apache.org/docs/latest/ml-guide.html#pipeline
  • 20. Spark ML pipeline Transformer: ● Implementuje metodę transform() ● Bierze wejściowy DataFrame i produkuje nowy przez dodanie odpowiednich kolumn Estymator: ● Implementuje metodę fit() ● Bierze wejściowy DataFrame i trenuje model ● Wytrenowany estymator staje się modelem ● Metoda transform() wykonuje predykcję import org.apache.spark.ml.feature.Word2Vec val documentDF = sqlContext.createDataFrame(Seq( "Hi I heard about Spark".split(" "), "I wish Java could use case classes".split(" "), "Logistic regression models are neat".split(" ") ).map(Tuple1.apply)).toDF("text") val word2Vec = new Word2Vec() .setInputCol("text") .setOutputCol("result") .setVectorSize(3) .setMinCount(0) val model = word2Vec.fit(documentDF) val result = model.transform(documentDF) result.select("result").take(3).foreach(println) Źródło: https://spark.apache.org/docs/latest/ml-features.html#word2vec
  • 21. Spark ML pipeline val regexTokenizer = { new RegexTokenizer() .setPattern("[a-zA-Z']+").setGaps(false).setInputCol("text") } val remover = { new StopWordsRemover() .setInputCol(regexTokenizer.getOutputCol) } val ngram2 = { new NGram() .setInputCol(remover.getOutputCol.setN(2) } val removerHashingTF = { new HashingTF() .setInputCol(remover.getOutputCol) } val ngram2HashingTF = { new HashingTF() .setInputCol(ngram2.getOutputCol) } val assembler = { new VectorAssembler() .setInputCols(Array(removerHashingTF.getOutputCol, ngram2HashingTF.getOutputCol)) } val lr = { new LogisticRegression() .setMaxIter(10).setRegParam(0.3).setElasticNetParam(0.8) .setLabelCol("label").setFeaturesCol(assembler.getOutputCol) } val pipeline = {new Pipeline() .setStages(Array( regexTokenizer, remover, removerHashingTF, ngram2, ngram2HashingTF, assembler,lr)) } val modelPipeline = pipeline.fit(data) Data Stop Word Remover TF Hashing TF Hashing 2-Gram Vector Assembler Logistic Regression
  • 22. Spark CoreNLP Databricks przygotowało Spark CoreNLP - zestaw funkcji do pracy z danymi tekstowymi w oparciu o Stanford CoreNLP Simple API. Można zarówno używać funkcji na kolumnach jak i używać w transformatorach pipelinach. Obsługuje wiele języków z angielskim na czele, ale nie ma polskiego bezpośrednio. Stanford CoreNLP jest na licencji GPL 3. Źródło: https://github.com/databricks/spark-corenlp df.withColumn("tokens", tokenize('text)).withColumn("lemma", lemma('text)).show() +------------+------------------+------------------+ | text| tokens| lemma| +------------+------------------+------------------+ |Ala ma kota.|[Ala, ma, kota, .]|[Ala, ma, kota, .]| +------------+------------------+------------------+
  • 23. Co z językiem polskim? Obecnie nie ma wiele dedykowanych narzędzi do NLP w języku polskim dla Spark. Można używać korpusów do trenowania np Word2Vec i innych algorytmów dostępnych w Spark ML. Można opakować istniejące narzędzia w User Defined Functions (UDF), które są podstawą transformatorów. // Prosty def simpleAddOne = sqlContext.udf.register (“simpleAddOne”, (s: String) => s + “one”) // df - DataFrame z textem “Ala ma kota.” df.select(simpleAddOne(‘text).show() // +-------------+ // | UDF(text)| // +-------------+ // |Ala ma kota.1| // +-------------+ // Złożony def myTokenize = sqlContext.udf.register("myTokenize", (s: String) => { val sentence = new Sentence(s) sentence.words().asScala }) df.select(myTokenize(‘text).show() // +------------------+ // | UDF(text)| // +------------------+ // |[Ala, ma, kota, .]| // +------------------+
  • 24. Stworzenie własnego transformera class MyTokenizer( override val uid: String ) extends UnaryTransformer[String, Seq[String], MyTokenizer] { def this() = this( s"stok_${UUID.randomUUID().toString.takeRight(12)}" ) override protected def createTransformFunc: String => Seq[String] = { (s: String) => { val sentence = new Sentence(s) sentence.words().asScala } } override protected def validateInputType( inputType: DataType ): Unit = { require(inputType == StringType, s"Input type must be string type but got $inputType.") } override protected def outputDataType: DataType = new ArrayType(StringType, false) }
  • 25. Stworzenie własnego transformera val myTokenizer = { new MyTokenizer() .setInputCol("text") .setOutputCol("my_tokenizer_out") } myTokenizer.transform(df).show() +------------+------------------+ | text| my_tokenizer_out| +------------+------------------+ |Ala ma kota.|[Ala, ma, kota, .]| +------------+------------------+
  • 27. Odnośniki do oprogramowania i zasobów 1. Segmentacja ○ Segment: https://github.com/loomchild/segment ○ Toki: http://nlp.pwr.wroc.pl/redmine/projects/toki/wiki 2. Analiza morfologiczna ○ Morfeusz: http://sgjp.pl/morfeusz/ ○ Maca: http://nlp.pwr.wroc.pl/redmine/projects/libpltagger/wiki 3. Tagowanie ○ Concraft: http://zil.ipipan.waw.pl/Concraft ○ WCRFT: http://nlp.pwr.wroc.pl/redmine/projects/wcrft/wiki ○ Pantera: http://zil.ipipan.waw.pl/PANTERA 4. Płytkie parsowanie ○ Spejd: http://zil.ipipan.waw.pl/Spejd
  • 28. Odnośniki do oprogramowania i zasobów (cd.) 1. Rozpoznawanie jednostek identyfikacyjnych ○ Liner2: http://www.nlp.pwr.wroc.pl/narzedzia-i-zasoby/narzedzia/liner2 ○ NERF: http://zil.ipipan.waw.pl/Nerf 2. Narzędzia i zasoby w postaci webserwisów ○ Clarin2: http://clarin-pl.eu/pl/uslugi/ ○ Multiserwis: http://multiservice.nlp.ipipan.waw.pl/pl/ 3. Inne odnośniki ○ CLIP: http://clip.ipipan.waw.pl/LRT
  • 29. Odnośniki do oprogramowania i zasobów (język angielski) 1. Biblioteki ○ Stanford CoreNLP: http://stanfordnlp.github.io/CoreNLP/ ○ Apache OpenNLP: https://opennlp.apache.org/ ○ GATE: https://gate.ac.uk/