Programm für Textanalyse

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.
M***

Samstag 7. April 2007, 22:09

Hallo allerseits.

Ich habe Grundkenntnisse in Python, aber es reicht leider nicht für das, was ich programmieren möchte. Ich möchte ein Programm erstellen, das einen Text analysiert.

Ich möchte nicht, dass mir jemand das Programm schreibt, das ist klar. Aber für Tips und Anregungen, wie und mit welchen Funktionen ich am besten vorgehe, bin ich sehr dankbar. Herumprobieren mache gerne ich alleine. ;)

So habe ich es mir gedacht:

----------

Textdatei einlesen (*.txt)

----------

Leerzeichen belassen oder in Punkte umwandeln.
Text in Kleinbuchstaben umwandeln.
Sonderzeichen löschen, ignorieren oder in 0 umwandeln.

=> In neue Datei (text.txt) schreiben (Ausgangsdatei soll nicht geändert werden.)

----------

Aus text.txt die Wörter und die Buchstaben einzeln zählen.

----------

Auswertung/Statistik

Es wurden 680 Wörter analysiert

Buchstaben gesamt: 3400
- davon "A" bzw. "a": 279 = 8.2 %
- davon "B" bzw. "b": 150 = 4.4 % usw.

----------

Den Anfang habe ich in etwa:

Code: Alles auswählen

datei = file('text.txt','r')
text = datei.read()
datei.close()

# Hier habe ich nur etwas ausprobiert, das an der Stelle noch nicht passieren soll.
laenge = len(text)
print(laenge)
Mir wurde schon geraten, mit Dictionaries zu arbeiten. Allerdings weiß ich nicht genau, wie ich das bewerkstellige und ob es nicht etwas simpleres gibt.

Für eure Hilfe bin ich euch sehr dankbar.
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Samstag 7. April 2007, 22:29

Marc hat geschrieben:Hallo allerseits.

Ich habe Grundkenntnisse in Python, aber es reicht leider nicht für das, was ich programmieren möchte. Ich möchte ein Programm erstellen, das einen Text analysiert.

Ich möchte nicht, dass mir jemand das Programm schreibt, das ist klar. Aber für Tips und Anregungen, wie und mit welchen Funktionen ich am besten vorgehe, bin ich sehr dankbar. Herumprobieren mache gerne ich alleine. ;)
Werd ich bestimmt nicht ;) dafür bin ich viel zu Müde :) :)
Marc hat geschrieben: So habe ich es mir gedacht:
Textdatei einlesen (*.txt)
Marc hat geschrieben:

Code: Alles auswählen

datei = file('text.txt','r')
text = datei.read()
datei.close()
Ham wa ja schonmal ;)
Leerzeichen belassen oder in Punkte umwandeln.
Darf man fragen wozu in Punkte umwandeln, bzw. wie du dir das rein theoretisch vorgestellt hast
Text in kleinbuchstaben umwandeln.
Das ist kein Problem:

Code: Alles auswählen

In [1]: "Ich bin ein Text".lower()
Out[1]: 'ich bin ein text'
Sonderzeichen löschen, ignorieren oder in 0 umwandeln.
Ohh... da gehts schonmal los. Auswahlkriterien, was für Sonderzeichen meinst du (alle Zeichen, die nicht im ASCII Raum liegen?)?
=> In neue Datei (text.txt) schreiben (Ausgangsdatei soll nicht geändert werden.)
Vorher unbedingt noch überprüfen, ob nicht schon eine ``text.txt`` existier, denn wenn du die Überschreibst könnte der Text weg sein :)

Code: Alles auswählen

In [4]: os.path.exists('/home/ente/test.py')
Out[4]: True
Aus text.txt die Wörter und die Buchstaben einzeln zählen.
Auswertung/Statistik

Es wurden 680 Wörter analysiert

Buchstaben gesamt: 3400
Das lässt sich genauso einfach machen, wie das "Alle Buchstaben klein machen".

Code: Alles auswählen

In [5]: text = '''Ich bin einfach mal ein wenig Text
   ...: Um hier ein gutes Beispiel zu geben'''

In [6]: words = len(text.split(' '))

In [7]: chars = len(text) # wie selber ja schon herausgefunden ;)

