Seite 1 von 2
Programm für Textanalyse
Verfasst: Samstag 7. April 2007, 22:09
von M***
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.
Re: Programm für Textanalyse
Verfasst: Samstag 7. April 2007, 22:29
von EnTeQuAk
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]
Verfasst: Samstag 7. April 2007, 23:35
von M***
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:
Verfasst: Samstag 7. April 2007, 23:48
von gerold
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
Verfasst: Sonntag 8. April 2007, 02:09
von M***
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?
Verfasst: Sonntag 8. April 2007, 06:32
von HWK
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
Verfasst: Sonntag 8. April 2007, 09:24
von BlackJack
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}
Verfasst: Sonntag 8. April 2007, 09:50
von mitsuhiko
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
))
Verfasst: Sonntag 8. April 2007, 10:07
von birkenfeld
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.
Verfasst: Sonntag 8. April 2007, 10:32
von mitsuhiko
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.
Verfasst: Sonntag 8. April 2007, 14:26
von M***
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))
Verfasst: Sonntag 8. April 2007, 14:38
von birkenfeld
Deine 26 prints solltest du aber schon noch durch eine Schleife ersetzen.
Verfasst: Sonntag 8. April 2007, 15:07
von M***
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.
Verfasst: Sonntag 8. April 2007, 17:23
von M***
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?
Verfasst: Sonntag 8. April 2007, 18:52
von birkenfeld
frequencies_dt[char + '_dt']?
Verfasst: Sonntag 8. April 2007, 19:10
von M***
Ich denke zu kompliziert! Danke.
Verfasst: Sonntag 8. April 2007, 20:41
von DaSch
Also ich hab jetzt einfach mal so weil ich nix besseres zu tun hatte auch mal ein Prog geschrieben.
Wie findet ihr das?
Ich hab noch die Möglichkeit eingebaut einen eigenen String anzugeben nach dem Gezählt wird und dann noch die Datei nicht vorher in kleinbuchstaben zu konvertieren.
Code: Alles auswählen
#!/usr/bin/python
# -*- coding: utf-8 -*-
import string
import sys
lower=True
if len(sys.argv) == 1:
print "Bitte eine Datei zum einlesen angeben"
if len(sys.argv) >= 2:
path = sys.argv[1]
charpath=-1
try:
daten = file (path,'r')
except:
print "Fehler beim Daten einlesen #000"
text = daten.read()
daten.close()
if len(sys.argv) >= 3:
charpath = sys.argv[1]
try:
chardaten = file (charpath,'r')
except:
print "Fehler beim Daten einlesen #001"
chartext = chardaten.read()
chardaten.close()
if len(sys.argv) >= 4:
if sys.argv[3]=="-l":
lower=False
else:
print "Falsches Argument angegeben"
if lower:
text = string.lower(text)
numworte=len(text.split())
if charpath!=-1:
char2count=list(chartext)
else:
char2count=list("abcdefghijklmnopqrstuvwxyz")
numchar=[]
numchartota=0
for i in range(len(char2count)):
char_tmp=char2count[i]
num_tmp=text.count(char_tmp)
numchartota+=num_tmp
numchar.append(num_tmp)
if len(numchar)!=len(char2count):
print "Fehler beim Zeichenzählen #002"
else:
print "Anzahl der Worte:",numworte
print "Anzahl der Buchstaben:",numchartota
print "Durchschnittliche Anzahl der Buchstaben pro Wort:",numchartota/numworte
print "Anteile der Zeichen"
for i in range(len(char2count)):
char_tmp=char2count[i]
num_tmp=float(numchar[i])
numchartota=float(numchartota)
proz=(num_tmp/numchartota)*100
print "Der Anteil von",char_tmp,"ist","%.2f" % proz,"%"
Verfasst: Sonntag 8. April 2007, 20:53
von EnTeQuAk
Beim groben drüber schauen, sind mir ein paar Dinge schonmal aufgefallen.
Einmal: schaue dir mal bitte das Python-Modul
optparse an. Das vereinfacht das parsen von Komandozeilen-Argumenten.
Weiterhin:
Code: Alles auswählen
try:
daten = file(path,'r')
except:
print "Fehler beim Daten einlesen #000"
Ist nicht schön. Es ist nicht gut, gleich
sämtliche Exceptions abzufangen. Fange nur die Exception ab, die du erwartest. So bleiben andere Bugs/Fehler nicht unbemerkt.
Die Fehlermeldung z.B. bringt nichts, sagt absolut gar nichts aus. Python hat schon so nen schönes Traceback-System
Code: Alles auswählen
try:
daten = file(path,'r')
except IOError, err:
print 'Fehler beim einlesen von "%s":\n%s' % (err.filename, err)
Ist ebenso wenig schön, wie auch veraltert.
MfG EnTeQuAk
Verfasst: Montag 9. April 2007, 00:17
von M***
Ich würde gerne direkt nachdem ich die text.txt eingelesen habe die Umlaute umwandeln (ä -> ae, ö -> oe, ü -> ue, ß -> ss).
Kann ich da mit chr() und ord() arbeiten? Warscheinlich nicht.^^ Wie wäre eine einfache Lösung?
Danke.
Verfasst: Montag 9. April 2007, 00:41
von EnTeQuAk
Bin mir nicht so sicher. Also entweder, du nutzt stures 'text.replace()' oder machst das so:
Code: Alles auswählen
def replace_chars(text):
chars = {
'ä': 'ae', 'Ä': 'Ae',
'ü': 'ue', 'Ü': 'Ue',
'ö': 'oe', 'Ö': 'Oe',
'ß': 'ss',
}
for char in chars:
if char in text:
text = text.replace(char, chars[char])
return text
Einfach jeden Buchstaben, den du ersetzt haben magst eintragen
Wobei, was mir auffällt. Warum `ß` in `ss` umwandeln? Das macht den ganzen Text nicht mehr so gaaanz Rechtschreibtechnisch richtig. Aber na ja
wollts nur sagen
(btw: was bezweckst du mit dem ersetzen?)
MfG EnTeQuAk