Frage zu verschachtelten Dictionaries

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Luki
User
Beiträge: 11
Registriert: Dienstag 18. März 2014, 10:41

Ich bin ein Python-Neuling, daher bitte ich um Nachsicht, wenn ich mich etwas blöd anstelle ;-)

Ich habe eine lange Liste a= [sagen, Verb, Haus, Nomen, laufen, Verb, leicht, Adjektiv, laufen, Verb, sagen, Verb ...]
Daraus möchte ich folgendes Dictionary erstellen: wortarten = {"Nomen": {"Haus":1}, "Verb": {"laufen":1, "sagen":2}, "Adjektiv": {"leicht":1} ...}

Ich habe mal ein dictionary erstellt, dass nur die Wörter ohne Wortart enthält und die jeweiligen Häufigkeiten.

Code: Alles auswählen

haeufigkeit = {}
for index in range(len(a[::2])-1):
	wort = a[::2][index]
	if wort in haeufigkeit:
		haeufigkeit[wort] += 1
	else:
		haeufigkeit[wort] = 1
print(haeufigkeit)
So erhalte ich ein dictionary haeufigkeit = {"Haus":1, "laufen":1, "sagen":2, "leicht":1}.

Jetzt komme ich nicht mehr weiter. Wie füge ich die Wortart nun als Schlüssel hinzu? Ich vermute ja, dass es der falsche Weg ist, erst das dictionary "haeufigkeit" zu erstellen, aber ich habe keine andere Idee.


Und vielleicht kennt jemand ein gutes ausführliches Tutorial zum Thema dictionaries, dass auch ausführlich auf Verschachtelungsmöglichkeiten eingeht. ;-) Ich habe da leider nichts gefunden, was mir hier helfen könnte.
BlackJack

@Luki: Das bisherige vorgehen ist falsch, denn wenn es ein Wort gibt das in mehrere Kategorien fallen kann, bekommst Du am Ende die Anzahl nicht mehr aufgeteilt, jedenfalls nicht ohne die Eingangsdaten wieder durchlaufen zu müssen.

Ich würde mich hier auch gar nicht erst mit dem normalen `dict` herumschlagen sondern gleich `collection.defaultdict` verwenden.

Wie ist denn die Ausgangsliste zustande gekommen? Die ist ungünstig organisiert. Wenn immer zwei aufeinanderfolgende Elemente zusammen gehören, dann sollten die zu jeweils einem Element zusammengefasst werden. Zum Beispiel in einer Liste oder einem Tupel.

Code: Alles auswählen

#!/usr/bin/env python
from collections import defaultdict
from itertools import izip


def main():
    data = [
        'sagen', 'Verb', 'Haus', 'Nomen', 'laufen', 'Verb', 'leicht',
        'Adjektiv', 'laufen', 'Verb', 'sagen', 'Verb'
    ]

    category2histogram = defaultdict(lambda: defaultdict(int))
    items = iter(data)
    for word, category in izip(items, items):
        category2histogram[category][word] += 1

    for category, histogram in category2histogram.viewitems():
        print category
        for word, count in histogram.viewitems():
            print '{0:5d} - {1}'.format(count, word)


if __name__ == '__main__':
    main()
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Hallo Luki,

am besten baust du dir Struktur von außen auf, d.h. fang erst mit den Worttypen an.

Code: Alles auswählen

a = ["sagen", "Verb", "Haus", "Nomen", "laufen", "Verb", "leicht", "Adjektiv", "laufen", "Verb", "sagen", "Verb"]
zipped_a = zip(a[::2], a[1::2])
#  [('sagen', 'Verb'),  ('Haus', 'Nomen'),  ('laufen', 'Verb'),  ('leicht', 'Adjektiv'),  ('laufen', 'Verb'),  ('sagen', 'Verb')] 
Jetzt gibts hier ein paar Tricks wie man weiter machen kann.

Code: Alles auswählen

from collections import defaultdict, Counter
words = defaultdict(list)
for word, word_type in zipped_a:
    words[word_type].append(word)

# defaultdict(<type 'list'>, {'Nomen': ['Haus'], 'Verb': ['sagen', 'laufen', 'laufen', 'sagen'], 'Adjektiv': ['leicht']})
Um die Wörter zu zählen gibts es bereits eine Klasse in der Standardbibliothek. Diese habe ich oben schon importiert (Counter).

