Q: Are there NPs/PPs in PCC that aren't markables although they should be?


In [1]:
import os
import glob

import discoursegraphs as dg


Couldn't import dot_parser, loading of dot files will not be possible.

In [2]:
MMAX_ROOT_DIR = os.path.expanduser('/home/arne/corpora/potsdam-commentary-corpus-2.0.0/coreference/')
TIGER_ROOT_DIR = os.path.expanduser('/home/arne/corpora/potsdam-commentary-corpus-2.0.0/syntax/')


MMAX_TEST_FILE = os.path.join(MMAX_ROOT_DIR, 'maz-1423.mmax')
TIGER_TEST_FILE = os.path.join(TIGER_ROOT_DIR, 'maz-1423.xml')

In [3]:
# for mmax_file in glob.glob(MMAX_ROOT_DIR+'*.mmax'):
#     dg.read_mmax2(mmax_file)

In [4]:
from discoursegraphs.readwrite.mmax2 import get_potential_markables

def get_unmarked_potential_markables(docgraph):
    """
    Parameters
    ----------
    docgraph : DiscourseDocumentGraph
        a document graph that (at least) contains syntax trees
        (imported from Tiger XML files) and markables (imported from
        an MMAX2 file)
    """
    unmarked_potential_markables = []
    for cat_node in get_potential_markables(docgraph):
        if not any('mmax:markable' in eattr['layers']
                  for token_id in dg.get_span(docgraph, cat_node)
                  for (src, trg, eattr) in docgraph.in_edges(token_id, data=True)):
            unmarked_potential_markables.append(cat_node)
    return unmarked_potential_markables

In [5]:
from collections import defaultdict

def gen_unmarked_bracket_mappings(docgraph, unmarked_potential_markables):

    # a token node can be part of more than one markable/span
    opening = defaultdict(list)
    closing = defaultdict(list)
    
    for unmarked_phrase_id in unmarked_potential_markables:
        span_node_ids = dg.get_span(docgraph, unmarked_phrase_id)
        first = span_node_ids[0]
        last = span_node_ids[-1]
        opening[first].append(unmarked_phrase_id)
        closing[last].append(unmarked_phrase_id)
    return opening, closing

In [6]:
def gen_bracketed_output_for_unmarkables(docgraph):
    ret_str = u''
    unmarked_potential_markables = get_unmarked_potential_markables(docgraph)
    opening, closing = gen_unmarked_bracket_mappings(docgraph, unmarked_potential_markables)
    for tok_id in docgraph.tokens:
        token = docgraph.get_token(tok_id)
        if tok_id in opening:
            ret_str += u"[{} ".format(token)
        elif tok_id in closing:
            ret_str += u"{0}]_{{{1}}} ".format(token, 'UNMARKED: '+' '.join(closing[tok_id]))
        else:
            ret_str += u"{} ".format(token)
    return ret_str

In [7]:
from discoursegraphs.readwrite.brackets import gen_bracket_mappings, gen_closing_string

def gen_bracketed_output(docgraph, layer='mmax'):
    '''

    TODO: the order of the opening brackets should be determined (e.g. if
    a token marks the beginning of two markables, we could check if the
    first markable subsumes the second markable or vice versa.)

    Example
    -------
    Die Diskussion , wie teuer [die neue [Wittstocker]_{markable_22}
    Stadthalle]_{markable_21} für Vereine und Veranstalter wird , hat
    einige Zeit in Anspruch genommen .
    Die Betriebskosten [für den schmucken Veranstaltungsort]_{markable_21}
    sind hoch . Jetzt wird es darum gehen , [die Halle]_{markable_21} so oft
    wie möglich zu füllen .
    Und [in der Region]_{markable_22} gibt es Konkurrenz .
    '''
    opening, closing, markable2chain = gen_bracket_mappings(docgraph, layer=layer)
    
    unmarked_potential_markables = get_unmarked_potential_markables(docgraph)
    unmark_opening, unmark_closing = gen_unmarked_bracket_mappings(docgraph, unmarked_potential_markables)
    
    ret_str = u''
    stack = []
    for token_id in docgraph.tokens:
        token_str = docgraph.get_token(token_id)
        if token_id in opening:
            num_of_opening_brackets = len(opening[token_id])
            stack.extend(opening[token_id])
            opening_str = u'[' * num_of_opening_brackets

            if token_id in closing:
                # token is both the first and last element of 1+ markables
                closing_str = gen_closing_string(closing, markable2chain,
                                                 token_id, stack)
                ret_str += u'{0}{1}{2} '.format(opening_str, token_str,
                                                closing_str)
            else: # token is the first element of 1+ markables
                ret_str += u'{0}{1} '.format(opening_str, token_str)
        elif token_id in closing:
            closing_str = gen_closing_string(closing, markable2chain,
                                             token_id, stack)
            ret_str += u'{0}{1} '.format(token_str, closing_str)

        # token is not part of a markable, but of an (unmarked) NP/PP
        elif token_id in unmark_opening:
            num_of_opening_brackets = len(unmark_opening[token_id])
            stack.extend(unmark_opening[token_id])
            opening_str = u'//' * num_of_opening_brackets

            if token_id in unmark_closing:
                # token is both the first and last element of 1+ markables
