Zapisz jako PDF
Transkrypt
Zapisz jako PDF
Spis treści 1 TI:WTBD/Kolokwium Poprawkowe 1.1 zadanie 1 1.1.1 przykład rozwiązania: 1.2 zadanie 2 1.2.1 przykład rozwiązania: 1.3 zadanie 3 1.3.1 przykład rozwiązania: TI:WTBD/Kolokwium Poprawkowe zadanie 1 Medianę sekwencji liczb można zdefiniować za pomocą następującego kodu: def median(x): xx = sorted(x) if not xx: return None if len(xx) == 1: return xx[] if len(xx) == 2: return sum(xx)/2. else: return median(xx[1:-1]) (kod ten służy wprowadzeniu definicji mediany, nie jest to optymalna ani nawet szczególnie dobra implementacja obliczania mediany w praktyce!) Niech T będzie tabelą, zawierającą (między innymi) kolumnę "X float not null". Napisać zapytanie SQL zwracające medianę wartości z kolumny X. Napisać program do testowania tego zapytania, tworzący tabelę z 10 000 liczb losowych (w pamięci) i porównujący medianę obliczoną za pomocą zapytania SQL z wynikiem rachunku w Pythonie na tych samych liczbach (ulepszając algorytm z powyższej definicji). przykład rozwiązania: #! /usr/bin/python # coding: utf-8 def py_median(x): xx = sorted(x) if not xx: return None limit, offset = 2 - len(xx) % 2, (len(xx) - 1) / 2 middle = xx[offset:offset+limit] return sum(middle) / float(limit) def sql_median(x): from sqlite3 import connect conn = connect(':memory:') conn.execute('create table T (X float not null)') conn.executemany('insert into T values (?)', zip(x)) #((X,) for X in x)) ((res,), ) = conn.execute(''' select avg(X) from ( select X from T order by X limit 2 - (select count(*) from T)%2 offset ((select count(*) from T) - 1)/2 )''' ) conn.close() return res def test_median(N=10000): from numpy.random import rand x = rand(N) m1 = py_median(x) m2 = sql_median(x) delta = m1 - m2 return delta if __name__ == '__main__': from sys import argv N = 10000 if len(argv) == 2: N = int(argv[1]) print 'py_median - sql_median = {}'.format(test_median(N)) zadanie 2 Posługując się gotową bazą SQLite zawartą w pliku pl_lud.db napisać program, który: w odpowiedzi na argument 'q1' wypisuje listę nazw województw, po jednym na linijkę, i w tej samej linijce dla każdego z nich podaje liczbę powiatów, należących do danego województwa; w odpowiedzi na argument 'q2' wypisuje listę nazw 10 powiatów o największym zaludnieniu w kraju, obok jego nazwy wypisując liczbę ludności i nazwę województwa, do którego należy; w odpowiedzi na argument 'q3' wypisuje średnią i odchylenie standardowe liczby ludności obliczone dla wszystkich powiatów w kraju. przykład rozwiązania: #! /usr/bin/python # coding: utf-8 QUERIES = { 'q1' : ''' select w.NAZWA as WOJEWODZTWO, count(*) as ILE_POWIATOW from WOJEWODZTWA w join POWIATY p on w.ID=p.W_ID group by w.NAZWA order by w.NAZWA ''', 'q2' : ''' select p.NAZWA as POWIAT, p.LUDNOSC, w.NAZWA as WOJEWODZTWO from POWIATY p join WOJEWODZTWA w on w.ID=p.W_ID order by p.LUDNOSC desc limit 10 ''', 'q3' : ''' select sum(LUDNOSC)/count(*), sum(LUDNOSC*LUDNOSC)/count(*) from POWIATY; ''' } def main(baza, arg): from sqlite3 import connect conn = connect(baza) cursor = conn.execute(QUERIES[arg]) if arg in ('q1', 'q2'): rows = list() rows.append(tuple(r[] for r in cursor.description)) for r in cursor: rows.append(tuple(unicode(x) for x in r)) for r in rows: print u' | '.join(r).encode('utf-8') #print r elif arg == 'q3': avg, avg2 = cursor.fetchall()[] stddev = (avg2 - avg**2)**0.5 print u'średnia: {}; sigma: {}'.format(avg, round(stddev)).encode('utf-8') if __name__ == '__main__': from sys import argv baza = 'pl_lud.db' try: arg = argv[1] except IndexError: print u'{}: wymaga dokładnie jednego argumentu.'.format(__file__).encode('utf-8') exit(1) if arg in ('q1', 'q2', 'q3'): main(baza, arg) else: print u'{0}: {1}: nieznany argument.'.format(__file__, arg).encode('utf-8') zadanie 3 Napisać program, który na podstawie pliku tekstowego kodowanego w UTF-8 stworzy indeks słów występujących w tym pliku, w postaci tabeli SQLite zawierającej kolumny slowo (tekst słowa), wiersz (nr wiersza w którym wystąpiło) i kolumna (pozycja w wierszu). Sprawdzić działanie tego programu na podstawie pliku z tekstem 1. księgi Pana Tadeusza (Plik:PanTadeusz1.txt). W sformułowaniu tego zadania kryje się niestety pewna niejednoznaczność, której z początku nie zauważyłem: ,,pozycja w wierszu" może oznaczać numer kolejny słowa w wierszu, lub pozycję w wierszu początku tego słowa jako numer kolejny znaku w wierszu -ta druga interpretacja była zamierzona, ale oceniając traktowałem obie jako poprawne. Również jako równie poprawne traktowałem zaczynanie numeracji od zera lub od jedynki. przykład rozwiązania: #! /usr/bin/python # coding: utf-8 import re import sqlite3 def words(plik): wordrx = re.compile(r'\b\w+\b', re.UNICODE) f = open(plik) for num, line in enumerate(f): line = line.decode('utf-8') ## to jeśli kolumnę rozumieć jako nr słowa w linii #for pos, word in enumerate(wordrx.findall(line)): #yield word, num, pos ## a teraz wersja gdy kolumna oznacza pozycję początku słowa w znakach m = wordrx.search(line) while m: yield m.group(), num, m.start() m = wordrx.search(line, m.end()) f.close() def create(dbplik, plik): db = sqlite3.connect(dbplik) db.execute(''' drop table if exists indeks_slow ''') db.execute(''' create table indeks_slow (slowo text, wiersz int, kolumna int, primary key (wiersz, kolumna)) ''') db.executemany(''' insert into indeks_slow (slowo, wiersz, kolumna) values (?, ?, ?) ''', words(plik)) db.commit() ((n,),) = db.execute(''' select count(*) from indeks_slow ''') return n if __name__ == '__main__': from sys import argv try: plik = argv[1] except IndexError: print (u'{}: wymaga argumentu - nazwy pliku tekstowego w UTF-8.'. format(__file__).encode('utf-8') ) exit(1) dbplik = plik + '.sqlite3' print u'tworzę tabelę indeks_slow w pliku {} ...'.format(dbplik).encode('utf-8') nrows = create(dbplik, plik) print u'wstawiono {} wierszy.'.format(nrows).encode('utf-8')