"""
## 47.Exploration de la syntaxe des verbes fonctionnels[Permalink](https://nlp100.github.io/ja/ch05.html#47-Explorationdelasyntaxedesverbesfonctionnels)
Je voudrais prêter attention uniquement au cas où le verbe wo case contient un nom de connexion sa-hen. Modifiez 46 programmes pour répondre aux spécifications suivantes.
-"Nomenclature de connexion Sahen+Uniquement lorsque la phrase composée de "(auxiliaire)" est liée au verbe
-Le prédicat est "Nomenclature de connexion sahénienne"+À+動詞の基本形」とし,文節中に複数の動詞があるときは,最左の動詞À用いる
-S'il existe plusieurs mots auxiliaires (phrases) liés au prédicat, organisez tous les mots auxiliaires dans l'ordre du dictionnaire, séparés par des espaces.
-S'il y a plusieurs clauses liées au prédicat, arrangez tous les termes séparés par des espaces (alignez-vous sur l'ordre des mots auxiliaires).
Par exemple, le résultat suivant doit être obtenu à partir de la phrase "Il existe également une méthode appelée apprentissage amélioré qui apprend en fonction de sa propre expérience."
Expérience basée sur l'apprentissage
"""
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\symbole t,Vide,*,*,*,*,\u3000,\u3000,\u3000',
'* 1 2D 0/1 -0.764522',
'je\t substantif,Synonyme,Général,*,*,*,je,Wagahai,Wagahai',
'Est\t assistant,Assistance,*,*,*,*,Est,C,sensationnel',
'* 2 -1D 0/2 0.000000',
'Chat\t substantif,Général,*,*,*,*,Chat,chat,chat',
'alors\t verbe auxiliaire,*,*,*,Spécial,Type continu,Est,De,De',
'y a-t-il\t verbe auxiliaire,*,*,*,Cinq étapes, La ligne Al,Forme basique,y a-t-il,Al,Al',
'。\symbole t,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):Surface
base (str):Base
pos (str):Pièce (base)
pos1 (str):Sous-classification des pièces détachées 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 (Numéro de phrase).
morphs List[Morph]: Morph (morphème) list.
dst (str): The index of dependency target (Numéro d'index de la clause de contact).
srcs (List[str]): The index list of dependency source. (Numéro d'index de la clause d'origine).
"""
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(je), Morph(Est)]
Return:
e.g. 'je suis'
"""
morphs = self.morphs
res = ""
for morph in morphs:
if morph.pos != "symbole":
res += morph.surface
return res
def validate_pos(self, pos: str) -> bool:
"""Return Ture if 'nom' or 'verbe' 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',
'je\t substantif,Synonyme,Général,*,*,*,je,Wagahai,Wagahai',
'Est\t assistant,Assistance,*,*,*,*,Est,C,sensationnel',
'* 1 -1D 0/2 0.000000',
'Chat\t substantif,Général,*,*,*,*,Chat,chat,chat',
'alors\t verbe auxiliaire,*,*,*,Spécial,Type continu,Est,De,De',
'y a-t-il\t verbe auxiliaire,*,*,*,Cinq étapes, La ligne Al,Forme basique,y a-t-il,Al,Al',
'。\symbole t,Phrase,*,*,*,*,。,。,。']
Parsing format:
e.g. "* 0 1D 0/1 0.000000"
|colonne|sens|
| :----: | :----------------------------------------------------------- |
| 1 |La première colonne est`*`.. Indique qu'il s'agit d'un résultat d'analyse des dépendances.|
| 2 |Numéro de phrase (entier à partir de 0)|
| 3 |Numéro de contact +`D` |
| 4 |Adresse principale/Position du mot de fonction et nombre illimité de colonnes d'identité|
| 5 |Score d'engagement. En général, plus la valeur est élevée, plus il est facile de s'engager.|
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:
"""Valider le bloc contient(sa_connect_noun)et (auxiliaire)(particle).
Args:
chunk (Chunk): Chunk object.
e.g. Chunk( id: 4, dst: 5, srcs: ['3'], morphs: [Morph(chose), Morph(À)] )
Returns:
bool: True or False
"""
sa_hen_flag = False
jyo_shi_flag = False
verb_flag = False
for morph in chunk.morphs:
if morph.pos1 == "Changer de connexion":
sa_hen_flag = True
if morph.pos == "Particule" and morph.surface == "À":
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 == "verbe":
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édicat(predicate)
-Article(argument)
-Cas(case)
Notice:
- Chunk.les morphs ont «nomenclature de connexion sa-hen» et «o (auxiliaire)»
- Chunk.srcs ont des "verbes"
Args:
chunks (List[Chunk]): A sentence contains many chunks.
e.g. [Chunk( id: 0, dst: 5, srcs: [], morphs: [Morph(je), Morph(Est)] ),
Chunk( id: 1, dst: 2, srcs: [], morphs: [Morph(ici), Morph(alors)] ),
Chunk( id: 2, dst: 3, srcs: ['1'], morphs: [Morph(début), Morph(main)] ),
Chunk( id: 3, dst: 4, srcs: ['2'], morphs: [Morph(Humain), Morph(Cette)] ),
Chunk( id: 4, dst: 5, srcs: ['3'], morphs: [Morph(chose), Morph(À)] ),
Chunk( id: 5, dst: -1, srcs: ['0', '4'], morphs: [Morph(Vous voyez), Morph(Ta), Morph(。)] )]
Returns:
dict: Predicate frame.
e.g. {'pred': 'parler', 'case': [], 'arg': []}
or {'pred': 'Voir un rire', 'case': ['main'], 'arg': ['見main']}
or {'pred': 'Faites une démonstration', 'case': ['main', 'À'], 'arg': ['持っmain', '性格À']},
"""
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 == "Changer de connexion":
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 == "verbe"
]
# Get predicate
frame["pred"] = sa_hen_surface + "À" + 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 == "Particule":
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': 'parler', 'case': [], 'arg': []},
{'pred': 'Voir un rire', 'case': ['main'], 'arg': ['見main']},
{'pred': 'Faites une démonstration', 'case': ['main', 'À'], 'arg': ['持っmain', '性格À']}]
"""
# 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":
#parler
#Regarde le rire
#Chagrin la presse
#Je me demande si je vais écouter l'imagination et l'écrire.
#Controverse
#Salutations mal placées
#Après l'avoir lu, c'est encore mieux
#Avoir une personnalité
Recommended Posts