PPy3/NumPy
Spis treści
NumPy: rachunki numeryczne na tablicach liczb
Pakiet Numpy
Moduł Numpy jest podstawowym zestawem narzędzi dla języka Python umożliwiającym zaawansowane obliczenia matematyczne, w szczególności do zastosowań naukowych (tzw. obliczenia numeryczne, jak mnożenie i dodawanie macierzy, diagonalizacja czy odwrócenie, całkowanie, rozwiązywanie równań, itd.). Daje on nam do dyspozycji specjalizowane typy danych, operacje i funkcje, których nie ma w typowej instalacji Pythona. Natomiast moduł Scipy pozwala na dostęp do bardziej złożonych i różnorodnych algorytmów wykorzystujących narzędzia dostarczone w Numpy.
Przedstawimy tutaj tylko wstęp do Numpy. Wynika to z faktu, że opisanie licznych funkcji dostępnych w bibliotece Numpy jest ogromną pracą, która zupełnie nie ma sensu — równie dobrze można zajrzeć bezpośrednio do źródła, http://docs.scipy.org/doc/numpy/reference/.
Najważniejszym obiektem, na którym bazuje pakiet Numpy i szereg pakietów z niego korzystających jest klasa ndarray wprowadzająca obiekty array. Obiekty array możemy traktować jako uniwersalne pojemniki na dane w postaci macierzy (czyli wektorów lub tablic). W porównaniu ze standardowymi typami sekwencji Pythonowych (lista, krotka) jest kilka różnic w operowaniu tymi obiektami:
- obiekty przechowywane w tablicy array muszą być wszystkie tego samego typu;
- obiekty array zachowują swój rozmiar; przy zmianie rozmiaru takiego obiektu powstaje nowy obiekt, a obiekt sprzed zmiany zostaje usunięty;
- obiekty array wyposażone są w bogaty zestaw funkcji operujących na wszystkich przechowywanych w obiekcie danych, specjalnie optymalizowanych do przetwarzania dużych ilości danych. Jak to działa zostanie zaprezentowane poniżej.
Tworzenie tablic
Najprostszym sposobem stworzenia tablicy Numpy jest wywołanie funkcji array z argumentem w postaci listy liczb. Jeśli zamiast listy liczb użyjemy listy zawierającej inne listy (tzw. listy zagnieżdżone), to otrzymamy tablicę wielowymiarową. Na przykład jeśli listy są podwójnie zagnieżdzone, to otrzymujemy tablicę dwuwymiarową (macierz).
# przykład wykorzystania Numpy
>>> import numpy
>>> A = numpy.array([1, 3, 7, 2, 8])
array([1, 3, 7, 2, 8])
>>> B = numpy.array([[1, 2, 3], [4, 5, 6]])
>>> B
array([[1, 2, 3],
[4, 5, 6]])
>>> B.transpose()
array([[1, 4],
[2, 5],
[3, 6]])
Innym sposobem tworzenia tablicy jest funkcja numpy.arange, która działa analogicznie do range, tyle tylko, że zwraca tablicę NumPy zamiast listy, i dopuszcza parametry ułamkowe -- a nie tylko całkowite.
Argumenty są takie same:
- indeks początkowy [opcjonalnie, domyślnie 0]
- indeks następny po końcowym
- krok [opcjonalnie, domyślnie 1]
>>> numpy.arange(1000000)
array([ 0, 1, 2, ..., 999997, 999998, 999999])
>>> numpy.arange(0.1, 0.2, 0.01)
array([ 0.1 , 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19])
>>> numpy.arange(0.9, 0.0, -0.1)
array([ 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1])
Jak było już wspomniane, w przypadku tablicy array typowe operacje matematyczne możemy przeprowadzić dla wszystkich elementów tablicy przy użyciu jednego operatora lub funkcji. Zachowanie takie jest odmienne niż w przypadku list czy innych sekwencji Pythona. Jeśli chcielibyśmy na przykład pomnożyć wszystkie elementy listy L przez liczbę a, musimy użyć pętli:
L = [1, 3, 5, 2, 3, 1]
for k, x in enumerate(L):
L[k] = a * x
Można też zapisać to zwięźlej, używając wyrażenia generatorowego:
L = [1, 3, 5, 2, 3, 1]
L = [a * x for x in L]
jest to jednak poniekąd tylko uproszczony zapis pętli. Natomiast mnożenie wszystkich elementów tablicy M przez liczbę a wygląda tak:
M = numpy.array([1, 3, 5, 2, 3, 1])
M = a * M
Operacje wykonywane od razu na całych macierzach mają wiele zalet. Kod programu jest prostszy i krótszy, przez co mniej podatny na błędy. Poza tym nie musimy przejmować się konkretną realizacją danej operacji — robi to za nas funkcja pakietu Numpy, która jest specjalnie optymalizowana, żeby działała jak najszybciej.
- Inne
- zob.numpy.mgrid, numpy.ogrid, numpy.linspace, numpy.zeros, numpy.ones, numpy.r_.
Ćwiczenia
1. Napisz funkcję zastap_zera(A, x), która zwraca tablicę utworzoną z tablicy A (o dowolnym kształcie) poprzez zastąpienie wszystkich elementów równych zero liczbą x. Sama tablica A powinna pozostać niezmieniona.
2. Napisz funkcję wysrodkuj(A), która modyfikuje tablicę A (o dowolnym kształcie) w taki sposób, że od każdego jej elementu odejmuje średnią arytmetyczną wszystkich elementów A.
3. Dla (dowolnego rozmiaru większego niż 1) tablicy kwadratowej A stworzyć tablicę jednowymiarową, której k-ty element to suma elementów k-tej kolumny tablicy A leżących poniżej głównej przekątnej.
3. Napisz funkcję, która w minimalnej liczbie kroków tworzy (i zwraca) kwadratową tablicę NumPy zawierającą na przemian jedynki i zera, o dowolnym - zadanym przez argument wywołania - rozmiarze, w postaci:
In [1]: from naprzemian import naprzemian
In [2]: naprzemian(2)
Out[2]:
array([[ 1., 0.],
[ 0., 1.]])
In [3]: naprzemian(3)
Out[3]:
array([[ 1., 0., 1.],
[ 0., 1., 0.],
[ 1., 0., 1.]])
In [4]: naprzemian(4)
Out[4]:
array([[ 1., 0., 1., 0.],
[ 0., 1., 0., 1.],
[ 1., 0., 1., 0.],
[ 0., 1., 0., 1.]])
In [5]: naprzemian(5)
Out[5]:
array([[ 1., 0., 1., 0., 1.],
[ 0., 1., 0., 1., 0.],
[ 1., 0., 1., 0., 1.],
[ 0., 1., 0., 1., 0.],
[ 1., 0., 1., 0., 1.]])