In [8]: print 'Es wurden %d Wörter analysiert.' % words
Es wurden 13 Wörter analysiert.

In [9]: print 'Buchstaben gesamt: %d' % chars
Buchstaben gesamt: 70
Das mit der Prozentberechnung ist dann ein wenig komplizierter, was du ja selber machen magst ;)

Ich hoffe ich konnte dir einen kleinen Anfang gebem.

MfG EnTeQuAk

PS: für sämtliche Fehler ist die Uhrzeit schult ;)[/code]
M***

Samstag 7. April 2007, 23:35

Vielen Dank schonmal. Das gibt mir einen guten Einblick.
Darf man fragen wozu in Punkte umwandeln, bzw. wie du dir das rein theoretisch vorgestellt hast
Ich wusste nicht genau, wie die Leerzeichen gezählt werden. Deswegen dachte ich, dass ich die umwandle und später beim Zählen ausschließe. Falsch gedacht. ;)
Ohh... da gehts schonmal los. Auswahlkriterien, was für Sonderzeichen meinst du (alle Zeichen, die nicht im ASCII Raum liegen?)?
Ich sage es mal so. Es sollen nur die 26 Zeichen des Alphabets bleiben, alle anderen können raus, sollen nicht mitgezählt werden.


Ich könnte den Schritt des Aspeicherns des Textes nachdem Löschen der Sonderzeichen etc. eigentlich weglassen, oder?

Was aus Python kann ich verwenden, um die Buchstaben einzeln zu zählen?
Sprich: Wenn ein "a" gezählt wird, dann:

Code: Alles auswählen

anzahl_a += 1
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Samstag 7. April 2007, 23:48

Hi Marc!

Willkommen im Python-Forum!
Marc hat geschrieben:Ich sage es mal so. Es sollen nur die 26 Zeichen des Alphabets bleiben, alle anderen können raus, sollen nicht mitgezählt werden.

Code: Alles auswählen

>>> import string
>>> old_string = "asdf12345"
>>> string.ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> new_string = "".join([ char for char in old_string if char in string.ascii_letters ])
>>> new_string
'asdf'
>>> 
Marc hat geschrieben:Was aus Python kann ich verwenden, um die Buchstaben einzeln zu zählen?
http://www.python-forum.de/viewtopic.php?p=62261

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
M***

Sonntag 8. April 2007, 02:09

Danke, das hat mir geholfen.

Ein Problem besteht aber leider noch. Wenn in dem zu analysierenden Text ein Buchstabe nicht vorkommt, wird folglich auch kein Eintrag im Dictionary vorgenommen.

Code: Alles auswählen

frequencies = dict()
for word in text:
    frequencies[word] = frequencies.get(word, 0) + 1
In der Auswertung ist folgendes vorhanden:

Code: Alles auswählen

print '- davon "Q" / "q": %s = %s %%' % (frequencies['q'], ((frequencies ['q']*100)/chars))
Es folgt die Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "F:\Dokumente\Schule\Oberstufe\E-Phase\Material\Informatik PK\Kryptografie\textanalyse.py", line 62, in <module>
    print '- davon "Q" / "q": %s = %s %%' % (frequencies['q'], ((frequencies ['q']*100)/chars))
KeyError: 'q'

Was muss ich tun, damit ein, aufgrund im Text nicht vorhandener Buchstabe, fehlender Eintrag im Dictionary ignoriert wird? Oder anders: Wie kann ich das Problem am einfachsten umgehen?
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Sonntag 8. April 2007, 06:32

Code: Alles auswählen

for char in string.ascii_lowercase:
    if char in frequencies:
        print '- davon "%s" / "%s": %s = %s %%' % \
              (char.upper(), char,  frequencies[char],
              ((frequencies[char]*100)/chars))
MfG
HWK
BlackJack

Sonntag 8. April 2007, 09:24

Da es sich ja nur um 26 Buchstaben handelt, kann man auch einfach ein Dictionary erstellen bei dem jedem Buchstaben eine 0 als Startwert zugerodnet ist:

Code: Alles auswählen