#                 ret_str += u"{0}//_{{{1}}} ".format(token_str, 'UNMARKED: '+' '.join(unmark_closing[token_id]))
                ret_str += token_str + gen_unmark_closing_string(unmark_closing, token_id, stack)
                
                
            else: # token is the first element of 1+ markables
                ret_str += u'{0}{1} '.format(opening_str, token_str)            
        elif token_id in unmark_closing:
#             ret_str += u"{0}//_{{{1}}} ".format(token_str, 'UNMARKED: '+' '.join(unmark_closing[token_id]))
            ret_str += token_str + gen_unmark_closing_string(unmark_closing, token_id, stack)
            
            
            
        else: # token is not part of any span
            ret_str += u'{} '.format(token_str)
    return ret_str

In [8]:
def gen_unmark_closing_string(closing_dict, token_id, stack):
    num_of_closing_brackets = len(closing_dict[token_id])
    closing_markable_ids = [stack.pop()
                            for i in range(num_of_closing_brackets)]
    return u''.join(u'//_{{{}}}'.format(cmi) for cmi in closing_markable_ids) + u' '

In [9]:
import itertools

MMAX_BAD_FILE = os.path.expanduser('~/corpora/potsdam-commentary-corpus-2.0.0/coreference/maz-14172.mmax')

# Traceback (most recent call last):
#   File "<ipython-input-9-6e65fa629262>", line 11, in <module>
#     print gen_bracketed_output(mdg)
#   File "<ipython-input-7-c182c063225c>", line 20, in gen_bracketed_output
#     opening, closing, markable2chain = gen_bracket_mappings(docgraph)
#   File "/usr/local/lib/python2.7/dist-packages/discoursegraphs-0.1.2-py2.7.egg/discoursegraphs/readwrite/brackets.py", line 41, in gen_bracket_mappings
#     docgraph, docgraph.node[markable][docgraph.ns+':span'])
# KeyError: 'mmax:span'

mdg = dg.read_mmax2(MMAX_BAD_FILE)

generate a file that contains all markables and potential markables


In [19]:
import sys
import traceback
import codecs

with codecs.open('/tmp/unmarked_markables.txt', 'w', encoding='utf-8') as outfile:
    for mmax_file in sorted(glob.glob(MMAX_ROOT_DIR+'*.mmax'), key=dg.util.natural_sort_key)[:5]:
        mdg = dg.read_mmax2(mmax_file)
        doc_id = os.path.basename(mmax_file).split('.')[0]
        tdg = dg.read_tiger(os.path.join(TIGER_ROOT_DIR, doc_id+'.xml'))
        mdg.merge_graphs(tdg)
#         outfile.write(u"{}\n{}\n\n".format(mdg.name, gen_bracketed_output(mdg, layer='mmax')))
        sys.stdout.write(u"{}\n{}\n\n".format(mdg.name, gen_bracketed_output(mdg, layer='mmax')))


