G. Jagiella

Podstawowy warsztat AI 2025/26

ostatnia modyfikacja: 31.10.2025

Wykład 5 - tablice, numpy, zastosowania w wizualizacji¶

Tablice w "surowym" Pythonie¶

Rozważmy tablicę (np. liczb):

2.53.61.0-1.0
-1.010.311.31.4
1.03.4-6.01.2

Każdy wiersz możemy traktować jak ciąg wartości, natomiast całą tablicę jako ciąg wierszy.
Ciąg możemy reprezentować jako listę.
Zatem: tablicę można reprezentować jako listę list.

In [1]:
table = [[2.5, 3.6, 1.0, -1.0], 
         [-1.0, 10.3, 11.3, 1.4],
         [1.0, 3.4, -6.0, 1.2]]
print(table)
[[2.5, 3.6, 1.0, -1.0], [-1.0, 10.3, 11.3, 1.4], [1.0, 3.4, -6.0, 1.2]]

table[i] to i-ta lista, czyli i-ty wiersz, a wiersz ten można indeksować:

In [2]:
table[1][2]
Out[2]:
11.3
In [3]:
table[1][2] = 100
print(table)
[[2.5, 3.6, 1.0, -1.0], [-1.0, 10.3, 100, 1.4], [1.0, 3.4, -6.0, 1.2]]

Tablice niekoniecznie złożone z liczb:

In [4]:
board = [['🌊', '🌊', '🟩', '🌳'],
         ['🌊', '🟩', '🌳', '🌳'],
         ['🟩', '🏰', '🐉', '🌳'],
         ['🟩', '🟩', '⛰️', '⛰️']]

Dla wyższych wymiarów (np. liczby ułożone w kostkę) - listy tablic, czyli listy list list.

tablice

Taki sposób reprezentacji danych tabelarycznych jest naturalny w "czystym" Pythonie, jednak do przechowywania i obróbki takich danych służą wyspecjalizowane biblioteki. Przykład na dziś": numpy.

Biblioteka numpy¶

In [ ]:
!pip install numpy
In [5]:
import numpy as np # zwyczajowy skrót

Główne cele biblioteki:

  • Dostarczanie obiektów do przechowywania danych liczbowych (np. macierzy). Wiele innych bibliotek korzysta z tych reprezentacji - numpy to w praktyce lingua franca dla ML.
  • Wykonywanie operacji na danych (implementacja np. wielu narzędzi algebry liniowej).
  • Wydajne obliczenia numeryczne na całych zestawach danych, nie tylko pojedynczych liczbach (które w "domyślnej" implementacji Pythona są bardzo powolne w porównaniu do innych języków).

Typ ndarray: wielowymiarowa tablica obiektów (zazwyczaj liczb).

In [6]:
X = np.array([[1, 2, 3], [4, 5, 6]])
print(X)
print(type(X))
X[0][0] = 50
print(X)
X[0,0] = 100 # jak X[0][0]
print(X)
[[1 2 3]
 [4 5 6]]
<class 'numpy.ndarray'>
[[50  2  3]
 [ 4  5  6]]
[[100   2   3]
 [  4   5   6]]

Inne kształty:

In [7]:
X = np.array([[1, 2, 3], [4, 5, 6]]) # dwa wymiary
print(X.shape)
(2, 3)
In [8]:
X = np.array([1, 2, 3]) # jeden wymiar: ciąg
print(X.shape)
(3,)
In [9]:
X = np.array([[[1, 2, 3], [4, 5, 6]], [[11, 12, 13], [14, 15, 16]]])
print(X)
print(X.shape)
[[[ 1  2  3]
  [ 4  5  6]]

 [[11 12 13]
  [14 15 16]]]
(2, 2, 3)

Pewne operacje na ndarray¶

Indeksowanie i slicing:

In [10]:
A = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
print(A)
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
In [11]:
A[1]
Out[11]:
array([5, 6, 7, 8])
In [12]:
A[1].shape
Out[12]:
(4,)
In [13]:
A[1, 1]
Out[13]:
6
In [14]:
A[0:2, 1:3]
Out[14]:
array([[2, 3],
       [6, 7]])
In [15]:
A[0:2, 1]
Out[15]:
array([2, 6])
In [16]:
A[:, 1:]
Out[16]:
array([[ 2,  3,  4],
       [ 6,  7,  8],
       [10, 11, 12]])
In [17]:
A[:2, :2] = np.array([[100, 101], [102, 103]])
print(X)
[[[ 1  2  3]
  [ 4  5  6]]

 [[11 12 13]
  [14 15 16]]]
In [18]:
A[:2, :2] = -1
print(X)
[[[ 1  2  3]
  [ 4  5  6]]

 [[11 12 13]
  [14 15 16]]]

Różne funkcje - charakterystyki danych¶

In [19]:
X = np.array([[1, 2, 3], [4, 5, 6]])
print(X)
[[1 2 3]
 [4 5 6]]
In [20]:
np.sum(X)
Out[20]:
21
In [21]:
np.mean(X)
Out[21]:
3.5
In [22]:
np.max(X)
Out[22]:
6
In [23]:
np.sum(X, axis=0)
Out[23]:
array([5, 7, 9])
In [24]:
np.sum(X, axis=1)
Out[24]:
array([ 6, 15])

