"""
## 47.Functional Verb Syntax Mining[Permalink](https://nlp100.github.io/ja/ch05.html#47-FunctionalVerbSyntaxMining)
Ich möchte nur auf den Fall achten, in dem das Verb wo case ein Sa-hen-Verbindungsnomen enthält. Ändern Sie 46 Programme, um die folgenden Spezifikationen zu erfüllen.
-"Sahen Verbindungsnomenklatur+Nur wenn die Phrase aus "(Hilfs)" mit dem Verb zusammenhängt
-Das Prädikat lautet "Sahen verbindet Nomenklatur"+Zu+動詞の基本形」とし,文節中に複数の動詞があるときは,最左の動詞Zu用いる
-Wenn das Prädikat mehrere Hilfswörter (Phrasen) enthält, ordnen Sie alle Hilfswörter in Wörterbuchreihenfolge an, die durch Leerzeichen getrennt sind.
-Wenn sich mehrere Klauseln auf das Prädikat beziehen, ordnen Sie alle durch Leerzeichen getrennten Begriffe an (richten Sie sie nach der Reihenfolge der Hilfswörter aus).
Die folgende Ausgabe sollte beispielsweise aus dem Satz "Es gibt auch eine Methode namens erweitertes Lernen, die auf der Grundlage der eigenen Erfahrung lernt" erhalten werden.
Erfahrung basierend auf Lernen
"""
from collections import defaultdict
from typing import List
def read_file(fpath: str) -> List[List[str]]:
"""Get clear format of parsed sentences.
Args:
fpath (str): File path.
Returns:
List[List[str]]: List of sentences, and each sentence contains a word list.
e.g. result[1]:
['* 0 2D 0/0 -0.764522',
'\u3000\t Symbol,Leer,*,*,*,*,\u3000,\u3000,\u3000',
'* 1 2D 0/1 -0.764522',
'ich\t Substantiv,Gleichbedeutend,Allgemeines,*,*,*,ich,Wagahai,Wagahai',
'Ist\t Assistent,Hilfe,*,*,*,*,Ist,C.,Beeindruckend',
'* 2 -1D 0/2 0.000000',
'Katze\t Substantiv,Allgemeines,*,*,*,*,Katze,Katze,Katze',
'damit\t Hilfsverb,*,*,*,Besondere,Kontinuierlicher Typ,Ist,De,De',
'Gibt es\t Hilfsverb,*,*,*,Fünf Schritte, La Linie Al,Grundform,Gibt es,Al,Al',
'。\t Symbol,Phrase,*,*,*,*,。,。,。']
"""
with open(fpath, mode="rt", encoding="utf-8") as f:
sentences = f.read().split("EOS\n")
return [sent.strip().split("\n") for sent in sentences if sent.strip() != ""]
class Morph:
"""Morph information for each token.
Args:
data (dict): A dictionary contains necessary information.
Attributes:
surface (str):Oberfläche
base (str):Base
pos (str):Teil (Basis)
pos1 (str):Teil Teil Unterklassifizierung 1 (pos1)
"""
def __init__(self, data):
self.surface = data["surface"]
self.base = data["base"]
self.pos = data["pos"]
self.pos1 = data["pos1"]
def __repr__(self):
return f"Morph({self.surface})"
def __str__(self):
return "surface[{}]\tbase[{}]\tpos[{}]\tpos1[{}]".format(
self.surface, self.base, self.pos, self.pos1
)
class Chunk:
"""Containing information for Clause/phrase.
Args:
data (dict): A dictionary contains necessary information.
Attributes:
chunk_id (str): The number of clause chunk (Phrasennummer).
morphs List[Morph]: Morph (Morphem) list.
dst (str): The index of dependency target (Indexnummer der Kontaktklausel).
srcs (List[str]): The index list of dependency source. (Original-Klauselindexnummer).
"""
def __init__(self, chunk_id, dst):
self.id = chunk_id
self.morphs = []
self.dst = dst
self.srcs = []
def __repr__(self):
return "Chunk( id: {}, dst: {}, srcs: {}, morphs: {} )".format(
self.id, self.dst, self.srcs, self.morphs
)
def get_surface(self) -> str:
"""Concatenate morph surfaces in a chink.
Args:
chunk (Chunk): e.g. Chunk( id: 0, dst: 5, srcs: [], morphs: [Morph(ich), Morph(Ist)]
Return:
e.g. 'ich bin'
"""
morphs = self.morphs
res = ""
for morph in morphs:
if morph.pos != "Symbol":
res += morph.surface
return res
def validate_pos(self, pos: str) -> bool:
"""Return Ture if 'Substantiv' or 'Verb' in chunk's morphs. Otherwise, return False."""
morphs = self.morphs
return any([morph.pos == pos for morph in morphs])
def convert_sent_to_chunks(sent: List[str]) -> List[Morph]:
"""Extract word and convert to morph.
Args:
sent (List[str]): A sentence contains a word list.
e.g. sent:
['* 0 1D 0/1 0.000000',
'ich\t Substantiv,Gleichbedeutend,Allgemeines,*,*,*,ich,Wagahai,Wagahai',
'Ist\t Assistent,Hilfe,*,*,*,*,Ist,C.,Beeindruckend',
'* 1 -1D 0/2 0.000000',
'Katze\t Substantiv,Allgemeines,*,*,*,*,Katze,Katze,Katze',
'damit\t Hilfsverb,*,*,*,Besondere,Kontinuierlicher Typ,Ist,De,De',
'Gibt es\t Hilfsverb,*,*,*,Fünf Schritte, La Linie Al,Grundform,Gibt es,Al,Al',
'。\t Symbol,Phrase,*,*,*,*,。,。,。']
Parsing format:
e.g. "* 0 1D 0/1 0.000000"
|Säule|Bedeutung|
| :----: | :----------------------------------------------------------- |
| 1 |Die erste Spalte ist`*`.. Zeigt an, dass es sich um ein Ergebnis der Abhängigkeitsanalyse handelt.|
| 2 |Phrasennummer (Ganzzahl ab 0)|
| 3 |Kontaktnummer +`D` |
| 4 |Hauptadresse/Funktionswortposition und beliebig viele Identitätsspalten|
| 5 |Verlobungspunktzahl. Im Allgemeinen ist es umso einfacher, sich zu engagieren, je größer der Wert ist.|
Returns:
List[Chunk]: List of chunks.
"""
chunks = []
chunk = None
srcs = defaultdict(list)
for i, word in enumerate(sent):
if word[0] == "*":
# Add chunk to chunks
if chunk is not None:
chunks.append(chunk)
# eNw Chunk beggin
chunk_id = word.split(" ")[1]
dst = word.split(" ")[2].rstrip("D")
chunk = Chunk(chunk_id, dst)
srcs[dst].append(chunk_id) # Add target->source to mapping list
else: # Add Morch to chunk.morphs
features = word.split(",")
dic = {
"surface": features[0].split("\t")[0],
"base": features[6],
"pos": features[0].split("\t")[1],
"pos1": features[1],
}
chunk.morphs.append(Morph(dic))
if i == len(sent) - 1: # Add the last chunk
chunks.append(chunk)
# Add srcs to each chunk
for chunk in chunks:
chunk.srcs = list(srcs[chunk.id])
return chunks
def validate_chunk(chunk: Chunk, chunks: List[Chunk]) -> bool:
"""Validiere Chunk enthält(sa_connect_noun)und (Hilfs-)(particle).
Args:
chunk (Chunk): Chunk object.
e.g. Chunk( id: 4, dst: 5, srcs: ['3'], morphs: [Morph(Ding), Morph(Zu)] )
Returns:
bool: True or False
"""
sa_hen_flag = False
jyo_shi_flag = False
verb_flag = False
for morph in chunk.morphs:
if morph.pos1 == "Verbindung ändern":
sa_hen_flag = True
if morph.pos == "Partikel" and morph.surface == "Zu":
jyo_shi_flag = True
if (not sa_hen_flag) and (not jyo_shi_flag):
return False
for src in chunk.srcs:
src_chunk = chunks[int(src)]
for morph in src_chunk.morphs:
if morph.pos == "Verb":
verb_flag = True
return all([sa_hen_flag, jyo_shi_flag, verb_flag])
def get_verb_frame(chunks: List[Chunk]) -> dict:
"""Get edges from sentence chunks.
Terms:
-Prädikat(predicate)
-Artikel(argument)
-Fall(case)
Notice:
- Chunk.Morphen haben "sa-hen Verbindungsnomenklatur" und "o (Hilfs)"
- Chunk.srcs haben "Verben"
Args:
chunks (List[Chunk]): A sentence contains many chunks.
e.g. [Chunk( id: 0, dst: 5, srcs: [], morphs: [Morph(ich), Morph(Ist)] ),
Chunk( id: 1, dst: 2, srcs: [], morphs: [Morph(Hier), Morph(damit)] ),
Chunk( id: 2, dst: 3, srcs: ['1'], morphs: [Morph(Start), Morph(Hand)] ),
Chunk( id: 3, dst: 4, srcs: ['2'], morphs: [Morph(Mensch), Morph(Das)] ),
Chunk( id: 4, dst: 5, srcs: ['3'], morphs: [Morph(Ding), Morph(Zu)] ),
Chunk( id: 5, dst: -1, srcs: ['0', '4'], morphs: [Morph(Sie sehen), Morph(Ta), Morph(。)] )]
Returns:
dict: Predicate frame.
e.g. {'pred': 'sich unterhalten', 'case': [], 'arg': []}
or {'pred': 'Sehen Sie ein Lachen', 'case': ['Hand'], 'arg': ['見Hand']}
or {'pred': 'Habe eine Demonstration', 'case': ['Hand', 'Zu'], 'arg': ['持っHand', '性格Zu']},
"""
frame = {"pred": None, "case": [], "arg": []}
for chunk in chunks:
# Initialize
sa_hen_surface = None
# Skip if not valid
if not validate_chunk(chunk, chunks):
continue
# Get sa_hen
for morph in chunk.morphs:
if morph.pos1 == "Verbindung ändern":
sa_hen_surface = morph.surface
# Get verb
src_verb_chunks = [
morph
for src in chunk.srcs
for morph in chunks[int(src)].morphs
if morph.pos == "Verb"
]
# Get predicate
frame["pred"] = sa_hen_surface + "Zu" + src_verb_chunks[0].base
# Get case
for src in chunk.srcs:
src_chunk = chunks[int(src)]
for morph in src_chunk.morphs:
if morph.pos == "Partikel":
frame["case"].append(morph.base)
frame["arg"].append(src_chunk.get_surface())
return frame
def write_to_file(sents: List[dict], path):
"""Write patterns to file.
Args:
sents ([type]): predicate-verb frame
e.g. [{'pred': 'sich unterhalten', 'case': [], 'arg': []},
{'pred': 'Sehen Sie ein Lachen', 'case': ['Hand'], 'arg': ['見Hand']},
{'pred': 'Habe eine Demonstration', 'case': ['Hand', 'Zu'], 'arg': ['持っHand', '性格Zu']}]
"""
# convert_frame_to_text
lines = []
for frame in sents:
case_text = " ".join(frame["case"])
arg_text = " ".join(frame["arg"])
lines.append((frame["pred"], case_text, arg_text))
# write_to_file
with open(path, "w") as f:
for line in lines:
f.write(f"{line[0]}\t{line[1]}\t{line[2]}\n")
fpath = "neko.txt.cabocha"
sentences = read_file(fpath)
sentences = [convert_sent_to_chunks(sent) for sent in sentences] # ans41
# ans47
pattern_sents = [get_verb_frame(sent) for sent in sentences]
pattern_sents = list(filter(lambda x: x["pred"] is not None, pattern_sents))
write_to_file(pattern_sents, "predicate_verb_frame.txt")
# "predicate_verb_frame.txt":
#sich unterhalten
#Schau dir das Lachen an
#Trauer die Presse
#Ich frage mich, ob ich auf die Fantasie hören und sie aufschreiben werde.
#Kontroverse
#Fehlgeleitete Grüße
#Nach dem Lesen ist es noch besser
#Habe eine Persönlichkeit
Recommended Posts