Podstawy Pythona

Transkrypt

Podstawy Pythona
Plan
Ćwiczenie
Opis zadania
Interludium - analiza tekstów z wykorzystanie ngramów
Przydatne techniki/pakiety
Mini-aplikacja, szczegółowa specyfikacja
Rozwiązanie
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
1 / 34
Opis zadania
Sprawdzenie podobieństwa trzech dużych, różnojęzycznych tekstów
Zadanie podzielone jest na następujące etapy:
dekompozycja tekstu na ngramy o zadanej długości, po 3 albo po 4
znaki każdy
wykonaniu dla każdego z tekstów histogramu częstości występowania
ngramów, wizualizacji otrzymanych wyników
przekształceniu histogramów do postaci dużych macierzy liczb
naturalnych i zbadaniu ich podobieństwa - iloczyn skalarny wektorów
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
2 / 34
Interludium
porównywanie tekstów z użyciem ngramów
Analiza tekstów z użyciem ngramów
ngram - krotka tekstu o zadanej długości
ngramy znajdują się poniżej leksykalnego poziomu słów
wykorzystanie ngramów o długości co najmniej 2 pozwala na
efektywne rozróżnianie języków
wykorzystanie ngramów o długości 3 pozwala już na rozróżnianie
pomiędzy dziedzinami wiedzy
zwiększona długość krotki poprawia specyficzność wyszukiwania
zwiększając jednocześnie ilość różnych ngramów
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
3 / 34
Interludium
porównywanie tekstów z użyciem ngramów
Analiza tekstów z użyciem ngramów - przykład 3-gramów
#!/usr/bin/python
# -*- coding: utf-8 -*# rozkład frazy na trójgramy
’to jest przykladowa fraza’
’to ’
’o j’
’ je’
’jes’
’est’
’st ’
’t p’
’ pr’
’prz’
’rzy’
...
’aza’
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
4 / 34
Przydatne techniki/pakiety
przydatne na potrzeby wykonania zadania informacje i umiejętności
moduł logowania
test driven development - unit testy
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
5 / 34
Przydatne techniki/pakiety
moduł logowania
logging
główne obiekty: loggery, uchwyty, formaty i filtry
obiekty typu logger mogą wysyłać komunikaty o różnym poziomie
ważności z wykorzystanie wielu uchwytów
uchwyty mogą być różnego typu - pliki, strumienie, mail
format komunikatów definiowany jest przy użyciu obiektów Formatter
konfigurację logowania wygodnie jest zapisywać w plikach o składni
tożsamej z używaną przez ConfigParser
konfiguracja logowania, w tym pliki konfiguracyjne, obsługiwana jest
przez moduł logging.config
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
6 / 34
Przydatne techniki/pakiety
moduł logowania
logging - przykład
import logging
from sys import stdout
def func( logger ): logger.debug( ’debug’ ),logger.info( ’info’ )
logger = logging.getLogger(’test_logger’) # init logger
#set up handler for logger
handler = logging.StreamHandler( stdout )
format =’%(asctime)s - %(name)s - %(levelname)s - %(message)s’
formatter = logging.Formatter( format )
handler.setFormatter( formatter )
logger.addHandler( handler ) # add handler
logger.setLevel( logging.DEBUG ) #set level
func( logger ) # test
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
7 / 34
Przydatne techniki/pakiety
moduł logowania - przykład pliku konfiguracyjnego
[loggers]
keys=root
[handlers]
keys=consoleHandler
[formatters]
keys=simpleFormatter
[logger_root]
qualname=root
level=DEBUG
propagate=0
handlers=consoleHandler
[handler_consoleHandler]
class=StreamHandler
args=(sys.stdout,)
formatter=simpleFormatter
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
8 / 34
Przydatne techniki/pakiety
moduł logowania - wykorzystanie zapisanej konfiguracji
#!/usr/bin/python
# -*- coding: utf-8 -*import logging, logging.config
def screamer(logger, value):
logger.debug(’to ja :)’)
try: int( value ) # test function
except:
logger.error(’ValueError, ’ + str(value))
logger.debug(’to ja :(’)
logging.config.fileConfig(’pliki/loggers’) # read config
logger = logging.getLogger(’root’) # init logger
logger.setLevel( logging.DEBUG ) # set level
screamer( logger, ’test value’ )
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
9 / 34
Przydatne techniki/pakiety
test driven development - unit testy
TDD - idealny schemat postępowania
odwracamy kierunek postępowania, zaczynamy implementację od
zdefiniowania przypadków testowych i napisania testów
zaczynamy od napisania najprostszej działającej wersji kodu, dla
każdego z testów
następnie iteracjnie: wykonujemy test, a w przypadku zakończenia
testu sukcesem optymalizujemy kod
grupowanie testów w logiczne szeregi pozwala na automatyczne
wykonywanie testów regresji
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
10 / 34
Przydatne techniki/pakiety
test driven development - unit testy
pakiet unittest
klasa TestCase - zautomatyzowane środowisko do obsługi testów
każda metoda, klasy TestCase, której nazwa rozpoczyna się od ’test ’
definiuje pojedynczy test
wykonanie każdego testu poprzedzone jest wywołaniem funkcji
setUp(), po zakonczeniu wywoływana jest funkcja tearDown()
TestCase zawiera całą gamę funkcji służących do określania czy dany
test zakończył się powodzeniem - assertEqual, failUnlessAlmostEqual,
...
testy można grupować w zestawy - unittest.TestSuite
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
11 / 34
Przydatne techniki/pakiety
test driven development - unit testy
’’’sumowanie dwoch ciągów liczb naturalnych’’’
# wyrocznia wykorzystuje wbudowaną funkcję
def oracle( left, right ):
return sum( left + right )
# pierwsze podejście, jawne przeiterowanie się przez listy
def first( seq_left, seq_right ): #
ret = 0
for i in seq_left: ret+=i
for i in seq_right: ret+=i
return ret
# inny sposób
from itertools import izip_longest, starmap
def second( left, right ):
#wyrównanie długości list
equal_iter = izip_longest( left, right, fillvalue=0 )
# zsumowanie sum wszystkich par elementow
return sum( starmap( lambda x, y: x + y, equal_iter ) )
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
12 / 34
Przydatne techniki/pakiety
test driven development - unit testy
import unittest
from testing_functions import oracle, first, second
class SimpleTestCase(unittest.TestCase):
’’’przypadki testowe - zaczynajace sie od test_,
porownujemy z wynikiem wyroczni’’’
def setUp(self):
self.l, self.r = range(20), range(40)
def test_first(self):
self.assertEqual( first( self.l, self.r ),
oracle( self.l, self.r ) )
def test_second(self):
self.assertEqual( second( self.l, self.r ),
oracle( self.l, self.r) )
def tearDown(self):
print ’ciekawe czy testy sie powiodly?’
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
13 / 34
Przydatne techniki/pakiety
test driven development - unit testy
#!/usr/bin/python
# -*- coding: utf-8 -*import unittest
from basic_testing import SimpleTestCase
if __name__==’__main__’:
’’’ budujemy zestaw testowy, unittest.TestSuite ’’’
todo = [ ’test_first’, ’test_second’ ]
test_cases = map( SimpleTestCase, todo )
test_suite = unittest.TestSuite( test_cases )
’’’ uruchamiamy testy ’’’
runner = unittest.TextTestRunner( verbosity=2 )
runner.run( test_suite )
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
14 / 34
Przydatne techniki/pakiety
itertools
Bardzo przydatne w rozwiązywaniu może być wykorzystanie elementów
programowania funkcyjnego. W pakiecie ’itertools’ znajduje się wiele
bardzo ciekawych narzędzi, w szczególności:
imap
izip
Bardziej szczegółowy opis kilku wybranych funkcji zawartych w itertools
zostanie dokonany podczas prezentacji rozwiązania zadania.
Użycie itertools nie jest konieczne do rozwiązania zadania.
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
15 / 34
Mini-aplikacja, szczegółowa specyfikacja
Etapy zadania
1
wczytanie tekstów wejściowych
2
dekompozycja tekstów na 3-ngramy
3
wygenerowanie histogramów częstości występowania zapytań
4
porównanie tekstów poprzez wykonanie iloczynu skalarnego
histogramów
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
16 / 34
Mini-aplikacja, szczegółowa specyfikacja
wczytanie tekstów wejściowych, wstępna obróbka tekstu
etap 1
w /opt/python znajdują się trzy opisy bitwy pod Flodden (1513):
flodden.en, flodden.pl i flodden.it
interesujące są jedynie niepuste linie
zmieniamy cały tekst na małe litery
każdy znak różny od [ a − z0 − 9] zmieniamy na spację - w tekście
polskim usunięto polskie znaki, rozmiar wybranego alfabetu oznaczmy
przez A
jeden znak to jeden bit - ASCII
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
17 / 34
Mini-aplikacja, szczegółowa specyfikacja
dekompozycja tekstu
etap 2
rozdzielić tekst na ngramy o dł. 3
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
18 / 34
Mini-aplikacja, szczegółowa specyfikacja
wygenerowanie histogramów
etap 3
zmapować alfabet do ciągu liczb naturalnych, ( mapa[litera] =
pozycja w alfabecie )
zakodować każdy ngram xyz do liczby naturalnej takiej że:
n = mx ∗ A0 + my ∗ A1 + mz ∗ A2 , gdzie mX - pozycja litery w
alfabecie
utworzyć histogram o rozmiarze zdefiniowanym przez maksymalne n,
wypełnić histogram zliczeniami ngramów
nie dokonujemy zliczenia ngramów zawierających dwie następujące po
sobie spacje
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
19 / 34
Mini-aplikacja, szczegółowa specyfikacja
porównanie tekstów
etap 4
na podstawie histogramów utworzyć wektory
obliczyć normę wektorów
obliczyć iloczyny skalarny wektorów odpowiadających tekstowm w
określonym języku
dokonać oceny jakości wyniku, czy włoski jest bardziej podobny do
polskiego niż angielski?
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
20 / 34
Implementacja - podpowiedzi i rozwiązania
W miarę postępu prac pliki zawierające unittesty dla każdego z etapów
oraz rozwiązania i pozostałe materiały, będą umieszczane na w katalogu
na serwerze w ICM:
Python basics
http://bioinfo.icm.edu.pl/algorithm/source/python course
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
21 / 34
Implementacja - etap pierwszy, podpowiedzi
utworzyć oddzielny moduł dla etapu, dla kżdego następnego również
napisy mogą być iterowane znak po znaku, mozna użyć napisu jako
alfabetu
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
22 / 34
Implementacja - etap pierwszy, podpowiedzi
utworzyć oddzielny moduł dla etapu, dla kżdego następnego również
napisy mogą być iterowane znak po znaku, mozna użyć napisu jako
alfabetu
pusta linia to tylko jeden znak - str.replace()
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
22 / 34
Implementacja - etap pierwszy, podpowiedzi
utworzyć oddzielny moduł dla etapu, dla kżdego następnego również
napisy mogą być iterowane znak po znaku, mozna użyć napisu jako
alfabetu
pusta linia to tylko jeden znak - str.replace()
na tym etapie nie trzeba przejmować się czy krotka zawiera właściwą
liczbę spacji
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
22 / 34
Implementacja - etap pierwszy, rozwiązanie
alfabet = ’ abcdefghijklmnopqrstuvwxyz0123456789’
width = len( alfabet )
def load( file ):
with open( file ) as f:
content = f.read() #load
content = content.replace(’\n’,’’) #eliminacja pustych linii
content = content.lower() # tylko male litery
return map_to_alphabet( content, alfabet )
def map_to_alphabet( text, alfabet ):
output = []
for i in text:
if i in alfabet:
output.append( i )
else:
output.append( ’ ’ )
# print output, ’\n’, ’’.join( output ) # skleja ’’ z lista
return output
if __name__==’__main__’:
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
23 / 34
Implementacja - etap drugi, podpowiedzi
utworzyć oddzielny moduł dla etapu, dla każdego następnego również
napisy mogą być iterowane znak po znaku, mozna użyć napisu jako
alfabetu
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
24 / 34
Implementacja - etap drugi, podpowiedzi
utworzyć oddzielny moduł dla etapu, dla każdego następnego również
napisy mogą być iterowane znak po znaku, mozna użyć napisu jako
alfabetu
pusta linia to tylko jeden znak - str.replace()
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
24 / 34
Implementacja - etap drugi, podpowiedzi
utworzyć oddzielny moduł dla etapu, dla każdego następnego również
napisy mogą być iterowane znak po znaku, mozna użyć napisu jako
alfabetu
pusta linia to tylko jeden znak - str.replace()
na tym etapie nie trzeba przejmować się czy krotka zawiera właściwą
liczbę spacji
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
24 / 34
Implementacja - etap drugi, rozwiązanie
from etap_1_load import alfabet, load
def classic( input, ngram_len ):
output = []
range = len(input)
for i in xrange( range - ngram_len + 1 ):
output.append( ’’.join( input[ i:i+ ngram_len] ) )
return output
def functional( input, ngram_len ):
from itertools import islice, izip
iterators=[ islice( input, i, None ) for i in xrange( ngram_len ) ]
return map( ’’.join, izip( *iterators ) )
if __name__==’__main__’:
from sys import argv
reduced_content, ngram_len = load( argv[1] ), int(argv[2])
print classic( reduced_content, ngram_len ), ’\n’
print functional( reduced_content, ngram_len )
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
25 / 34
Implementacja - etap trzeci, podpowiedzi
stwórz trzy odrębne funkcje służące do:
1
2
3
mapowania alfabetu na liczby naturalne
wyliczania kodu ngramu
zliczającą wystąpienia ngramów które nie mają dwóch sąsiadujących
spacji - histogram
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
26 / 34
Implementacja - etap trzeci, podpowiedzi
stwórz trzy odrębne funkcje służące do:
1
2
3
mapowania alfabetu na liczby naturalne
wyliczania kodu ngramu
zliczającą wystąpienia ngramów które nie mają dwóch sąsiadujących
spacji - histogram
na histogram swietnie nadaje się słownik postaci: klucz - kod ngramu,
wartość - ( klucz, ngram, zliczenia )
słownik w podanej wyżej postaci mozna w prosty sposób zamienić na
wektor/listę/tablicę(array)
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
26 / 34
Implementacja - etap trzeci, podpowiedzi
aby pozbyć się sąsiadujących spacji można wykorzystać funkcje
rstrip() i lstrip(), działają dla napisów, sprawdzając czy w rezultacie
ich działania otrzymujemy napis o określonej długości ( tutaj n >= 2,
dla trój-gramów )
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
27 / 34
Implementacja - etap trzeci, podpowiedzi
aby pozbyć się sąsiadujących spacji można wykorzystać funkcje
rstrip() i lstrip(), działają dla napisów, sprawdzając czy w rezultacie
ich działania otrzymujemy napis o określonej długości ( tutaj n >= 2,
dla trój-gramów )
aby sprawdzić czy klucz jest w słowniku mozna użyć konstrukcji
if a in dict :
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
27 / 34
Implementacja - etap trzeci, rozwiązanie
#!/usr/bin/python
# -*- coding: utf-8 -*def mapping( alfabet ):
’’’ map alphabet into ordered set of numbers ’’’
ret_dict = {}
for i in xrange(len(alfabet)):
ret_dict[ alfabet[i] ] = i
return ret_dict
def code( ngram, codes, width ):
’’’ find ngram’s code ’’’
value = 0
for i in xrange( len( ngram ) ):
tmp1 = codes[ ngram[i] ]
tmp2 = width**i
value += tmp1 * tmp2
return value
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
28 / 34
Implementacja - etap trzeci, rozwiązanie
from etap_3_histogramy_a import code
def count_ngrams( codes, width, text ):
’’’ generate histogram as a dictionary of
lists, key = ngram’s code, value = [ key, ngram, count ]’’’
histogram = {}
for ngram in text:
’’’ eliminate ngrams containing more than 1 space ’’’
if len( ngram.lstrip() )>1 and len( ngram.rstrip() ) >1:
’’’ calculate code ’’’
code_value = code( ngram, codes, width )
’’’ insert into histogram ’’’
if code_value not in histogram:
histogram[ code_value ] = [ code_value, ngr
else:
histogram[ code_value ][2] +=1
’’’how to sort a dictionary ’’’
#from operator import itemgetter
#return sorted( histogram.values(), key=itemgetter(2), reverse=True
return histogram
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
29 / 34
Implementacja - etap trzeci, rozwiązanie
from etap_1_load import alfabet, width, load
from etap_2_dekompozycja import functional, classic
from etap_3_histogramy_a import mapping
from etap_3_histogramy_b import count_ngrams
if __name__==’__main__’:
from sys import argv
’’’ wczytaj text i rozmiar ngramu ’’’
reduced_content, ngram_len = load( argv[1] ),
’’’ dekompozycja na ngramy o zadanej dlugosci
#print classic( reduced_content, ngram_len ),
text = functional( reduced_content, ngram_len
’’’ utworz mape wartosci ’’’
codes = mapping( alfabet )
’’’ stworz histogram ’’’
ret = count_ngrams( codes, width , text )
’’’ wyswietlanie wyniku’’’
print ret#[:10]
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
int(argv[2])
’’’
’\n’
)
19 stycznia 2010
30 / 34
Implementacja - etap czwarty, podpowiedzi
utworzyć wyzerowaną listę o odpowiedniej długości, najprościej przy
użyciu ’generator expression’ i ’xrange’
sumę wszystkich elementów wektora mozna policzyć wykorzystując
wbudowaną funkcję sum
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
31 / 34
Implementacja - etap czwarty, rozwiązanie
def produce_vector( histogram, width ):
# set range
max_range = width + width**2 + width**3
vector = [ 0 for i in xrange( max_range + 1) ]
# mozna rowniez uzyc klasy array z pakietu array
’’’ zliczenie jest trzecim elementem wartosci w slowniku ’’’
for position in xrange( max_range + 1 ):
if position in histogram:
vector[ position ] = histogram[ position ][2]
return vector
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
32 / 34
Implementacja - etap czwarty, rozwiązanie
from etap_1_load import alfabet, width, load
from etap_2_dekompozycja import functional
from etap_3_histogramy_a import mapping
from etap_3_histogramy_b import count_ngrams
from etap_4_cmp_a import produce_vector
def eat_file( file, ngram_len ):
reduced_content = load( file )
text = functional( reduced_content, ngram_len )
codes = mapping( alfabet )
histogram = count_ngrams( codes, len(alfabet), text )
’’’ wygeneruj wektor i jego norme ’’’
vec = produce_vector( histogram, len(alfabet))
return vec, sum(vec)
def dot( left, right ):
from operator import mul
tmp = sum( map( mul, left[0], right[0] ) )
return 1. * tmp / ( left[1] * right[1] )
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
33 / 34
Implementacja - etap czwarty, rozwiązanie
from etap_4_cmp_b import eat_file, dot
from sys import argv
suffixes = [’pl’,’en’,’it’]
if __name__==’__main__’:
result = {}
prefix, ngram_len = argv[1], int( argv[2] )
’’’ pliki dla trzech jezykow ’’’
for language in suffixes:
filename = prefix + language
result[ language ] = eat_file( filename, ngram_len )
pl_it = dot( result[’pl’], result[’it’] )
pl_en = dot( result[’pl’], result[’en’] )
it_en = dot( result[’en’], result[’it’] )
print ’pl * it’,pl_it
print ’pl * en’,pl_en
print ’en * it’,it_en
print ’czy wynik ma sens ?:)’
Łukasz Ligowski, Sławomir Walkowiak (ICM UW)
Podstawy Pythona - ćwiczenie
19 stycznia 2010
34 / 34

Podobne dokumenty