13 - Biblioteki
Instalując Pythona, przy okazji instalujesz zestaw modułów o bardzo różnym zastosowaniu tworzących Bibliotekę Standardową Pythona (ang. The Python Standard Library). Poniżej umieściłem, krótki przegląd wybranych, znajdujących się w niej, modułów i niektórych zawartych w nich funkcji. Skupię się na tych, które mają związek z obliczeniami i procesami losowymi. Przynajmniej niektóre z pewnością uznasz za użyteczne. Będziemy się zresztą do wielu z nich, a także innych, odwoływać w przyszłości. Warto jednak samemu przejrzeć dokumentację Biblioteki Standardowej Pythona, którą znajdziesz pod adresem: https://docs.python.org/pl/3.8/library/index.html, Warto też zajrzeć do przewodnika: https://docs.python.org/pl/3.8/tutorial/stdlib.html. Na końcu tej lekcji skorzystamy także z innych bibliotek.
Moduł math
Moduł math
zawiera (m.in.) funkcje matematyczne.
Dokumentacja: https://docs.python.org/3.8/library/math.html.
Importujemy poleceniem:
import math
Wybrane funkcje
math.ceil(x)
- zaokrąglanie ,,w górę’'.
math.ceil(3.14)
4
math.floor(x)
- zaokrąglanie ,,w dół’'.
math.floor(3.14)
3
math.modf(x)
- zwraca część ułamkową i całkowitą w krotce, zachowując przy tym znak.
math.modf(-12.125)
(-0.125, -12.0)
math.fabs(x)
- zwraca wartość absolutną liczby. Warto jednak zauważyć, że istnieje także wbudowana funkcja abs(x)
, zwróć uwagę, że math.fabs(x)
zwraca liczbę zmiennoprzecinkową, nawet kiedy przekażemy jej liczbę całkowitą, abs(x)
zwraca w takim przypadku liczbę całkowitą.
math.fabs(-12)
12.0
abs(-12)
12
math.fmod(x, y)
- działa podobnie jak wyrażenie x % y
, czyli zwraca resztę z dzielenia. Między oboma sposobami uzyskiwania są jednak pewne różnice (zob. dokumentacja), które sprawiają, że o ile wyrażenie x % y
zaleca się dla liczb całkowitych, to jeśli chcemy uzyskać wynik dla liczb zmiennoprzecinkowych, to lepiej użyć funkcji math.fmod(x, y)
.
math.fmod(10, 3)
1.0
math.factorial(x)
- zwraca silnię dla podanej liczby całkowitej.
math.factorial(5)
120
math.log(x[, podstawa])
- zwraca logarytm liczby x
dla podanej podstawy. Jeśli podamy tylko liczbę x
to zostanie zwrócony logarytm dla podstawy e
(logarytm naturalny).
math.log(8,2)
3.0
math.pow(x, y)
- zwraca wartość liczby x
podniesionej do potęgi y
.
math.pow(10, 3)
1000.0
math.sqrt(x)
- zwraca pierwiastek kwadratowy z liczby x
.
math.sqrt(9)
3.0
math.sin(x)
- zwraca sinus dla kąta x
podanego w radianach (!)
math.sin(0)
0.0
math.cos(x)
- zwraca sinus dla kąta x
podanego w radianach (!)
math.cos(0)
1.0
Wybrane stałe
math.pi
- stała π (pi), czyli 3.141592…
math.pi
3.141592653589793
math.e
- stała e, czyli 2.718281…
math.e
2.718281828459045
Moduł statistics
Jak nazwa wskazuje zawiera podstawowe funkcje statystyczne.
Dokumentacja: https://docs.python.org/3.8/library/statistics.html
Moduł importujemy poleceniem:
import statistics
W praktyce, ponieważ statistics
to raczej długa nazwa, warto użyć przy imporcie aliasu, lub zaimportować potrzebne funkcje. Tu jednak będę używał pełnej nazwy modułu.
Wybrane funkcje
statistics.mean(data)
- zwraca średnią arytmetyczną dla danych
dane = [1, 2, 3, 4]
statistics.mean(dane)
2.5
statistics.geometric_mean(data)
- zwraca średnią geometryczną dla danych
dane = [1, 2, 3, 4]
statistics.geometric_mean(dane)
2.2133638394006434
statistics.median(data)
- zwraca medianę dla danych
dane = [1, 2, 3, 4]
statistics.median(dane)
2.5
statistics.mode(data)
- zwraca dominantę, czyli najczęściej występującą wartość. Jeśli jest kilka takich wartości, to zwracana jest pierwsza z nich.
dane = [3, 2, 3, 2, 2, 1, 5, 4]
statistics.mode(dane)
2
dane = [3, 2, 3, 2, 2, 3, 5, 4]
statistics.mode(dane)
3
dane = ['Ala', 'Phe', 'Gly', 'Ala', 'Arg', 'Gly']
statistics.mode(dane)
'Ala'
sekwencja = 'ACGCATGATG'
statistics.mode(sekwencja)
'A'
statistics.multimode(data)
- zwraca dominantę, czyli najczęściej występującą wartość. Jeśli jest kilka takich wartości, to zwracane są wszystkie. Wynik zwracany jest w formie listy, nawet gdy jest to tylko jedna wartość.
dane = [3, 2, 3, 2, 2, 1, 5, 4]
statistics.multimode(dane)
[2]
dane = [3, 2, 3, 2, 2, 3, 5, 4]
statistics.multimode(dane)
[3, 2]
dane = ['Ala', 'Phe', 'Gly', 'Ala', 'Arg', 'Gly']
statistics.multimode(dane)
['Ala', 'Gly']
sekwencja = 'ACGCATGATG'
statistics.multimode(sekwencja)
['A', 'G']
statistics.pstdev(data)
- odchylenie standardowe dla całej populacji
dane = [1.2, 1.3, 1.2, 1.5, 1.1, 1.3]
statistics.pstdev(dane)
0.1247219128924647
statistics.stdev(data)
- odchylenie standardowe z próby
dane = [1.2, 1.3, 1.2, 1.5, 1.1, 1.3]
statistics.stdev(dane)
0.13662601021279464
statistics.pvariance(data)
- wariancja dla całej populacji
dane = [1.2, 1.3, 1.2, 1.5, 1.1, 1.3]
statistics.pvariance(dane)
0.015555555555555553
statistics.variance(dane)
- wariancja dla próby
dane = [1.2, 1.3, 1.2, 1.5, 1.1, 1.3]
statistics.variance(dane)
0.018666666666666665
Moduł random
Funkcje udostępniane przez moduł random
są związane z generowaniem liczb pseudolosowych. Możliwe, że w tej chwili nasunęło Ci się pytanie: „Dlaczego liczby pseudolosowe a nie po prostu losowe?".
Nie wchodząc w szczegóły, program komputerowy nie generuje liczb, które mają charakter rzeczywiście losowy. Generuje natomiast, używając algorytmów, zestawy liczb, które możliwie przypominają te prawdziwie losowe, ale mają charakter deterministyczny. Obliczenia zaczynają się od konkretnej liczby, zwanej ziarnem. Używając tego samego ziarna i tych samych algorytmów uzyskuje się taki sam zestaw liczb. Jeśli nie narzucamy ziarna funkcjom generującym liczby pseudolosowe, przy każdym wywołaniu używają innej wartości ziarna (korzystając z czasu systemowego), zatem otrzymujemy różne zestawy liczb.
Liczby pseudolosowe mają wiele zastosowań, od symulacji naukowych począwszy, na grach komputerowych skończywszy. Poświęcimy zatem temu modułowi nieco więcej uwagi. Dalej, dla uproszczenia, będę czasem używał terminu „losowy" zamiast „pseudolosowy".
Dokumentacja: https://docs.python.org/3.8/library/random.html
Moduł importujemy poleceniem:
import random
Wybrane funkcje
random.random()
- podstawowa funkcja w module. Większość pozostałych bazuje własnie na niej. Zwraca pseudolosową liczbę float
z zakresu [0.0, 1.0)
, czyli włącznie z 0.0
ale bez 1.0
.
random.random()
0.5646673199495892
Sprobuj kilkukrotnie wywołać powyższe polecenie, za każdym razem powinna zostać zwrócona inna liczba.
Łatwo można uzyskać np. listę zawierającą liczby pseudolosowe:
# Generowanie 10 liczb pseudolosowych
liczby = []
for i in range(1, 11):
liczby.append(random.random())
print(liczby)
[0.01712794026679565, 0.23080537747172514, 0.012876793612628279, 0.4662143843352964, 0.9962012130556934, 0.30002044902516023, 0.27076103471999935, 0.8657557128359082, 0.7221944878982216, 0.9720415877242576]
Można policzyć dla uzyskanych liczb np. średnią, zwiększmy jednak ich liczbę w liście do stu tysięcy. Przy okazji zauważ, że 100000
można zapisać jako 100_000
, co zwiększa czytelność.
import statistics, random
liczby = []
for i in range(100_000):
liczby.append(random.random())
print(f"Liczba liczb pseudolosowych: {len(liczby)}")
print(f"Średnia: {statistics.mean(liczby)}")
Liczba liczb pseudolosowych: 100000
Średnia: 0.5014882062952232
random.seed([a=None][, version=2])
- funkcja umożliwia zainicjalizowanie generatora liczb losowych. Jeśli argument a
jest pominięty, lub ma wartość None
to jako ziarno zostaje ustawiony czas systemowy. Można jednak tę wartość ustawić, co umożliwia uzyskanie powtarzalnych liczb pseudolosowych. Parametrem version
funkcji, nie będziemy się zajmować.
Napiszmy krótki program, który pokaże jak to działa. Dla zwiększenie przejrzystości programu zaokrąglimy liczby pseudolosowe. Przy okazji zauważ, że ziarnem nie musi być liczba.
def pobierz_liczby(ziarno):
liczby = []
random.seed(ziarno)
for i in range(5):
liczba = round(random.random(), 2)
liczby.append(liczba)
print(f" Ziarno: {ziarno}, liczby: {liczby}")
pobierz_liczby(1000)
pobierz_liczby(1000)
pobierz_liczby(1001)
pobierz_liczby("BUM!")
pobierz_liczby(1000)
Ziarno: 1000, liczby: [0.78, 0.67, 0.1, 0.35, 0.47]
Ziarno: 1000, liczby: [0.78, 0.67, 0.1, 0.35, 0.47]
Ziarno: 1001, liczby: [0.8, 0.06, 0.76, 0.86, 0.09]
Ziarno: BUM!, liczby: [0.46, 0.87, 0.43, 0.78, 0.81]
Ziarno: 1000, liczby: [0.78, 0.67, 0.1, 0.35, 0.47]
random.uniform(a, b)
- zwraca liczbę zmiennoprzecinkową z zakresu między liczbą a
(włącznie) i b
(włącznie, lub nie - patrz dokumentacja)
random.uniform(0, 10)
4.812153673237898
random.gauss(mu, sigma)
- funkcja, która może być bardzo pomocna dla różnych symulacji komputerowych procesów m.in. biologicznych, zwraca bowiem liczbę pseudolosową, ale zgodną z rozkładem Gaussa. Czyli np. jeśli wygenerujemy odpowiednią liczbę takich liczb i je przedstawimy na histogramie to powinniśmy uzyskać charakterystyczny kształt ,,dzwonu’’. Na razie nie wiemy, co prawda jak taki histogram otrzymać, ale zrobimy to pod koniec lekcji.
Parametry tej funkcji to: mu
- średnia i sigma
- odchylenie standardowe.
liczby = []
srednia = 10
sd = 1
for i in range(10):
liczba = round(random.gauss(srednia, sd))
liczby.append(liczba)
print(liczby)
[8, 10, 11, 10, 10, 8, 8, 12, 9, 9]
random.randrange([start,] stop[, step])
- funkcja zwraca pseudolosową liczbę całkowitą z zakresu od wartości start
(opcjonalna, jeśli jej nie podamy to początkiem zakresu jest 0
) do stop -1
. Można też przekazać argument step
oznaczający ,,krok’’ co pozwala np. uzyskać pseudolosowe liczby parzyste:
liczby = []
for i in range(10):
# Liczby pseudolosowe z zakresu od 1 do 9
liczby.append(random.randrange(1, 10))
print(liczby)
[9, 8, 7, 5, 1, 2, 1, 9, 6, 3]
liczby = []
for i in range(10):
# Liczby pseudolosowe z zakresu od 0 do 9
liczby.append(random.randrange(10))
print(liczby)
[5, 2, 3, 7, 6, 7, 2, 0, 1, 5]
liczby = []
for i in range(10):
# Liczby pseudolosowe z zakresu od 0 do 9, parzyste
liczby.append(random.randrange(0, 10, 2))
print(liczby)
[6, 8, 6, 2, 0, 2, 2, 4, 6, 6]
random.randint(a, b)
- działa podobnie jak random.randrange()
, ale w zakresie od liczby a
do b
włącznie. Brak jest trzeciego parametru oznaczającego ,,krok’'.
liczby = []
for i in range(10):
# Liczby pseudolosowe z zakresu od 0 do 5
liczby.append(random.randint(0, 5))
print(liczby)
[5, 3, 0, 1, 5, 0, 1, 5, 0, 5]
random.choice(seq)
- zwraca (pseudo)losowy element z podanej sekwencji (np. list, krotek itd.), można także przekazać łańcuch znaków, wtedy zostanie zwrócony znak.
zasady_azotowe = ['adenina', 'guanina', 'cytozyna', 'tymina', 'uracyl']
random.choice(zasady_azotowe)
'tymina'
dna = 'AGCTACGATTAGG'
random.choice(dna)
'T'
random.choices(population, weights=None, *, cum_weights=None, k=1)
- zwraca listę k
losowych elementów (mogą się powtarzać) z population
(listy, krotki, zbiory, łańcuchy znaków etc…). Pozostałymi parametrami nie będziemy się zajmować.
Można np. wykorzystać tę funkcję do wygenerowania losowej sekwencji DNA:
zasady = 'ACGT'
sekwencja_lista = random.choices(zasady, k=10)
print(sekwencja_lista)
# Tworzymy łańcuch znaków z listy
sekwencja = ''.join(sekwencja_lista)
print(sekwencja)
['C', 'C', 'A', 'G', 'G', 'T', 'C', 'T', 'A', 'A']
CCAGGTCTAA
random.sample(population, k)
- zwraca listę k
losowych elementów z population
ale bez powtórzeń. Wartość k
nie może być większa niż liczba elementów do wylosowania.
Przykładowo, możemy wylosować trzy planety Układu Słonecznego:
planety = ['Merkury', 'Wenus', 'Ziemia', 'Mars', 'Jowisz', 'Saturn', 'Uran', 'Neptun']
random.sample(planety, k=3)
['Ziemia', 'Neptun', 'Merkury']
Natomiast w ten sposób możemy wylosować 6 liczb z 49 (symulacja losowania Lotto):
random.sample(range(1,50), 6)
[45, 35, 22, 27, 9, 20]
random.shuffle(x)
- losowo miesza elementy w x. W tym przypadku nie jest tworzony nowy obiekt z wynikiem, ale zmienia się przekazany funkcji obiekt x
. Zatem nie można jej użyć dla obiektów niemodyfikowalnych, jak string
czy tuple
(krotka). W takich przypadkach można użyć sample(x, k=len(x))
, który zwraca nową listę z wynikiem. Należy zauważyć, że przekazany obiekt musi być uporządkowany, nie możemy zatem użyć np. zbioru (set
).
Pomieszajmy np. kolejność planet:
planety = ['Merkury', 'Wenus', 'Ziemia', 'Mars', 'Jowisz', 'Saturn', 'Uran', 'Neptun']
random.shuffle(planety)
print(planety)
['Merkury', 'Ziemia', 'Saturn', 'Mars', 'Wenus', 'Neptun', 'Uran', 'Jowisz']
Inne biblioteki
Poza Biblioteką Standardową Pythona dostępnych jest wiele innych bibliotek o bardzo różnych zastosowaniach. Niektóre z nich możesz już mieć zainstalowane wraz z instalacją środowiska Anaconda, inne możesz doinstalować samodzielnie. Jeśli używasz Anacondy można wiele z nich zainstalować (Terminal/Anaconda Prompt) poleceniem: conda install nazwa_pakietu
. Jeśli nie używasz Anacondy można użyć np. narzędzia pip: pip install nazwa_pakietu
. Instalacja danej biblioteki powinna być zresztą opisana na stronie internetowej jej poświęconej.
Niektórych bibliotek będziemy używać w dalszej części kursu, teraz wspomnę tylko o dwu z nich, służących wizualizacji danych.
Biblioteka matplotlib
Matplotlib jest bardzo rozbudowaną biblioteką służąca wizualizacji w języku Python. Możemy z jej pomocą tworzyć np. wykresy, czy histogramy, co zobaczymy w poniższych, prostych przykładach. Warto zajrzeć na stronę WWW biblioteki, która znajduje się pod adresem: https://matplotlib.org.
W pierwszym przykładzie utworzymy wykres losowych zmian początkowej liczby (10). Przy każdej ze 100 iteracji pętli losowana jest liczba z zakresu -1 do 1, która jest dodawana do bieżącej wartości zmiennej l
. Kolejne wartości l
są dołączane do listy liczby
. Na końcu jest tworzony, zapisany do pliku i wyświetlony (w tej kolejności!) wykres zmian wartości l
. Wykres będzie zapisany w formacie wektorowym svg
łatwym w dalszej edycji w takich programach jak np. Inkscape
# Import potrzebnych modułów
import matplotlib.pyplot as plt
import random
# Lista przechowująca wartości l
liczby = []
# Przypisanie początkowej wartości 10 zmiennej l
l = 10
for i in range(100):
# Ddanie wartości l do listy
liczby.append(l)
# Zmiana l o wylosowaną wartość z zakresu -1 - 1
l += random.uniform(-1, 1)
# Tworzenie wykresu
plt.plot(liczby)
# etykiety osi x i y
plt.xlabel('losowanie',fontsize=15)
plt.ylabel('wartość',fontsize=15)
# Zapisanie pliku w formacie svg
plt.savefig('wykres_liniowy_1.svg')
# Wyświetlenie wykresu
plt.show()
Drugi przykład będzie rozwinięciem poprzedniego. Na wykresie przedstawione zostaną dwie serie zmian losowych wartości. Ustawimy kolor i styl krzywych oraz dodamy legendę.
import matplotlib.pyplot as plt
import random
liczby_1 = []
liczby_2 = []
l_1 = 10
l_2 = 10
for i in range(100):
liczby_1.append(l_1)
liczby_2.append(l_2)
l_1 += random.uniform(-1, 1)
l_2 += random.uniform(-1, 1)
# Linia zielona, ciągła, etykieta: "seria 1"
plt.plot(liczby_1, 'g-', label='seria 1')
# Linia niebieska, kropkowana, etykieta: "seria 2"
plt.plot(liczby_2, 'b:', label='seria 2')
plt.xlabel('losowanie',fontsize=15)
plt.ylabel('wartość',fontsize=15)
# legenda loc=0 oznacza optymalną lokalizację
plt.legend(loc=0)
plt.savefig('wykres_liniowy_2.svg')
# Wyświetlenie wykresu
plt.show()
W trzecim przykładzie pokażę, jak utworzyć wykres wartości losowych o rozkładzie Gaussa. Przykład ten jest na tyle podobny do poprzedniego, że nie wymaga raczej dodatkowych wyjaśnień. Tajemniczy może wydawać się parametr bins
, który służy określeniu interwałów wartości. Więcej na ten temat, jak tez innych aspektów tworzenia histogramów za pomocą matplotlib
można poczytać np. w dokumentacji: https://matplotlib.org/3.3.3/api/_as_gen/matplotlib.pyplot.hist.html. Tym razem zapiszemy plik w formacie png
.
import matplotlib.pyplot as plt
import random
liczby = []
srednia = 10
sd = 1
for i in range(100000):
liczba = random.gauss(srednia, sd)
liczby.append(liczba)
plt.hist(liczby, bins = 'auto')
plt.xlabel('wartość',fontsize=15)
plt.ylabel('liczba wartości',fontsize=15)
# Zapisanie pliku w formacie png
plt.savefig('wykres_2.png')
plt.show()
Biblioteka seaborn
W ostatnim przykładzie utworzymy podobny, jak w poprzednim, histogram, ale tym razem przy użyciu biblioteki seaborn
, która bazuje na matplotlib
, poszerzają, jest nowocześniejsza i bardziej przyjazna w użyciu. Strona domowa znajduje się pod adresem: https://seaborn.pydata.org.
import seaborn as sbn
import random
liczby = []
srednia = 10
sd = 1
for i in range(100000):
liczba = random.gauss(srednia, sd)
liczby.append(liczba)
# Tworzenie histogramu
his = sbn.histplot(liczby)
# Ustawienie etykiet osi
his.set_xlabel("wartość", fontsize=15)
his.set_ylabel("liczba wartości", fontsize=15)
# Zapisanie histogramu w formacie png
his.get_figure().savefig('histogram_seaborn.png')