Code: Alles auswählen

counted_words = dict()
for key, value in words:
    counted_words[key] = Counter(value)
# {'Adjektiv': Counter({'leicht': 1}),  'Nomen': Counter({'Haus': 1}),  'Verb': Counter({'sagen': 2, 'laufen': 2})}
Das ist ungefähr das was du habenen willst. Wenn du Fragen hast nur her damit :)

Grüße,
anogayales
Luki
User
Beiträge: 11
Registriert: Dienstag 18. März 2014, 10:41

Ich habe ein Textdokument, in dem jedes Wort mit der Wortart getagged ist, also die Wortart steht hinter dem Wort in der Textdatei. Den Inhalt habe ich in eine Liste gepackt.

Bei mir funktioniert izip nicht, kann es sein, dass das bei Python 3 anders heißt?
Luki
User
Beiträge: 11
Registriert: Dienstag 18. März 2014, 10:41

@anogayales

Ich möchte die Ergebnisse später untereinander in eine Textdatei schreiben, da sollte das "Counter" nicht mit erscheinen.

Also so:

Wortart Wort1 Häufigkeit Wort2 Häufigkeit
Luki
User
Beiträge: 11
Registriert: Dienstag 18. März 2014, 10:41

Alternativ habe ich das versucht:

Code: Alles auswählen


a= ["sagen", "Verb", "Haus", "Nomen", "laufen", "Verb", "leicht", "Adjektiv", "laufen", "Verb", "sagen", "Verb"]            

haeufigkeiten = {}
for index in range(0,len(a)-1,2):
    wort = a[index+1] + " " + a[index]
    if wort in haeufigkeiten:
        haeufigkeiten[wort] += 1
    else:
        haeufigkeiten[wort] = 1
print(haeufigkeiten)


Meine Ausgabe ist:

{'Adjektiv leicht': 1, 'Verb laufen': 2, 'Nomen Haus': 1, 'Verb sagen': 2}


Auch das führt mich nicht zum Ergebnis. :-P
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Luki hat geschrieben:Bei mir funktioniert izip nicht, kann es sein, dass das bei Python 3 anders heißt?
In Python 3 entspricht zip dem itertools.izip von Python 2.
Luki
User
Beiträge: 11
Registriert: Dienstag 18. März 2014, 10:41

@ Blackjack

Da ich deinen Code nicht so ganz verstanden habe, habe ich ihn mal getestet. Ich bekomme folgende Fehlermeldung:

for category, histogram in category2histogram.viewitems():
AttributeError: 'collections.defaultdict' object has no attribute 'viewitems'
BlackJack

@Luki: Wie schon festgestellt wurde verwende ich Python 2. Bei 3 kannst Du das `viewitems` in `items` umbenennen.
Luki
User
Beiträge: 11
Registriert: Dienstag 18. März 2014, 10:41

@ Blackjack
Du hast mir auf jeden Fall schon weitergeholfen, aber mir ist das Ausgabeformat wichtig. Ich habe mal das aus deinem Code genommen:

Code: Alles auswählen

data = ['sagen', 'Verb', 'Haus', 'Nomen', 'laufen', 'Verb', 'leicht',
        'Adjektiv', 'laufen', 'Verb', 'sagen', 'Verb']
category2histogram = defaultdict(lambda: defaultdict(int))
items = iter(data)
for word, category in zip(items, items):
    category2histogram[category][word] += 1
print (category2histogram)