In [2]: dict.fromkeys(string.ascii_lowercase, 0)
Out[2]:
{'a': 0,
 'b': 0,
 'c': 0,
 'd': 0,
 'e': 0,
 'f': 0,
 'g': 0,
 'h': 0,
 'i': 0,
 'j': 0,
 'k': 0,
 'l': 0,
 'm': 0,
 'n': 0,
 'o': 0,
 'p': 0,
 'q': 0,
 'r': 0,
 's': 0,
 't': 0,
 'u': 0,
 'v': 0,
 'w': 0,
 'x': 0,
 'y': 0,
 'z': 0}
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Sonntag 8. April 2007, 09:50

Weil hier alle mit dem "string" Modul herumwurschteln hab ich jetzt mal eine Version mit "unicodedata" gemacht. Vorteile: Funktioniert automatisch für alle Sprachen, inkl. Umlauten etc. Außerdem ist der Quellcode sehr klein und leicht verständlich, wenn man von der NFKC Normalisierung absieht.

Code: Alles auswählen

# -*- coding: utf-8 -*-
# für die division mit ganzzahlen
from __future__ import division
import re
import unicodedata
import sys
from operator import itemgetter
from collections import defaultdict

# regular expression für buchstaben aber keine zahlen
# und keine unterstriche
word_re = re.compile(r'[^\W\d_]+(?u)')

# ein defaultdict fürs zählen der zahlen
char_mapping = defaultdict(int)

# anzahl der gefundenen zeichen und wörter
char_count = 0
word_count = 0

# text im utf-8 format einlesen und wörter in einen
# iterator stecken
f = file('text.txt', 'r')
try:
    data = f.read().decode('utf-8')
    text_length = len(data)
    worditer = word_re.finditer(data)
finally:
    f.close()

# für jeden treffer wird nur das wort analysiert
# für jedes zeichen im text wird eine unicode NFKC normalisierung
# angewendet um ligaturen etc. wieder zu trennen
# die normalisierten zeichen (können mehr werden) werden nun gezählt
# und in das char_mapping gesteckt.
for word_match in worditer:
    word = word_match.group()
    for char in word:
        for normalized in unicodedata.normalize('NFKC', char.lower()):
            char_mapping[normalized] += 1
            char_count += 1
    word_count += 1

# sortieren nach der häufigkeit in absteigender reihenfolge
stats = sorted(char_mapping.items(), key=itemgetter(1), reverse=True)

# Hilfsfunktion für die Ausgabe von Unicode Strings.
# ohne dem bekommen wir einen unicode encode error
write = lambda x: sys.stdout.write(x.encode(sys.stdout.encoding) + '\n')

# Und Statistiken ausgeben
write(u'Statistiken für die normalisierte Version des Textes')
write(u'  Anzahl der Wörter:             %d' % word_count)
write(u'  Anzahl der erkannten Zeichen:  %d' % char_count)
write(u'  Länge des Textes:              %d\n' % text_length)
write(u'Details:')
for char, occurrences in stats:
    write(u'  %s:%9d%20.3f%%' % (
        char,
        occurrences,
        occurrences / char_count * 100
    ))
TUFKAB – the user formerly known as blackbird
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Sonntag 8. April 2007, 10:07

Code: Alles auswählen

# Hilfsfunktion für die Ausgabe von Unicode Strings.
# ohne dem bekommen wir einen unicode encode error
write = lambda x: sys.stdout.write(x.encode(sys.stdout.encoding) + '\n') 
Huch? Enkodieren mit sys.stdout.encoding tut print auch schon, und ein Newline anhängen ebenso.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Sonntag 8. April 2007, 10:32

birkenfeld hat geschrieben:Huch? Enkodieren mit sys.stdout.encoding tut print auch schon, und ein Newline anhängen ebenso.
Joa. Hier auch. Allerdings war ich mir nicht mehr sicher, ob es das unter Windows auch tut. Warscheinlich hilft meines da aber auch nicht, weil das Windows Terminal Encoding sicher nicht utf-8 ist.
TUFKAB – the user formerly known as blackbird
M***

Sonntag 8. April 2007, 14:26

Erstmal ein großes Dankeschön an alle.

Ich habe in mein Programm jetzt die Lösung von BlackJack eingebaut und als alternative Auswertung den Code von HWK mit eingebaut.

