NumPy – wstęp do biblioteki w języku Python

Piotr Ludwinek | Rozwój oprogramowania | 09.03.2023

Jeżeli pojęcie biblioteki Python nie jest ci znane, w tym artykule wyjaśnię, czym jest biblioteka w języku Python, oraz omówię możliwości biblioteki NumPy, która w moim przekonaniu jest jedną z ciekawszych propozycji na start.

Czym właściwie jest biblioteka Python?

Jeżeli od pewnego czasu programujesz w języku Python, na pewno korzystasz z różnych bibliotek, które wspierają implementację rozwiązań i zwiększają wydajność zarówno twoją, jak i funkcjonalności, nad którymi pracujesz. Najpopularniejsze biblioteki w języku Python to m.in. Pandas, NumPy, TensorFlow czy SciPy.

Biblioteka w języku Python to w dużym uproszczeniu zbiór funkcji i metod, które stworzono w celu ułatwienia implementacji rozwiązań. Funkcje te można w łatwy sposób wykorzystać w programie, nie tracąc czasu na tworzenie wszystkiego od zera. To pewnego rodzaju moduły, które zostały stworzone w celu ułatwienia pracy z problemami konkretnych obszarów nauki czy biznesu.

Wiele bibliotek Python używanych jest np. na potrzeby medycyny (MedPy), przemysłu ciężkiego, lotnictwa, bankowości czy telekomunikacji i wojskowości. Biblioteki mogą także wspierać wąskie specjalizacje obszaru IT, takie jak przetwarzanie i wizualizacja zbiorów danych (Pandas, Matplotlib), sieci neuronowe (TensorFlow, PyTorch), a także obliczenia naukowe (SciPy).

Każda biblioteka posiada dokumentację, która objaśnia możliwości wykorzystania zawartych w niej funkcji i metod. Dokumentacja zazwyczaj zawiera też fragmenty kodu, które po niewielkim dostosowaniu można z powodzeniem użyć we własnym projekcie.

Do czego służy pakiet NumPy?

Jak zapewne wiesz, analiza danych (ang. Data Science) staje się z roku na rok coraz popularniejsza, a w momencie pisania tego artykułu jej wykorzystanie stało się w zasadzie powszechne w wielu obszarach biznesu. Obok różnych procesów dotyczących przygotowania danych czy wizualizacji efektów stoją metody obliczeniowe, które wspomagają uzyskanie realnej wartości z zebranych danych. W tym artykule skupiam się na danych numerycznych.

Języki programowania, do których należy Python, wspomagają naukowców, analityków i programistów w implementacji rozwiązań i osiąganiu rezultatów, które z powodzeniem mogą zostać użyte w procesach decyzyjnych wyższego szczebla i mieć realny wpływ na otaczający nas świat. W przypadku wspomnianych metod obliczeniowych jedną z najpopularniejszych bibliotek jest właśnie NumPy (Numeric Python). Jak nazwa wskazuje, skupia się ona głównie na wsparciu pracy z danymi numerycznymi i umożliwia efektywne i wydajne dokonywanie operacji na macierzach, tablicach czy wektorach, które zawierają elementy tego samego typu. Po wprowadzeniu teoretycznym skupimy się bardziej na części praktycznej i bazując na prostych przykładach, zapoznasz się z możliwościami biblioteki NumPy. Zanim to jednak zrobimy, upewnij się, że biblioteka NumPy jest u ciebie zainstalowana.

Instalacja NumPy

Instalacja NumPy została szczegółowo wyjaśniona w części FAQ. Jeżeli biblioteka NumPy jest już zainstalowana, możesz przejść do kolejnej części.

Nieważne, czy korzystasz z linii poleceń, IDE (np. PyCharm) czy notebooka (np. Jupyter). Jedyne, co musisz zrobić, żeby móc korzystać z NumPy, to napisać linijkę kodu odpowiedzialnego za import biblioteki.

import numpy as np

Od teraz możesz korzystać ze wszystkich możliwości, jakich dostarcza NumPy. Zachęcam cię do samodzielnego uruchomienia fragmentów kodu, które zawarte są w tym artykule, i modyfikacji według uznania, żeby lepiej zrozumieć zasady działania i możliwości omawianej biblioteki.