maz-00001.mmax
//Auf Eis//_{s2165_500} gelegt [[Dagmar Ziegler]_{markable_23}]_{markable_23} sitzt [in der Schuldenfalle]_{markable_12} . Auf Grund [der dramatischen Kassenlage [in Brandenburg]_{markable_90}]_{markable_12} hat [[sie]_{markable_23}]_{markable_23} jetzt [[eine seit mehr als einem Jahr erarbeitete Kabinettsvorlage]_{markable_64}]_{markable_64} überraschend //auf Eis//_{s2167_502} gelegt und vorgeschlagen , //erst 2003//_{s2167_503} [[darüber]_{markable_64}]_{markable_64} zu entscheiden . Überraschend , weil [das Finanz-]_{markable_23} und [das Bildungsressort]_{markable_1000139} [[das Lehrerpersonalkonzept]_{markable_64}]_{markable_64} gemeinsam entwickelt hatten . Der Rückzieher [der Finanzministerin]_{markable_31} ist aber verständlich . Es dürfte derzeit schwer zu vermitteln sein , weshalb //ein Ressort//_{s2170_501} pauschal //von künftigen Einsparungen//_{s2170_502} ausgenommen werden soll auf Kosten [der anderen]_{markable_1000193} . [[Reiches]_{markable_1000193} Ministerkollegen]_{markable_1000139} werden //mit Argusaugen//_{s2171_501} darüber wachen , dass [[das Konzept]_{markable_64}]_{markable_64} wasserdicht ist . Tatsächlich gibt es //noch etliche offene Fragen//_{s2172_500} . So ist etwa unklar , wer Abfindungen erhalten soll , oder was passiert , wenn //zu wenig Lehrer//_{s2173_504} [die Angebote des vorzeitigen Ausstiegs]_{markable_64} nutzen . Dennoch gibt es [zu [Reiches]_{markable_1000139} Personalpapier]_{markable_1000194} eigentlich keine Alternative . [Das Land]_{markable_90} hat künftig //zu wenig Arbeit //für zu viele Pädagogen//_{s2175_503}//_{s2175_504} . Und //die Zeit//_{s2176_500} drängt . Der große Einbruch der Schülerzahlen an den weiterführenden Schulen beginnt bereits im Herbst 2003 . [Die Regierung]_{markable_90} muss sich entscheiden , und zwar schnell . Entweder sparen //um jeden Preis//_{s2179_500} oder Priorität für die Bildung . 

maz-00002.mmax
Das Büchergeld Die Litanei ist nicht neu : Eltern beschweren sich //über veraltete Schulbücher//_{s2182_500} , Kommunen jammern //über leere Kassen//_{s2182_501} und [Schulbuchverlage]_{markable_33} beklagen Umsatzeinbrüche . Trommeln gehört halt zum Geschäft . Doch //unterm Strich//_{s2184_500} stehen [Brandenburgs]_{markable_64} Schulen ganz gut da . //Zum einen//_{s2185_500} wurden nach der Wende //fast alle Schulbuchbestände//_{s2185_507} ausgetauscht , //zum anderen//_{s2185_503} müssen sich //märkische Eltern//_{s2185_504} [am Buchkauf]_{markable_69} beteiligen . Dafür gibt es sogar Lob [von den Schulbuchverlagen]_{markable_33} . Denn //in vielen alten Bundesländern//_{s2187_500} gilt noch immer [die Lernmittelfreiheit]_{markable_100090} : Eltern müssen nichts zuzahlen . Der Preis [dafür]_{markable_100090} ist hoch - gerade dort wird oft //mit völlig veraltetem Material//_{s2189_504} gearbeitet . Doch [auch Brandenburg]_{markable_64} muss aufpassen . Wenn //immer mehr Kommunen//_{s2191_503} finanziell ausbluten , wird [die regelmäßige Schulbucherneuerung]_{markable_69} //zur Illusion//_{s2191_502} . Deshalb ist [auch die Landesregierung]_{markable_64} gefragt : Es kann nicht sein , dass ////für teure Modellprojekte wie Schnellläuferklassen oder Ganztagsschulen//_{s2193_504}//_{s2193_504} Geld locker gemacht , aber [an der Grundausstattung]_{markable_69} gespart wird . 

maz-1423.mmax
Zum Angewöhnen Die Diskussion , wie teuer [die neue [Wittstocker]_{markable_22} Stadthalle]_{markable_21} //für Vereine und Veranstalter//_{s525_505} wird , hat //einige Zeit//_{s525_503} //in Anspruch//_{s525_504} genommen . Bei der jüngsten Sitzung haben die Stadtverordneten entschieden . ////Vor allem//_{s527_503} kommerzielle Veranstalter//_{s527_500} werden //ab 2002//_{s527_501} gut //zur Kasse//_{s527_502} gebeten . Die Einnahmen sind dennoch //nur ein Tropfen //auf den heißen Stein//_{s528_501}//_{s528_502} . Die Betriebskosten [für den schmucken Veranstaltungsort]_{markable_21} sind hoch . Jetzt wird es darum gehen , [die Halle]_{markable_21} so oft wie möglich zu füllen . //Je mehr Veranstaltungen//_{s531_502} stattfinden , desto weniger wird der Stadthaushalt belastet . [Die Halle]_{markable_21} muss ausgelastet sein . Und [in der Region]_{markable_22} gibt es Konkurrenz . Auch die Nachbarstädte bieten Veranstaltern //genügend Platz//_{s534_501} . [Wittstock]_{markable_22} dagegen muss sich erst //einen Namen//_{s535_501} machen . Das Oktoberfest hat gezeigt , dass es //eine Anlaufzeit//_{s536_501} braucht . Die Gäste aus nah und fern müssen sich erst daran gewöhnen , nach [Wittstock]_{markable_22} und Richtung Gymnasium zu pilgern . Fest steht , dass [die Dosse-Stadt]_{markable_22} //als Mittelzentrum//_{s538_500} //ohne einen ansehnlichen Veranstaltungsort //mit ausreichend Platz //fürs Publikum//_{s538_501}//_{s538_503}//_{s538_504} nicht auskommt . Ohne [die Halle]_{markable_21} würde [Wittstock]_{markable_22} bald //ins Hintertreffen//_{s539_501} geraten . 

maz-1453.mmax
Zeit //für Frieden//_{s573_500} //Mit großer Mehrheit//_{s574_500} haben sich [[die Damsdorfer]_{markable_27}]_{markable_27} am Sonntag für den Wechsel und [[für Lehnin]_{markable_1000172}]_{markable_1000172} entschieden . //Als Erfolg//_{s575_500} können sich [die Damsdorfer Kommunalpolitiker]_{markable_100032} ////vor allem//_{s575_503} eins//_{s575_502} anrechnen : Dass es [ihnen]_{markable_100032} gelungen ist , //fast 700 Menschen//_{s576_504} zum Urnengang zu mobilisieren . [[Die Damsdorfer]_{markable_27}]_{markable_27} haben gezeigt , dass [die Bevölkerung]_{markable_27} das Recht auf einen Bürgerentscheid sehr wohl zu schätzen weiß . Aus dem Ergebnis lassen sich //drei Dinge//_{s578_501} ablesen : [Die Damsdorfer]_{markable_1000176} haben von Emster-Havel , vom dortigen Amtsausschuss und peinlichen Gezänk , //die Nase//_{s579_504} voll . Nach dem Motto , schlechter kann es woanders kaum werden . //Punkt zwei//_{s581_500} : [Die Lehniner Gemeinden]_{markable_57} machen //nach außen hin//_{s581_502} - //trotz aller Meinungsverschiedenheiten//_{s581_503} - //einen relativ geschlossenen Eindruck//_{s581_505} . Die Politik im dortigen Amtsausschuss läuft eben nicht nach dem Emster-Muster : Dorf gegen Dorf , Bündnis gegen Bündnis . Aus dem Ergebnis lässt sich drittens ableiten , dass sich [die Damsdorfer]_{markable_1000176} längst vom Emster-Amt verabschiedet haben . [Sie]_{markable_1000176} wollen das vollzogen wissen , was [sie]_{markable_1000176} täglich leben , die Nähe [zu Lehnin]_{markable_1000172} . Davon konnte [sie]_{markable_1000176} auch die Bürgerinitiative Pro Emster nicht abbringen . Jetzt ist Zeit , in die Reform- Debatte //endlich zivilisierten Frieden//_{s586_501} einkehren zu lassen . 

maz-1679.mmax
Stadtkern aufwerten Im Streit zwischen [der Stadt Wittstock]_{markable_100020} und dem Landesstraßenbauamt Kyritz hat Bürgermeister Lutz Scheidemann [einen klaren Sieg]_{markable_36} errungen . [Wittstock]_{markable_100020} wird //in einigen Jahren//_{s878_500} frei //von Lkw-Verkehr//_{s878_501} sein , [eine Umgehung]_{markable_51} entlastet [die Innenstadt]_{markable_82} . Klirrende Gläser in den Wohnzimmerschränken sind dann Geschichte . [Wer]_{markable_100046} [sein]_{markable_100046} Haus bereits saniert hat , muss auch nicht mehr befürchten , dass der Putz von der Fassade fällt . [Mit der Einigung]_{markable_36} kommt aber [auf die Wittstocker]_{markable_100079} //eine große Herausforderung//_{s881_502} zu . [Sie]_{markable_100079} sind aufgefordert , über neue , sinnvolle Verkehrsabläufe [in der Innenstadt]_{markable_82} nachzudenken . [Die Entlastungsstraße für Lkw]_{markable_51} führt zwar [um die Altstadt herum]_{markable_82} , doch //eine autofreie Stadt//_{s883_502} wird es nicht geben . So braucht sich //auch kein Geschäftsmann//_{s884_500} //vor einer leeren Altstadt//_{s884_501} zu fürchten . Gut beraten ist allerdings , wer sich jetzt //ernsthafte Gedanken //um kundenfreundliche Parkmöglichkeiten//_{s885_501}//_{s885_502} macht . Auch Flaniermeilen [in der Wittstocker Altstadt]_{markable_82} sind gefragt . Denn //ohne Lkw-Verkehr//_{s887_500} wird es ruhiger werden , der Stadtbummel kann wieder Spaß machen . Deshalb müssen //neue Ideen//_{s888_500} her , um [die Wittstocker Altstadt]_{markable_82} lebenswerter zu machen .