Die Lösung von dir, blackbird ist für die Analyse mehrerer Sprachen natürlich besser, aber ich kann mein Programm besser nachvollziehen, daher auch besser erklären und es reicht aus. Ich werde mir deine Lösung allerdings nochmal genauer anschauen, interessant finde ich sie.

Fertiges Programm zur Textanalyse:

Code: Alles auswählen

#-*- coding: utf-8 -*-
from __future__ import division
import string


print 'Um einen Text zu analysieren, muss der Text in einer Textdatei namens "text.txt" im selben Ordner, indem sich dieses Programm befindet, vorliegen.'
print 'Druecken Sie Enter um die Analyse zu starten.'
raw_input()

# Datei text.txt einlesen und anschließend wieder schließen.
file_in = file('text.txt','r')
old_text = file_in.read()
file_in.close()

# Text in Kleinbuchstaben umwandeln.
old_text = old_text.lower()

# Die Wörter zählen.
words = len(old_text.split(' '))

# Alle Zeichen außer die 26 Zeichen des deutschen Alphabets löschen.
# nutzt "import string"
text = [char for char in old_text if char in string.ascii_letters]

# Die Buchstaben zählen.
chars = len(text)

# Die Anzahl der einzelnen Buchstaben des Alphabets herausfinden.
frequencies = dict.fromkeys(string.ascii_lowercase, 0)
for word in text:
    frequencies[word] = frequencies.get(word, 0) + 1

# Auswertung
# nutzt "from __future__ import division"
print 'Es wurden %d Woerter analysiert. Alle Zeichen, die nicht im deutschen Alphabet (26 Zeichen) vorkommen, wurden ignoriert.' % words
print '\nGesamte Anzahl der Buchstaben: %d' % chars
print '\n- davon "A" / "a": %s = %s %%' % (frequencies['a'], ((frequencies ['a']*100)/chars))
print '- davon "B" / "b": %s = %s %%' % (frequencies['b'], ((frequencies ['b']*100)/chars))
print '- davon "C" / "c": %s = %s %%' % (frequencies['c'], ((frequencies ['c']*100)/chars))
print '- davon "D" / "d": %s = %s %%' % (frequencies['d'], ((frequencies ['d']*100)/chars))
print '- davon "E" / "e": %s = %s %%' % (frequencies['e'], ((frequencies ['e']*100)/chars))
print '- davon "F" / "f": %s = %s %%' % (frequencies['f'], ((frequencies ['f']*100)/chars))
print '- davon "G" / "g": %s = %s %%' % (frequencies['g'], ((frequencies ['g']*100)/chars))
print '- davon "H" / "h": %s = %s %%' % (frequencies['h'], ((frequencies ['h']*100)/chars))
print '- davon "I" / "i": %s = %s %%' % (frequencies['i'], ((frequencies ['i']*100)/chars))
print '- davon "J" / "j": %s = %s %%' % (frequencies['j'], ((frequencies ['j']*100)/chars))
print '- davon "K" / "k": %s = %s %%' % (frequencies['k'], ((frequencies ['k']*100)/chars))
print '- davon "L" / "l": %s = %s %%' % (frequencies['l'], ((frequencies ['l']*100)/chars))
print '- davon "M" / "m": %s = %s %%' % (frequencies['m'], ((frequencies ['m']*100)/chars))
print '- davon "N" / "n": %s = %s %%' % (frequencies['n'], ((frequencies ['n']*100)/chars))
print '- davon "O" / "o": %s = %s %%' % (frequencies['o'], ((frequencies ['o']*100)/chars))
print '- davon "P" / "p": %s = %s %%' % (frequencies['p'], ((frequencies ['p']*100)/chars))
print '- davon "Q" / "q": %s = %s %%' % (frequencies['q'], ((frequencies ['q']*100)/chars))
print '- davon "R" / "r": %s = %s %%' % (frequencies['r'], ((frequencies ['r']*100)/chars))
print '- davon "S" / "s": %s = %s %%' % (frequencies['s'], ((frequencies ['s']*100)/chars))
print '- davon "T" / "t": %s = %s %%' % (frequencies['t'], ((frequencies ['t']*100)/chars))
print '- davon "U" / "u": %s = %s %%' % (frequencies['u'], ((frequencies ['u']*100)/chars))
print '- davon "V" / "v": %s = %s %%' % (frequencies['v'], ((frequencies ['v']*100)/chars))
print '- davon "W" / "w": %s = %s %%' % (frequencies['w'], ((frequencies ['w']*100)/chars))
print '- davon "X" / "x": %s = %s %%' % (frequencies['x'], ((frequencies ['x']*100)/chars))
print '- davon "Y" / "y": %s = %s %%' % (frequencies['y'], ((frequencies ['y']*100)/chars))
print '- davon "Z" / "z": %s = %s %%' % (frequencies['z'], ((frequencies ['z']*100)/chars))