#Ausgabe defaultdict(<function <lambda> at 0x024F3540>, {'Nomen': defaultdict(<class 'int'>, {'Haus': 1}), 'Verb': defaultdict(<class 'int'>, {'sagen': 2, 'laufen': 2}), 'Adjektiv': defaultdict(<class 'int'>, {'leicht': 1})})
Bekomme ich jetzt das defaultdict(<function <lambda> at 0x024F3540> und das defaultdict(<class 'int'> irgendwie weg? Dann hätte ich nämlich genau das, was ich optisch zunächst haben will. :-)
BlackJack

@Luki: Du musst Dir halt das Ergebnis dann so zusammenbauen wie Du das brauchst. Die Zeichenkettendarstellungen direkt von irgendwelchen Containerobjekten zu verwenden ist eigentlich nie eine gute Idee.
Luki
User
Beiträge: 11
Registriert: Dienstag 18. März 2014, 10:41

BlackJack hat geschrieben:@Luki: Du musst Dir halt das Ergebnis dann so zusammenbauen wie Du das brauchst. Die Zeichenkettendarstellungen direkt von irgendwelchen Containerobjekten zu verwenden ist eigentlich nie eine gute Idee.


Da hapert es leider :oops: :oops:

Code: Alles auswählen

data = ['sagen', 'Verb','Haus', 'Nomen', 'laufen', 'Verb', 'leicht',
        'Adj', 'laufen', 'Verb', 'sagen', 'Verb']
 
category2histogram = defaultdict(lambda: defaultdict(int))
items = iter(data)
for word, category in zip(items, items):
    category2histogram[category][word] += 1
for category, histogram in category2histogram.items():
    print (category, end=" ")
    for word, count in histogram.items():
        #print (count, word, end=" ")
        print ('\t {0} \t {1}'.format(word,count))

#Ausgabe 
Nomen 	 Haus 	 1
Adj 	 leicht 	 1
Verb 	 sagen 	 2
	 laufen 	 2
Ich möchte das Verb laufen in der gleichen Zeile haben wie den Abschnitt Verb sagen 2, also Verb sagen 2 laufen 2
DaftWullie
User
Beiträge: 37
Registriert: Donnerstag 17. Mai 2012, 21:28

Du könntest doch das print in Zeile 12 leicht anpassen:

Code: Alles auswählen

       print ('\t {0} \t {1}'.format(word,count), end='')
Luki
User
Beiträge: 11
Registriert: Dienstag 18. März 2014, 10:41

DaftWullie hat geschrieben:Du könntest doch das print in Zeile 12 leicht anpassen:

Code: Alles auswählen

       print ('\t {0} \t {1}'.format(word,count), end='')

Schon probiert, dann ist aber alles in einer Zeile ;-)
BlackJack

@Luki: Dann überlege doch mal an welcher Stelle im Programmfluss ein neue Zeile mit ``print()`` begonnen werden muss.
Luki
User
Beiträge: 11
Registriert: Dienstag 18. März 2014, 10:41

BlackJack hat geschrieben:@Luki: Dann überlege doch mal an welcher Stelle im Programmfluss ein neue Zeile mit ``print()`` begonnen werden muss.

:idea: :idea: :idea:

print() am Ende auf gleicher Höhe mit der for-Schleife :D

Danke für den Schubser :-)
Luki
User
Beiträge: 11
Registriert: Dienstag 18. März 2014, 10:41

So, jetzt habe ich noch eine kleine Frage:

Ich habe ein dictionary der Form {"a":{"b":0.1}, "c":{"d":0.1}, "d":{"e":0.1}}

Ich möchte, dass es so in der Ausgabe aussieht:

a b 0.1
c d 0.1
d e 0.1

Mit den Buchstaben ist das kein Problem, aber ich weiß nicht, wie ich auf die Zahl zugreife.

Code: Alles auswählen


a = {"a":{"b":0.1}, "c":{"d":0.1}, "d":{"e":0.1}}
for key in a:
    print(key, end="\t")
    for key in a[key]:
        print (key, end="\n")
        #print (a[key]) 
# Ausgabe 
#c	 d
#a	 b
#d	 e
       
Die letzte ausgeklammerte Print-Anweisung lässt mich nicht auf die Zahl zugreifen, ich erhalte einen Key-Error.
Kann mir jemand sagen, wo mein Denkfehler ist?
Luki
User
Beiträge: 11
Registriert: Dienstag 18. März 2014, 10:41

Luki hat geschrieben:So, jetzt habe ich noch eine kleine Frage:

Ich habe ein dictionary der Form {"a":{"b":0.1}, "c":{"d":0.1}, "d":{"e":0.1}}

Habe es rausgefunden :D :D :D

Code: Alles auswählen

a = {"a":{"b":0.1}, "c":{"d":0.1}, "d":{"e":0.1}}
for key in a:
    print(key, end="\t")
    a_neu = (a[key])
    for key in a[key]:
        print (key, end="\t")
        print (a_neu[key])
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das geht noch einfacher:

Code: Alles auswählen

a = {"a":{"b":0.1}, "c":{"d":0.1}, "d":{"e":0.1}}
for key, values in a.items():
    print(key, end="\t")
    
    for key2, value in values.items():
        print(key2, end="\t")
        print(value)
Das Leben ist wie ein Tennisball.
Antworten