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