# Alternative Auswertung. (Weniger Quellcode)
# nutzt "from __future__ import division"
#print 'Es wurden %d Woerter analysiert. Alle Zeichen, die nicht im deutschen Alphabet (26 Zeichen) vorkommen, wurden ignoriert.' % words
#print '\nGesamte Anzahl der Buchstaben: %d' % chars
#for char in string.ascii_lowercase:
#    if char in frequencies:
#        print '- davon "%s" / "%s": %s = %s %%' % \
#              (char.upper(), char,  frequencies[char],
#              ((frequencies[char]*100)/chars))
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Sonntag 8. April 2007, 14:38

Deine 26 prints solltest du aber schon noch durch eine Schleife ersetzen.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
M***

Sonntag 8. April 2007, 15:07

Die 26 print-Befehle sind natürlich dazu prädestiniert, durch eine Schleife ersetzt zu werden. Ich werde die Auswertung aber nochmal anpassen, dann benutze ich auch die Schleife.
M***

Sonntag 8. April 2007, 17:23

Nochmal eine Frage wegen einer Schleife.

Ich habe ein Dictionary mit der Häufigkeitsverteilung im deutschen Alphabet angelegt:

Code: Alles auswählen

# Häufigkeitsverteilung im deutschen Alphabet
frequencies_dt = {'a_dt': '6.51',
                  'b_dt': '1.89',
                  'c_dt': '3.06',
                  'd_dt': '5.08',
                  'e_dt': '17.4',
                  'f_dt': '1.66',
                  'g_dt': '3.01',
                  'h_dt': '4.76',
                  'i_dt': '7.55',
                  'j_dt': '0.27',
                  'k_dt': '1.21',
                  'l_dt': '3.44',
                  'm_dt': '2.53',
                  'n_dt': '9.78',
                  'o_dt': '2.51',
                  'p_dt': '0.79',
                  'q_dt': '0.02',
                  'r_dt': '7.00',
                  's_dt': '7.27',
                  't_dt': '6.15',
                  'u_dt': '4.35',
                  'v_dt': '0.67',
                  'w_dt': '1.89',
                  'x_dt': '0.03',
                  'y_dt': '0.04',
                  'z_dt': '1.13'}
Meine Auswertung sieht jetzt so aus:

Code: Alles auswählen

# Auswertung
# nutzt "from __future__ import division"
print 'Es wurden %d Woerter analysiert. Alle Zeichen, die nicht im deutschen Alphabet (26 Zeichen) vorkommen, wurden ignoriert.' % words,
print 'In Klammern steht die Haeufigkeitsverteilung des jeweiligen Buchstaben im deutschen Alphabet.'
print '\nGesamte Anzahl der Buchstaben: %d' % chars
for char in string.ascii_lowercase:
    if char in frequencies:
        print '- davon "%s" / "%s": %s\t=\t%s %%\t(%s)' % (char.upper(), char, frequencies[char], ((frequencies[char]*100)/chars), ?)
Ich möchte jetzt noch eine Schleife einrichten, damit hinter der Prozentzahl der Auswertung in Klammern die Häufigkeitsverteilung im deutschen Alphabet für den jeweiligen Buchstaben steht. Aber meine Schleifen, die ich versucht habe, funktionieren nicht.
Was muss beim zweiten Code in Zeile 9 hin, da wo ich das Fragezeichen hingeschrieben habe?
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Sonntag 8. April 2007, 18:52

frequencies_dt[char + '_dt']?
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Antworten