The input is a list of [token, tag, chunk]-items. The output is a list of [token, tag, chunk, relation]-items. A noun phrase preceding a verb phrase is perceived as sentence subject. A noun phrase following a verb phrase is perceived as sentence object.
(chunked)
| 984 | GO = dict.fromkeys(("go", "goes", "going", "went"), True) |
| 985 | |
| 986 | def find_relations(chunked): |
| 987 | """ The input is a list of [token, tag, chunk]-items. |
| 988 | The output is a list of [token, tag, chunk, relation]-items. |
| 989 | A noun phrase preceding a verb phrase is perceived as sentence subject. |
| 990 | A noun phrase following a verb phrase is perceived as sentence object. |
| 991 | """ |
| 992 | tag = lambda token: token[2].split("-")[-1] # B-NP => NP |
| 993 | # Group successive tokens with the same chunk-tag. |
| 994 | chunks = [] |
| 995 | for token in chunked: |
| 996 | if len(chunks) == 0 \ |
| 997 | or token[2].startswith("B-") \ |
| 998 | or tag(token) != tag(chunks[-1][-1]): |
| 999 | chunks.append([]) |
| 1000 | chunks[-1].append(token+["O"]) |
| 1001 | # If a VP is preceded by a NP, the NP is tagged as NP-SBJ-(id). |
| 1002 | # If a VP is followed by a NP, the NP is tagged as NP-OBJ-(id). |
| 1003 | # Chunks that are not part of a relation get an O-tag. |
| 1004 | id = 0 |
| 1005 | for i, chunk in enumerate(chunks): |
| 1006 | if tag(chunk[-1]) == "VP" and i > 0 and tag(chunks[i-1][-1]) == "NP": |
| 1007 | if chunk[-1][-1] == "O": |
| 1008 | id += 1 |
| 1009 | for token in chunk: |
| 1010 | token[-1] = "VP-" + str(id) |
| 1011 | for token in chunks[i-1]: |
| 1012 | token[-1] += "*NP-SBJ-" + str(id) |
| 1013 | token[-1] = token[-1].lstrip("O-*") |
| 1014 | if tag(chunk[-1]) == "VP" and i < len(chunks)-1 and tag(chunks[i+1][-1]) == "NP": |
| 1015 | if chunk[-1][-1] == "O": |
| 1016 | id += 1 |
| 1017 | for token in chunk: |
| 1018 | token[-1] = "VP-" + str(id) |
| 1019 | for token in chunks[i+1]: |
| 1020 | token[-1] = "*NP-OBJ-" + str(id) |
| 1021 | token[-1] = token[-1].lstrip("O-*") |
| 1022 | # This is more a proof-of-concept than useful in practice: |
| 1023 | # PP-LOC = be + in|at + the|my |
| 1024 | # PP-DIR = go + to|towards + the|my |
| 1025 | for i, chunk in enumerate(chunks): |
| 1026 | if 0 < i < len(chunks)-1 and len(chunk) == 1 and chunk[-1][-1] == "O": |
| 1027 | t0, t1, t2 = chunks[i-1][-1], chunks[i][0], chunks[i+1][0] # previous / current / next |
| 1028 | if tag(t1) == "PP" and t2[1] in ("DT", "PR", "PRP$"): |
| 1029 | if t0[0] in BE and t1[0] in ("in", "at") : t1[-1] = "PP-LOC" |
| 1030 | if t0[0] in GO and t1[0] in ("to", "towards") : t1[-1] = "PP-DIR" |
| 1031 | related = []; [related.extend(chunk) for chunk in chunks] |
| 1032 | return related |
| 1033 | |
| 1034 | #### COMMAND LINE ################################################################################## |
| 1035 | # The commandline() function enables command line support for a Parser. |