Skupmy się najpierw na rzeczach prostych, jakimi są np. podstawowe operacje arytmetyczno-logiczne. Do tego niezbędne jest zrozumienie kluczowej struktury, którą wprowadzono w NumPy, czyli tablicy.

Teraz pewnie zastanawiasz się, dlaczego w ogóle masz korzystać z dodatkowej biblioteki, jeżeli wszystkie funkcjonalności możesz napisać z użyciem podstawowych rozwiązań w języku Python, jakimi są pętle (ang. loop) czy listy (ang. list). W profesjonalnym podejściu i pracy na ogromnych zbiorach danych (nie tylko numerycznych) często ważnym aspektem jest czas. I w tym tkwi właśnie przewaga NumPy, czyli w szybkości działania, która dodatkowo idzie w parze z niskim progiem wejścia dla użytkownika. W dalszej części artykułu przedstawię kilka przykładów, które wprowadzą cię w podstawy NumPy. Wykorzystane funkcje poprawiają wydajność w obliczeniach. A można to osiągnąć między innymi poprzez operacje na wspomnianych wcześniej tablicach.

Czym są tablice w NumPy?

Tablica (ang. array) w NumPy to struktura o jednym wymiarze lub większej liczbie wymiarów pozwalająca na działania ze zbiorami danych numerycznych, zaczynając od kilkuelementowych po ogromne zbiory przechowywane np. w chmurze. Pamiętajmy, że nie tylko wymiary charakteryzują tablicę – istnieje też kilka innych, równie ważnych cech.

  • Tablice są stałej wielkości – nie możemy zmienić rozmiaru po jej utworzeniu.
  • Przechowują elementy tego samego typu, np. liczby całkowite (ang. Integer) lub zmiennoprzecinkowe (ang. float-point).
  • Wykorzystywane „pod spodem” algorytmy pozwalają na bardzo szybkie operacje i efektywne wykorzystanie pamięci.

Niektórzy porównują tablice do list w Pythonie, ale listy różnią się od tablic, np. możliwością przechowywania elementów różnego typu (listy mogą być heterogeniczne), a także są jednowymiarowe (chociaż możliwe jest przechowywanie jednowymiarowej listy w drugiej liście). To tyle z teoretycznego wprowadzenia. Poniżej zamieściłem kilka przykładów wraz z objaśnieniami.

W celu stworzenia tablicy możesz skorzystać z kilku opcji, między innymi:

1. Konwersja listy w tablicę.

import numpy as np
# jednowymiarowa tablica na podstawie listy
arr_1d = np.array([1, 2, 3])
# dwuwymiarowa tablica na podstawie listy
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])

2. Tablica o stałej wartości.

import numpy as np
# jednowymiarowa tablica wypełniona zerami o długości 3
arr_zeros = np.zeros(5)
# dwuwymiarowa tablica wypełniona jedynkami o wymiarach 3x3
arr_2d_ones = np.ones((3, 3))

3. Tablica z wartości losowych.

# jednowymiarowa tablica z losowymi wartościami z przedziału [0,1] o długości 3
arr = np.random.rand(3)
# dwuwymiarowa tablica z losowymi wartościami z rozkładu normalnego o wymiarach 3x3
arr_2d = np.random.randn(3, 3)

4. Tablica na podstawie pliku wejściowego.

import numpy as np
# inicjalizacja tablicy za pomocą pliku wejściowego
arr_file = np.loadtxt('file_name.txt')

Jak widzisz, lista opcji stworzenia tablicy nie ogranicza się do jednej czy dwóch, a powyższe przykłady jej nie wyczerpują. Ponieważ wiesz już czym są tablice i jak je stworzyć, możemy przejść do omówienia operacji z wykorzystaniem tablic numerycznych, które ułatwią obliczenia na dużych zbiorach danych.

2020.04.28 JPro cover 2 1 - NumPy – wstęp do biblioteki w języku Python

Pułapki współbieżności. Narzut synchronizacji wątków

W powszechnym mniemaniu programowanie współbieżne zapewnia przyspieszenie działania każdej aplikacji.

Przeczytaj artykuł

NumPy – podstawowe operacje

import numpy as np
# tworzenie jednowymiarych tablic a i b
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# dodawanie tablicy b do tablicy a
c = a + b
# mnożenie tablicy a przez stałą 2
d = 2 * a

Wynikiem operacji logicznych takich jak AND (koniunkcja), OR (alternatywa) czy NOT (negacja) jest tablica zawierająca wartości logiczne True i False.

import numpy as np
# tworzenie jednowymiarych tablic a i b
a = np.array([1, 2, 3])
b = np.array([3, 2, 1])
# sprawdzamy, które elementy w tablicy a są mniejsze od odpowiadających im elementów w tablicy b
c = a < b
# sprawdzamy które elementy w tablicy a są równe 2 lub 3
d = (a == 2) | (a == 3)

Wynikiem operacji redukcyjnych takich jak suma, minimum, maksimum czy średnia jest skalar.

import numpy as np
# tworzenie jednowymiarowej tablicy a
a = np.array([1, 2, 3])
# suma elementów tablicy a
b = np.sum(a)
# średnia arytmetyczna dla elementów tablicy a
c = np.mean(a)
# największy element w tablicy a
d = np.max(a)

Dobrym przykładem jest także mnożenie macierzy i obliczenie wyznacznika, a także rozwiązanie układu równań liniowych.

import numpy as np
# tworzenie macierzy a i b
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
# operacja mnożenia macierzy a i b
c = np.dot(a, b)
# obliczenie wyznacznika macierzy a
d = np.linalg.det(a)
# wyznaczenie rozwiązania układu równań liniowych Ax = b
A = np.array([[1, 2], [3, 4]])
b = np.array([5, 6])
x = np.linalg.solve(A, b)

Różnica między ndarray a array

Jeżeli zagłębiłeś się chociaż trochę bardziej w tematykę tablic w bibliotece NumPy, to możliwe, że spotkałeś się z numpy.ndarray() oraz numpy.array(). Prawdopodobnie zastanawiasz się, jaka jest różnica pomiędzy nimi – dlatego proponuję krótkie wyjaśnienie. Na wstępie zaznaczę, że podstawowa wiedza z programowania obiektowego lub pojęcia typu klasa i obiekt powinny być ci znane w celu poprawnego zrozumienia różnicy pomiędzy ndarray a array.

Zgodnie z dokumentacją i koncepcją języka Python numpy.ndarray() jest klasą, a numpy.array() jest metodą/funkcją, za pomocą której tworzymy obiekt ndarray, czyli właśnie tablicę. Wcześniej omówiliśmy, w jaki sposób możesz stworzyć tablicę w NumPy. Zgodnie z dokumentacją NumPy możliwe jest tworzenie tablicy bezpośrednio za pomocą numpy.ndarray(), ale zalecanym podejściem jest korzystanie z funkcji wbudowanych, np. numpy.array(), numpy.zeros() lub numpy.empty().

Funkcje wbudowane

Za definicją funkcji wbudowanej w NumPy nie stoi nic skomplikowanego. To po prostu funkcja, która została dostarczona przez bibliotekę. Oznacza to, że możesz wywołać taką funkcję bez potrzeby importowania dodatkowych modułów np. poza biblioteką NumPy. Funkcje wbudowane to najczęściej zbiór podstawowych funkcjonalności gotowych do wykorzystania po przekazaniu.

odpowiednich parametrów (jeżeli są wymagane). W przypadku NumPy jest to zbiór funkcji umożliwiających działania na tablicach, macierzach czy wektorach. Jeżeli chcesz w pełni wykorzystać potencjał biblioteki NumPy, korzystanie z funkcji wbudowanych jest niezbędne. W celu zapoznania się z pełną listą funkcji wbudowanych odsyłam cię do dokumentacji NumPy, a poniżej zamieszczam kilka wybranych przykładów.

1. Utworzenie tablicy z równo rozłożonymi elementami w wybranym zakresie.

import numpy as np
# tablica z 10 równo rozłożonymi wartościami w zakresie od 0 do 2
a = np.linspace(0, 2, 10)

2. Utworzenie macierzy i jej transpozycja.

import numpy as np
# tworzenie macierzy 3x3
x = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# transpozycja macierzy a do macierzy b
b = np.transpose(a)

3. Sortowanie tablicy.

import numpy as np
# tworzenie tablicy z 10 elementami
a = np.array([3, 7, 3, 3, 2, 9, 7, 1, 5, 4])
# sortowanie tablicy
b = np.sort(a) 

4. Obliczenie transformaty Fouriera dla wybranej tablicy.

import numpy as np
# tworzenie tablicy z 6 elementami
a = np.array([1, 2, 3, 4, 5, 6])
# obliczanie transformaty Fouriera
b = np.fft.fft(a

5. Wygenerowanie pięciu losowych wartości z rozkładu normalnego.

import numpy as np
# ustalenie ziarna dla generatora liczb losowych
np.random.seed(12345)
# wygenerowanie pięciu losowych wartości z rozkładu normalnego
a = np.random.randn(5)

Powyżej zamieściłem kilka przykładów, zaczynając od tych o niskiej złożoności, ale niektóre z nich mogą wymagać znajomości bardziej zaawansowanych pojęć z obszarów matematyki, statystyki czy fizyki.

Porównanie czasu wykonania funkcji w NumPy i bez użycia tej biblioteki

Zanim omówię korzyści i potencjalne trudności wynikające z wykorzystania NumPy w twoim projekcie, chciałem pokazać ci różnice w czasie wykonania funkcji napisanej w języku Python bez dodatkowych bibliotek i tej z użyciem biblioteki NumPy. Użyjemy do tego dwóch przykładów. Pierwszy mierzy czas potrzebny na sumowanie losowych elementów z listy, a drugi pokazuje czas obliczania iloczynu skalarnego dwóch wektorów. Zwróć uwagę na to, że czas wykonania może się różnić w zależności od zasobów maszyny, na której uruchamiasz kod.

Przykład 1:

Pierwsza funkcja korzysta z numpy.sum(), a druga sumuje elementy z użyciem pętli for.

 import numpy as np
import time
# implementacja z użyciem NumPy
def numpy_sum(a):
return np.sum(a)
# implementacja bez dodatkowych bibliotek
def python_sum(a):
sum = 0
for i in a:
sum += i
return sum
# tworzenie listy z losowymi liczbami
a = np.random.randint(0, 100, 5000000)
# czas wykonania funkcji z NumPy
start_time = time.time()
numpy_sum(a)
print("Czas wykonania funkcji z NumPy: %.6f sekund" % (time.time() - start_time))
# czas wykonania funkcji bez dodatkowych bibliotek
start_time = time.time()
python_sum(a)
print("Czas wykonania funkcji bez NumPy: %.6f sekund" % (time.time() - start_time))
  • Czas wykonania funkcji z NumPy: 0.001995 sekund
  • Czas wykonania funkcji bez NumPy: 0.242352 sekund

Przykład 2:

Pierwsza funkcja korzysta z numpy.dot(), a druga korzysta z pętli for.

import numpy as np
import time
# implementacja z użyciem NumPy
def numpy_dot(a, b):
return np.dot(a, b)
# implementacja bez dodatkowych bibliotek
def python_dot(a, b):
dot = 0
for i in range(len(a)):
dot += a[i] * b[i]
return dot
# tworzenie dwóch wektorów z losowymi liczbami
a = np.random.randint(0, 100, 700000)
b = np.random.randint(0, 100, 700000)
# czas wykonania funkcji z NumPy
start_time = time.time()
numpy_dot(a, b)
print("Czas wykonania funkcji z NumPy: %.6f sekund" % (time.time() - start_time))
# czas wykonania funkcji bez dodatkowych bibliotek
start_time = time.time()
python_dot(a, b)
print("Czas wykonania funkcji bez NumPy: %.6f sekund" % (time.time() - start_time))
  • Czas wykonania funkcji z NumPy: 0.000000 sekund
  • Czas wykonania funkcji bez NumPy: 0.117685 sekund

Jak można zauważyć, funkcja z wykorzystaniem NumPy jest wyraźnie szybsza od implementacji z użyciem pętli for.

Biorąc pod uwagę, że zazwyczaj pracuje się na dużych zbiorach danych, ta różnica może być jeszcze większa.

blog 2023.01.18 cover 1 - NumPy – wstęp do biblioteki w języku Python

Wprowadzenie do świata Azure IoT

Czym jest Azure IoT? Jakie daje możliwości? Jaki jest koszt usług i gdzie zdobyć niezbędną wiedzę?

Przeczytaj artykuł

Zalety i wady korzystania z NumPy

Wykorzystanie NumPy w projekcie wiąże się z wieloma korzyściami i ułatwieniami, poniżej zebrałem najważniejsze z nich.

Zalety NumPy

  • Szybkość – główną zaletą NumPy jest szybkość, ponieważ rozwiązania w tej bibliotece bazują na niskopoziomowym języku C. Obliczenia są zoptymalizowane i pozwalają na wykonywanie operacji w sposób wektorowy, co w znaczący sposób przekłada się na wzrost wydajności.
  • Próg wejścia – NumPy ma niski próg wejścia dla osób, które na co dzień nie mają do czynienia z programowaniem. Umożliwia łatwe tworzenie lub modyfikację istniejących rozwiązań, które używane są w przetwarzaniu dużych zbiorów danych, w tym przypadku numerycznych.
  • Zakres operacji – jak omówiono w przykładach, NumPy posiada szeroki zakres operacji numerycznych. Umożliwia wykonanie prostych działań arytmetyczno-logicznych, ale też zadań sortowania czy operacji statystycznych. Dodatkowo działa niezależnie od platformy czy systemu operacyjnego. Jeżeli możesz korzystać z Pythona, pewnie skorzystasz również z NumPy.
  • Integracja z innymi bibliotekami – NumPy dobrze współpracuje z innymi bibliotekami, które używane są w analizie i pracy z dużymi zbiorami danych. Przykładem może być integracja z Pandas, Matplotlib lub SciPy.

Wady NumPy

Należy też pamiętać o potencjalnych utrudnieniach, które mogą wynikać z używania biblioteki NumPy nie do końca zgodnie z jej przeznaczeniem.

  • Wykorzystanie pamięci – biblioteka ta wykorzystana w niewłaściwy sposób może używać sporo pamięci, a to z kolei – wpłynąć na wydajność w przetwarzaniu ogromnych zbiorów danych. Ważne jest właściwe zrozumienie składni i znajomość pojęć matematycznych, które stoją za funkcjami dostarczanymi przez bibliotekę.
  • Ograniczone wykorzystanie – NumPy nie wspiera tablic o zmiennej długości, dlatego nie nadaje się do pracy na przykład z danymi tekstowymi. Istnieją inne biblioteki, które w tym przypadku poradzą sobie lepiej.
  • Indeksowanie może być skomplikowane – to temat na odrębny artykuł, ale należy wspomnieć, że NumPy pozwala na zaawansowane indeksowanie tablic, które poprawia wydajność programu. Wymaga to jednak praktyki i bardzo dobrego zrozumienia zarówno samej biblioteki, jak i przetwarzanego zbioru danych.

Podsumowanie

Mam nadzieję, że udało mi się przedstawić podstawowe zagadnienia związane z przetwarzaniem danych numerycznych za pomocą biblioteki NumPy i pokazać jej potencjalne możliwości. Implementacja w realnych projektach pozwoli w pełni pokazać jej potencjał i korzyści wynikające z użycia funkcji, których dostarcza. Szybkość, integracja z innymi bibliotekami i łatwość użycia zdecydowanie zachęcają do zapoznania się z jej możliwościami. Oczywiście, jak w każdym przypadku, sprawne korzystanie z tej biblioteki przychodzi z czasem, ale już od pierwszych godzin może przynieść zadowalające efekty.

FAQ

Jak zainstalować NumPy?

W celu instalacji biblioteki NumPy zachęcam do przejścia prostego tutoriala zawartego na stronie biblioteki: https://numpy.org/doc/stable/user/absolute_beginners.html Jeżeli masz już zainstalowany Python, możesz skorzystać z jednej z komend:
pip install numpy, lub conda install numpy.

TOPICS