Kompleksowe operacje na tablicach¶

In [25]:
X = np.array([[1, 2, 3], [4, 5, 6]])
Y = np.array([[7, 8, 9], [10, 11, 12]])
print(X)
print()
print(Y)
[[1 2 3]
 [4 5 6]]

[[ 7  8  9]
 [10 11 12]]
In [26]:
print(X + Y)
[[ 8 10 12]
 [14 16 18]]
In [27]:
print(X * Y)
[[ 7 16 27]
 [40 55 72]]
In [28]:
print(X / Y)
[[0.14285714 0.25       0.33333333]
 [0.4        0.45454545 0.5       ]]
In [29]:
print(Y % X)
[[0 0 0]
 [2 1 0]]
In [30]:
print(X + 1000)
[[1001 1002 1003]
 [1004 1005 1006]]
In [31]:
print(X * 0.5)
[[0.5 1.  1.5]
 [2.  2.5 3. ]]
In [32]:
print(1 / X)
[[1.         0.5        0.33333333]
 [0.25       0.2        0.16666667]]
In [33]:
X = np.array([1, 2, 3])
Y = np.array([5, 4, 3])
np.dot(X, Y) # iloczyn skalarny
Out[33]:
22

Zwektoryzowane funkcje¶

In [34]:
X = np.array([[1, 2, 3], [4, 5, 6]])
print(X)
[[1 2 3]
 [4 5 6]]
In [35]:
np.sin(X)
Out[35]:
array([[ 0.84147098,  0.90929743,  0.14112001],
       [-0.7568025 , -0.95892427, -0.2794155 ]])
In [36]:
np.cos(X)
Out[36]:
array([[ 0.54030231, -0.41614684, -0.9899925 ],
       [-0.65364362,  0.28366219,  0.96017029]])
In [37]:
np.exp(X)
Out[37]:
array([[  2.71828183,   7.3890561 ,  20.08553692],
       [ 54.59815003, 148.4131591 , 403.42879349]])

Dzięki temu można pisać całe wyrażenia i wyliczać je dla wszystkich elementów danej tablicy:

In [38]:
np.sin(X)**2
Out[38]:
array([[0.70807342, 0.82682181, 0.01991486],
       [0.57275002, 0.91953576, 0.07807302]])
In [39]:
np.sin(X)**2 + np.cos(X)**2
Out[39]:
array([[1., 1., 1.],
       [1., 1., 1.]])

Kilka przydatnych konstrukcji¶

In [40]:
np.zeros((3, 4))
Out[40]:
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.],
       [0., 0., 0., 0.]])
In [41]:
np.ones((3, 4))
Out[41]:
array([[1., 1., 1., 1.],
       [1., 1., 1., 1.],
       [1., 1., 1., 1.]])
In [42]:
np.full((3, 4), 2025)
Out[42]:
array([[2025, 2025, 2025, 2025],
       [2025, 2025, 2025, 2025],
       [2025, 2025, 2025, 2025]])
In [43]:
np.linspace(-10, 10, 25)
Out[43]:
array([-10.        ,  -9.16666667,  -8.33333333,  -7.5       ,
        -6.66666667,  -5.83333333,  -5.        ,  -4.16666667,
        -3.33333333,  -2.5       ,  -1.66666667,  -0.83333333,
         0.        ,   0.83333333,   1.66666667,   2.5       ,
         3.33333333,   4.16666667,   5.        ,   5.83333333,
         6.66666667,   7.5       ,   8.33333333,   9.16666667,
        10.        ])
In [44]:
np.arange(0, 5, 0.1)
Out[44]:
array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1, 1.2,
       1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1, 2.2, 2.3, 2.4, 2.5,
       2.6, 2.7, 2.8, 2.9, 3. , 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8,
       3.9, 4. , 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9])

Synergia z matplotlib¶

In [45]:
import matplotlib.pyplot as plt
In [46]:
X = np.linspace(0, 2 * np.pi, 100)
X
Out[46]:
array([0.        , 0.06346652, 0.12693304, 0.19039955, 0.25386607,
       0.31733259, 0.38079911, 0.44426563, 0.50773215, 0.57119866,
       0.63466518, 0.6981317 , 0.76159822, 0.82506474, 0.88853126,
       0.95199777, 1.01546429, 1.07893081, 1.14239733, 1.20586385,
       1.26933037, 1.33279688, 1.3962634 , 1.45972992, 1.52319644,
       1.58666296, 1.65012947, 1.71359599, 1.77706251, 1.84052903,
       1.90399555, 1.96746207, 2.03092858, 2.0943951 , 2.15786162,
       2.22132814, 2.28479466, 2.34826118, 2.41172769, 2.47519421,
       2.53866073, 2.60212725, 2.66559377, 2.72906028, 2.7925268 ,
       2.85599332, 2.91945984, 2.98292636, 3.04639288, 3.10985939,
       3.17332591, 3.23679243, 3.30025895, 3.36372547, 3.42719199,
       3.4906585 , 3.55412502, 3.61759154, 3.68105806, 3.74452458,
       3.8079911 , 3.87145761, 3.93492413, 3.99839065, 4.06185717,
       4.12532369, 4.1887902 , 4.25225672, 4.31572324, 4.37918976,
       4.44265628, 4.5061228 , 4.56958931, 4.63305583, 4.69652235,
       4.75998887, 4.82345539, 4.88692191, 4.95038842, 5.01385494,
       5.07732146, 5.14078798, 5.2042545 , 5.26772102, 5.33118753,
       5.39465405, 5.45812057, 5.52158709, 5.58505361, 5.64852012,
       5.71198664, 5.77545316, 5.83891968, 5.9023862 , 5.96585272,
       6.02931923, 6.09278575, 6.15625227, 6.21971879, 6.28318531])
In [47]:
Y = np.sin(X)
In [48]:
plt.plot(X, Y)
plt.show()
In [49]:
X = np.arange(0, 10, 0.01)
In [50]:
plt.plot(X, 2 * X + 1)
plt.plot(X, X ** 2 / 2)
plt.plot(X, 5 * np.cos(X))
plt.show()

Obrazy jako tablice¶

Tablice numpy są używane wprost w matplotlib i innych bibliotekach.

Przykład: ręcznie napisany obraz monochromatyczny jako tablica wymiaru (wiersze) $\times$ (kolumny), gdzie liczba rzeczywista z przedziału $[0, 1]$ reprezentuje natężenie.

In [51]:
Z = np.array([[1, 0.5, 1, 0.33, 1], [0, 1, 0.33, 0, 0], [0, 0.5, 0.5, 1, 0.25], [0.5, 1, 0.33, 0.25, 1]])
plt.imshow(Z) # wyświetla tablicę jako obraz monochromatyczny - paleta domyślna lub dostarczona przez użytkownika
plt.show()

Rysunek jest w "domyślnej" palecie. Inna paleta (w której najmniejsza wartość to [niemal] biały, największa to czerwony):

In [52]:
plt.imshow(Z, cmap="Reds")
plt.show()

A kolorowe obrazki?

Przypomnienie: kolor można opisać za pomocą trzech składowych (R - czerwona, G - zielona, B - niebieska). Natężenie każdej ze składowych wyraża się jako liczba ze zbioru $\{0, 1, \ldots, 255\}$.

Każdą składową można zebrać w tablicę.

In [53]:
R = np.array([[0, 128, 0, 255], [255, 128, 255, 0]])
G = np.array([[0, 255, 0, 255], [255, 0, 128, 255]])
B = np.array([[0, 255, 255, 0], [255, 0, 128, 128]])
In [54]:
_, (i1, i2, i3) = plt.subplots(1, 3) # trochę magii
i1.imshow(R, cmap="gray")
i2.imshow(G, cmap="gray")
i3.imshow(B, cmap="gray")
plt.show()

Składowe można zebrać w trójwymiarową tablicę rozmiaru (wiersze) $\times$ (kolumny) $\times$ 3.

In [55]:
Z = np.stack((R, G, B), axis=2)
print(Z.shape)
print(Z[:,:,0])
(2, 4, 3)
[[  0 128   0 255]
 [255 128 255   0]]
In [56]:
plt.imshow(Z) # tablica (height, width, 3)
plt.show()

To już demonstracja konkretnych narzędzi (niekoniecznie z myślą o laboratoriach):

In [ ]:
!pip install imageio
In [57]:
import imageio # obsługa obrazków
In [58]:
cat = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/pwai/cat.jpg")
cat.shape
Out[58]:
(297, 400, 3)
In [59]:
plt.imshow(cat)
plt.show()
In [60]:
plt.imshow(cat[:, :, 0], cmap="gray") # "czerwona składowa" kota
plt.show()
In [61]:
_, (i1, i2, i3) = plt.subplots(1, 3, figsize=(15, 15)) # trochę podobnej magii
i1.imshow(cat[:, :, 0], cmap='gray')
i2.imshow(cat[:, :, 1], cmap='gray')
i3.imshow(cat[:, :, 2], cmap='gray')
plt.show()
In [62]:
eyes = cat[95:125, 165:240, :]
plt.imshow(eyes)
plt.show()
In [63]:
cat[95:125, 165:240, 0] = 0
In [64]:
plt.imshow(cat)
plt.show()
In [65]:
cat[95:125, 165:240] = 0
plt.imshow(cat)
plt.show()
In [66]:
cat = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/pwai/cat.jpg")

cat[:, :, 2] = cat[:, :, 0]
plt.imshow(cat)
plt.show()
In [67]:
cat = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/pwai/cat.jpg")

cat[95:125, 265:340, 1:] = cat[95:125, 165:240, 0:2]
cat[95:125, 265:340, 0] = 0
plt.imshow(cat)
plt.show()
In [68]:
cat = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/pwai/cat.jpg")

plt.imshow(255 - cat)
plt.show()
In [69]:
plt.imshow(cat // 2)
plt.show()
In [70]:
plt.imshow(np.clip(cat**1.1, 0, 255).astype(np.uint8))
plt.show()
In [ ]: