NumPy. Основы визуализации в MPL

Библиотека NumPy

NumPy [/ˈnʌmpaɪ/ (NUM-py)] - библиотека языка Python, добавляющая поддержку многомерных массивов и матриц, а также целую коллекцию формул и высокоуровневых математических функций для работы с массивами и матрицами.

In [1]:
import numpy as np
In [2]:
np.__version__
Out[2]:
'1.18.1'

Давайте подумаем, зачем нужен целый модуль для математики, массивов и матриц?

Мне будет достаточно списков! - they said.

Что есть в numpy?

numpy-operations.png

Зачем же нужен numpy?

Сколько программистов нужно, чтобы заменить лампочку?

Ни одного - проблема тут по части железа.

Numpy нужен для векторизованных вычислений!

Что такое векторизованные вычисления?

Если бы у вас был список чисел, и ко всем надо было прибавить 1, то как бы вы поступили?

In [3]:
a = [1, 6, 3, 4, 3, 7]
In [4]:
a = [i + 1 for i in a]
a
Out[4]:
[2, 7, 4, 5, 4, 8]
In [5]:
a = np.array([1, 6, 3, 4, 3, 7])
a
Out[5]:
array([1, 6, 3, 4, 3, 7])
In [6]:
a + 1
Out[6]:
array([2, 7, 4, 5, 4, 8])

Мораль:

Векторизация помогает избавиться от циклов и лишнего кода!

А чем еще помогает векторизация вычислений?

In [7]:
mln = 10 ** 6
In [8]:
a = list(range(mln))
In [9]:
%%timeit

[e * e for e in a]
73.9 ms ± 1.42 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [10]:
a = np.arange(mln)
In [11]:
%%timeit

a * a
1.26 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Какая операция здесь самая медленная?

Конечно же, цикл!

Ещё дольше выполняются вложенные циклы:

In [12]:
rows, cols = 1000, 1000

a = [list(range(i, i + cols)) for i in range(0, rows)]
b = [[0 for j in range(cols)] for i in range(rows)]
In [13]:
%%timeit

for i in range(rows):
    for j in range(cols):
        b[i][j] = 2 * a[i][j]
126 ms ± 4.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Сравним с векторизованными циклами:

In [14]:
a = np.asarray([list(range(i, i + cols)) for i in range(0, rows)])
In [15]:
%%timeit

2 * a
1.19 ms ± 49.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Мораль:

Векторизация помогает ускорить скорость выполнения векторизуемых операций в десятки раз!

Массив numpy.array

В чем его отличие от списка?

list-array.png

Почему в массиве важно иметь один и тот же тип данных?

Создание массива

Самый простой способ создать массив numpy.array - из стандартного списка list.

vis-numpy-2.jpg

In [16]:
mydata = np.array([1, 2, 3])
mydata
Out[16]:
array([1, 2, 3])

Массив может быть и многомерным!

vis-numpy-10.jpg

In [17]:
mydata_2d = np.array([[1, 2],
                      [3, 4]])
mydata_2d
Out[17]:
array([[1, 2],
       [3, 4]])

Важнейшая информация о массиве

In [18]:
mydata.dtype
Out[18]:
dtype('int32')

Типы данных в numpy

Тип данных Описание
bool Boolean (True or False) stored as a byte
int Platform integer (normally either int32 or int64)
int8 Byte (-128 to 127)
int16 Integer (-32768 to 32767)
int32 Integer (-2147483648 to 2147483647)
int64 Integer (-9223372036854775808 to 9223372036854775807)
uint8 Unsigned integer (0 to 255)
uint16 Unsigned integer (0 to 65535)
uint32 Unsigned integer (0 to 4294967295)
uint64 Unsigned integer (0 to 18446744073709551615)
float Shorthand for float64
float32 Single precision float: sign bit, 8 bits exponent, 23 bits mantissa
float64 Double precision float: sign bit, 11 bits exponent, 52 bits mantissa
complex Shorthand for complex128
complex64 Complex number, represented by two 32-bit floats (real and imaginary components)
complex128 Complex number, represented by two 64-bit floats (real and imaginary components)
In [19]:
mydata = np.array([[1, 2, 3, 4, 5],
                   [6, 7, 8, 9, 0],
                   [7, 0, 8, 8, 1]], dtype=np.int8)
mydata
Out[19]:
array([[1, 2, 3, 4, 5],
       [6, 7, 8, 9, 0],
       [7, 0, 8, 8, 1]], dtype=int8)
In [20]:
len(mydata)
Out[20]:
3
In [21]:
mydata.ndim
Out[21]:
2
In [22]:
mydata.shape
Out[22]:
(3, 5)

numpy.array.shape

dimensions.png

Транспонирование

Что значит "транспонировать матрицу"?

Как транспонировать в стандартном Python?

In [23]:
list_data = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
list_T = list(zip(*list_data))
list_T
Out[23]:
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
In [24]:
data = np.array(list_data)
data.T
Out[24]:
array([[1, 4, 7],
       [2, 5, 8],
       [3, 6, 9]])
In [25]:
data.transpose()
Out[25]:
array([[1, 4, 7],
       [2, 5, 8],
       [3, 6, 9]])

Другие способы инициализации numpy.array...

Но сначала... Кто знает, что называют индусским кодом? :^)

In [ ]:
int a0 = 0;
int a1 = 0;
int a2 = 0;
int a3 = 0;
int a4 = 0;
int a5 = 0;
int a6 = 0;
int a7 = 0;
int a8 = 0;
int a9 = 0;

Допустим, мы хотим сделать массив numpy.array из нулей.

Сделаем способом, который помним!

In [27]:
x = 10
y = 3
zeros = []
for i in range(y):
    sub_zero = []
    for j in range(x):
        sub_zero.append(0)
    zeros.append(sub_zero)
zeros = np.array(zeros)
zeros
Out[27]:
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

jack-sparrow.jpg

Как сделать это нормально?

В стандартном Python:

In [28]:
x = 10
y = 3
zeros = [[0 for _ in range(x)] for _ in range(y)]
zeros
Out[28]:
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
In [29]:
[[0] * x] * y
Out[29]:
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
In [30]:
np.zeros(shape=(3, 10), dtype=int)
Out[30]:
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

Чтобы создавать простые массивы numpy.array, можно воспользоваться специальными функциями:

vis-numpy-3.jpg

Аналогично с многомерными массивами:

vis-numpy-11.jpg

Аналоги range, сразу возвращающие массив numpy.array:

In [31]:
np.arange(1, 10)
Out[31]:
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
In [32]:
np.arange(1, 10, 2)
Out[32]:
array([1, 3, 5, 7, 9])
In [33]:
np.arange(1, 10, 0.5)
Out[33]:
array([1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. , 5.5, 6. , 6.5, 7. ,
       7.5, 8. , 8.5, 9. , 9.5])
In [34]:
np.linspace(0, 1, 5, endpoint=True)
Out[34]:
array([0.  , 0.25, 0.5 , 0.75, 1.  ])

В чем разница?

Алгебраические операции

— Какие храбрые поступки вы совершали в своей жизни?

— Однажды на алгебре я руку поднял.

sci-calc.png

Базовая арифметика

In [35]:
data = np.array([[1, 2],
                 [3, 4],
                 [5, 6]], dtype=np.int8)

Перейдем в интерпретатор

А если складывать не с числом?

Как вы думаете, что произойдет, если попытаться сложить 2 массива?

vis-numpy-5.jpg

С другими операциями это тоже работает:

vis-numpy-6.jpg

А что получится с многомерными массивами?

Всё так же!

vis-numpy-12.jpg

Можно складывать и разные по размерностям массивы.

vis-numpy-13.jpg

In [36]:
data.shape
Out[36]:
(3, 2)
In [37]:
data + np.ones(2)
Out[37]:
array([[2., 3.],
       [4., 5.],
       [6., 7.]])
In [38]:
data + np.ones(3)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-38-59adb053f41f> in <module>
----> 1 data + np.ones(3)

ValueError: operands could not be broadcast together with shapes (3,2) (3,) 
In [39]:
data + np.ones(shape=(3, 1))
Out[39]:
array([[2., 3.],
       [4., 5.],
       [6., 7.]])

karina.jpg

Почему для 2D-массивов 1D-массив прибавляется по axis=1, но не прибавляется по axis=0?

На самом деле существуют специальное правило приведения размерностей:

  1. Предположим, что a.shape = (a_1, a_2, ..., a_n) и b.shape = (b_1, b_2, ..., b_n). Над a и b можно произвести поэлементую бинарную операцию, если $\forall \; i \in (1...n)$ выполнено хотя бы одно из условий:
    • a_i == b_i;
    • a_i == 1;
    • b_i == 1.
  1. Если размерности не совпадают, то к массиву меньшей размерности добавляются ведущие фиктивные размерности.

Документация: https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html

(из материалов Техносферы@Mail.Ru)

А как будет происходить умножение?

In [40]:
data1 = np.array([[1, 2],
                  [3, 4]])

data2 = np.array([[0, 10],
                  [20, -1]])
In [41]:
data1 * data2
Out[41]:
array([[ 0, 20],
       [60, -4]])

Но что делать, если нам нужно матричное умножение?

In [42]:
data = np.array([1, 2, 3])
In [43]:
powers_of_ten = (10 ** np.arange(6)).reshape(3, 2)
powers_of_ten
Out[43]:
array([[     1,     10],
       [   100,   1000],
       [ 10000, 100000]], dtype=int32)
In [44]:
data.dot(powers_of_ten)
Out[44]:
array([ 30201, 302010])

vis-numpy-14.jpg

Для тех, кто забыл, что такое матричное умножение:

vis-numpy-14.jpg

vis-numpy-15.jpg

А теперь перейдем от базовой арифметики к чуть более cложным функциям.

Подождите, это все была базовая арифметика?

In [45]:
data = np.array([[1, 2, 3],
                 [4, 5, 8]])
In [46]:
np.sqrt(data)
Out[46]:
array([[1.        , 1.41421356, 1.73205081],
       [2.        , 2.23606798, 2.82842712]])
In [47]:
np.exp(data)
Out[47]:
array([[2.71828183e+00, 7.38905610e+00, 2.00855369e+01],
       [5.45981500e+01, 1.48413159e+02, 2.98095799e+03]])
In [48]:
np.log(data)
Out[48]:
array([[0.        , 0.69314718, 1.09861229],
       [1.38629436, 1.60943791, 2.07944154]])
In [49]:
np.log2(data)
Out[49]:
array([[0.        , 1.        , 1.5849625 ],
       [2.        , 2.32192809, 3.        ]])

Агрегирующие операции

In [50]:
np.random.seed(777)
a = np.random.randint(0, 6, size=(8,))
a[3] = 10
a
Out[50]:
array([ 3,  1,  5, 10,  1,  2,  0,  2])
In [51]:
a.min(), a.max(), a.argmax(), a.sum(), a.prod(), a.mean()
Out[51]:
(0, 10, 3, 24, 0, 3.0)
In [52]:
np.min(a), np.max(a), np.argmax(a), np.sum(a), np.prod(a), np.mean(a)
Out[52]:
(0, 10, 3, 24, 0, 3.0)

vis-numpy-17.jpg

Старайтесь не использовать с массивами numpy.array нативные функции min, max и sum.

Какая у этого причина?

In [53]:
a = np.random.randint(-2, 8, size=(6,))
max(a), a
Out[53]:
(5, array([-2, -1,  0,  2,  3,  5]))
In [54]:
a = np.random.randint(-2, 8, size=(4, 3))
max(a), a
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-54-5c91eed52270> in <module>
      1 a = np.random.randint(-2, 8, size=(4, 3))
----> 2 max(a), a

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Почему агрегирующие операции?

Просто потому что они выполняют агрегацию (редукцию) по определенной оси!

Разберем, что делает numpy.array.???(axis=axis) – агрегирующая операция вдоль оси axis:

  • выполняет редукцию (агрегирующую операцию) по оси axis;
  • удаляет ось axis из исходного массива.

Что все это значит? Как это применять?

Разберем пример:

vis-numpy-18.jpg

In [55]:
data = np.array([[1, 2],
                 [5, 3],
                 [4, 6]], dtype=int)
In [56]:
data.max(axis=0)
Out[56]:
array([5, 6])
In [57]:
data.max(axis=1)
Out[57]:
array([2, 5, 6])
In [58]:
np.random.seed(777)

data = np.random.randint(0, 10, size=(3, 7))
data[1, 3] = 15

data
Out[58]:
array([[ 7,  6,  7,  1,  7,  4,  7],
       [ 9,  8,  7, 15,  0,  1,  2],
       [ 4,  5,  7,  1,  7,  2,  2]])
In [59]:
data.argmax()
Out[59]:
10

Логические операции

In [60]:
data = np.arange(6)
data
Out[60]:
array([0, 1, 2, 3, 4, 5])
In [61]:
data = data > 2
data
Out[61]:
array([False, False, False,  True,  True,  True])
In [62]:
data.any(), np.any(data), any(data)
Out[62]:
(True, True, True)
In [63]:
data.all(), np.all(data), all(data)
Out[63]:
(False, False, False)
In [64]:
~data
Out[64]:
array([ True,  True,  True, False, False, False])

Логические операции в многомерных массивах

In [65]:
data = np.arange(12).reshape(3, 4) >= 3
data
Out[65]:
array([[False, False, False,  True],
       [ True,  True,  True,  True],
       [ True,  True,  True,  True]])
In [66]:
data.all()
Out[66]:
False
In [67]:
data.all(axis=0), data.all(axis=1)
Out[67]:
(array([False, False, False,  True]), array([False,  True,  True]))
In [68]:
all(data)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-68-4eb86e975eae> in <module>
----> 1 all(data)

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Бинарные логические операции

In [69]:
a = np.array([1, 1, 0, 0, 1], dtype=bool)
b = np.array([1, 0, 0, 1, 0], dtype=bool)
In [70]:
a and b
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-70-61df3bd186ad> in <module>
----> 1 a and b

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
In [71]:
a & b
Out[71]:
array([ True, False, False, False, False])
In [72]:
a | b
Out[72]:
array([ True,  True, False,  True,  True])
In [73]:
a ^ b
Out[73]:
array([False,  True, False,  True,  True])

Другие операции с массивами numpy.array

Генерация случайных чисел

In [74]:
np.random.seed(777)
In [75]:
np.random.rand(10)
Out[75]:
array([0.15266373, 0.30235661, 0.06203641, 0.45986034, 0.83525338,
       0.92699705, 0.72698898, 0.76849622, 0.26920507, 0.64402929])
In [76]:
np.random.randint(0, 10, 10)
Out[76]:
array([1, 2, 4, 5, 7, 1, 7, 2, 2, 7])
In [77]:
np.random.permutation(10)
Out[77]:
array([1, 5, 0, 3, 9, 7, 2, 6, 8, 4])
In [78]:
np.random.choice(10, size=10)
Out[78]:
array([8, 3, 2, 0, 3, 3, 4, 0, 6, 5])

Сортировка массивов

In [79]:
np.random.seed(777)

data = np.random.randint(1, 20, 10)
data
Out[79]:
array([ 8, 16,  7, 18,  8,  8, 15,  8, 19, 14])
In [80]:
np.sort(data), data
Out[80]:
(array([ 7,  8,  8,  8,  8, 14, 15, 16, 18, 19]),
 array([ 8, 16,  7, 18,  8,  8, 15,  8, 19, 14]))
In [81]:
data.sort(), data
Out[81]:
(None, array([ 7,  8,  8,  8,  8, 14, 15, 16, 18, 19]))

Библиотека MPL

MPL (matplotlib)

Matplotlib -- одна из самых популярных библиотек для визуализации данных в Python.

In [82]:
import matplotlib.pyplot as plt

matplotlib.png

Разберем, как делать самую базовую визуализацию данных

In [83]:
a = np.array([1, 6, 3, 4, 3, 7, 2, 3, 2, 1, 10, 12, 0])
a
Out[83]:
array([ 1,  6,  3,  4,  3,  7,  2,  3,  2,  1, 10, 12,  0])
In [84]:
plt.plot(a)
Out[84]:
[<matplotlib.lines.Line2D at 0x1d4394bb148>]

На одном графике можно нарисовать несколько линий!

In [85]:
plt.plot(a + 3)
plt.plot(np.sqrt(a))
Out[85]:
[<matplotlib.lines.Line2D at 0x1d439d71ec8>]

Отлично! Попытаемся применить визуализацию к тому, что мы узнали!

In [86]:
x = np.linspace(-np.pi, np.pi, 100)
In [87]:
y = np.sin(x)
In [88]:
plt.plot(y)
Out[88]:
[<matplotlib.lines.Line2D at 0x1d439e2e688>]

Что-то не так: по оси X у нас неверные координаты. Кто виноват? Что делать?

In [89]:
plt.plot(x, y)
Out[89]:
[<matplotlib.lines.Line2D at 0x1d439e9d148>]

Если plt.plot передан один аргумент, то x принимается за индексы массива!

А если у нас точки неупорядоченные?

In [90]:
x = np.random.normal(size=100)
y = np.random.normal(size=100)
In [91]:
plt.plot(x, y)
Out[91]:
[<matplotlib.lines.Line2D at 0x1d439f0dc48>]

Что-то не то...

In [92]:
plt.plot(x, y, "o")
Out[92]:
[<matplotlib.lines.Line2D at 0x1d439f6bf88>]

Третий аргумент plt.plot имеет множество функций. Одна из них - выбрать стиль маркера для точек.

In [93]:
plt.plot(x, y, "r")
Out[93]:
[<matplotlib.lines.Line2D at 0x1d439fce588>]

А еще он может определять цвет...

In [94]:
plt.plot(x, y, "--")
Out[94]:
[<matplotlib.lines.Line2D at 0x1d43a02cb48>]

Стиль линии...

In [95]:
plt.plot(x, y, "gx")
Out[95]:
[<matplotlib.lines.Line2D at 0x1d43a095248>]

Или все вместе!

In [96]:
x = np.random.normal(size=100)
y = np.random.normal(size=100)
plt.plot(x, y, "rx")
x = np.random.normal(size=100)
y = np.random.normal(size=100)
plt.plot(x, y, "b+")
Out[96]:
[<matplotlib.lines.Line2D at 0x1d439fb4848>]

Также это можно задать параметрами:

In [97]:
plt.plot(x, y, marker="o", color="navy", linestyle="")
Out[97]:
[<matplotlib.lines.Line2D at 0x1d43a14cd08>]

Как обозначать подписи и добавлять оси?

In [98]:
x = np.linspace(-np.pi / 2, np.pi / 2, 361)
y = np.tan(x)
In [99]:
plt.plot(x, y)
Out[99]:
[<matplotlib.lines.Line2D at 0x1d43a1ae848>]

Обратите внимание на ось Y!

In [100]:
plt.plot(x, y)
plt.ylim(-10, 10)
Out[100]:
(-10, 10)
In [101]:
plt.plot(x, y)
plt.ylim(-10, 10)
plt.xlabel("X")
plt.ylabel("tan X")
plt.title("Tangent of X")
Out[101]:
Text(0.5, 1.0, 'Tangent of X')

Деления по осям тоже не очень красивые

In [102]:
plt.plot(x, y)
plt.ylim(-10, 10)

plt.xticks([-np.pi / 2, -np.pi / 4, 0, np.pi / 4, np.pi / 2],
           ["$-\pi/2$", "$-\pi/4$", "0", "$\pi/4$", "$\pi/2$"])
plt.yticks([-10, -5, -2, 0, 2, 5, 10])

plt.xlabel("X")
plt.ylabel("tan X")
plt.title("Тангенс икс")
Out[102]:
Text(0.5, 1.0, 'Тангенс икс')

Теперь сделаем саму линию толстого зеленого цвета и пунктирной толщины.

In [103]:
plt.plot(x, y, ls=":", lw=4, color="green")
plt.ylim(-10, 10)

plt.xticks([-np.pi / 2, -np.pi / 4, 0, np.pi / 4, np.pi / 2],
           ["$-\pi/2$", "$-\pi/4$", "0", "$\pi/4$", "$\pi/2$"])
plt.yticks([-10, -5, -2, 0, 2, 5, 10])

plt.xlabel("X")
plt.ylabel("tan X")
plt.title("Тангенс икс")
Out[103]:
Text(0.5, 1.0, 'Тангенс икс')

Графики разных типов в MPL все строятся примерно так же!

Вам обычно достаточно немного поменять функцию, и вы получите другой график!

Как строить визуализацию?

Основная проблема обычно заключается в том, как выбрать, какой тип графика строить для ваших данных.

  1. Тренд или функция:
    1. Одномерный тренд/функция -> line plot
    2. Двумерная функция -> heat map
  2. Сравнение:
    1. Доли с известным целым -> pie chart
    2. Остальное -> bar plot (тут много других графиков, которые мы не рассматриваем)
  3. Распределение, зависимость:
    1. Единственная переменная -> histogram
    2. Совместное распределение -> scatter plot, heat map (если слишком плотно)
    3. Независимые распределения -> box plot

Disclaimer: это очень упрощенная схема выбора графика, на самом деле графиков существует огромное множество, для ваших данных может подойти какой-то другой график.

Тренд (1D)

In [104]:
data = {"2016": 105, "2016": 117,
        "2017": 126, "2018": 132,
        "2019": 149, "2020": 130,
        "2021": 146}
x = list(data.keys())
y = list(data.values())
In [105]:
plt.plot(x, y, "kD-")
plt.xlabel("Год")
plt.ylabel("Продажи (млн. р.)")
plt.title("Тренд продаж компании X за 6 лет")
plt.show()
In [106]:
plt.plot(x, y, marker="D")
plt.ylim(0, 170)
plt.xlabel("Год")
plt.ylabel("Продажи (млн. р.)")
plt.title("Тренд продаж компании X за 6 лет")
plt.show()

2D-функция

In [107]:
harvest = np.array([[0.8, 2.4, 2.5, 3.9, 0.0, 4.0, 0.0],
                    [2.4, 0.0, 4.0, 1.0, 2.7, 0.0, 0.0],
                    [1.1, 2.4, 0.8, 4.3, 1.9, 4.4, 0.0],
                    [0.6, 0.0, 0.3, 0.0, 3.1, 0.0, 0.0],
                    [0.7, 1.7, 0.6, 2.6, 2.2, 6.2, 0.0],
                    [1.3, 1.2, 0.0, 0.0, 0.0, 3.2, 5.1],
                    [0.1, 2.0, 0.0, 1.4, 0.0, 1.9, 6.3]])
# taken from https://matplotlib.org/stable/gallery/images_contours_and_fields/image_annotated_heatmap.html
In [108]:
im = plt.imshow(harvest)
In [109]:
im = plt.imshow(harvest, cmap="summer")

Доли с известным целым

In [110]:
parts = {"Apple": 18, "Alphabet": 16,
         "Microsoft": 15, "Amazon": 13,
         "Facebook": 11}
x = list(parts.values())
text = list(parts.keys())
In [111]:
plt.pie(x, labels=text)
plt.show()

Это пример плохого графика! Круговые диаграммы в научной среде никто не любит и строить их не стоит! =)

Но если вы все-таки решили строить pie chart, то обязательно учитывайте полную долю!

In [112]:
others = 100 - sum(x)
parts.update(Others=others)
x = list(parts.values())
text = list(parts.keys())
In [113]:
plt.pie(x, labels=text, startangle=90, counterclock=False, colors=None)
plt.show()

Сравнение с помощью bar plot

In [114]:
parts = {"Apple": 18000, "Alphabet": 16300,
         "Microsoft": 13220, "Amazon": 12900,
         "Facebook": 11000}
x = list(parts.values())
text = list(parts.keys())
In [115]:
plt.bar(text, x)
Out[115]:
<BarContainer object of 5 artists>
In [116]:
plt.barh(text[::-1], x[::-1])
plt.xlim(10000, 20000)
plt.xticks([10000, 12500, 15000, 17500, 20000])
Out[116]:
([<matplotlib.axis.XTick at 0x1d43a55db48>,
  <matplotlib.axis.XTick at 0x1d43a55d188>,
  <matplotlib.axis.XTick at 0x1d43a55ad48>,
  <matplotlib.axis.XTick at 0x1d43a596a08>,
  <matplotlib.axis.XTick at 0x1d43a598108>],
 <a list of 5 Text xticklabel objects>)
In [117]:
plt.barh(text[::-1], x[::-1])
plt.xticks([0, 5000, 10000, 15000, 20000])
Out[117]:
([<matplotlib.axis.XTick at 0x1d43a5c0088>,
  <matplotlib.axis.XTick at 0x1d43a5bd7c8>,
  <matplotlib.axis.XTick at 0x1d43a5bd388>,
  <matplotlib.axis.XTick at 0x1d43a5f75c8>,
  <matplotlib.axis.XTick at 0x1d43a5f7d88>],
 <a list of 5 Text xticklabel objects>)

Распределение одной переменной

In [118]:
rvs = np.random.normal(size=1000)
In [119]:
plt.hist(rvs)
plt.show()
In [120]:
from scipy import stats

kde = stats.gaussian_kde(rvs)

plt.hist(rvs, bins=30, density=True)
x_min, x_max = plt.xlim()
x_kde = np.linspace(x_min, x_max, 100)
plt.plot(x_kde, kde(x_kde), color="k")
# In `seaborn` this is automatic! Use seaborn =D
plt.show()

Совместное распределение двух переменных

In [121]:
x = np.random.normal(0, 1, 100)
y = (x + np.random.normal(0, 1, 100)) / 2
In [122]:
plt.scatter(x, y, color="k", marker="x")
Out[122]:
<matplotlib.collections.PathCollection at 0x1d43b5a8488>
In [123]:
m, b = np.polyfit(x, y, 1)  # Regression
x0, x1 = x.min(), x.max()
y0, y1 = m * x0 + b, m * x1 + b
plt.scatter(x, y, color="grey", marker="x")
plt.plot([x0, x1], [y0, y1], color="black", ls="--")
print(f"y={m:.2f}x{b:+.2f}")
y=0.53x+0.00
In [124]:
x = np.random.normal(0, 1, 10000)
y = np.random.normal(0, 1, 10000)
In [125]:
plt.scatter(x, y)
Out[125]:
<matplotlib.collections.PathCollection at 0x1d43b68fec8>
In [126]:
plt.scatter(x, y, marker=".", alpha=0.1)
Out[126]:
<matplotlib.collections.PathCollection at 0x1d43b6ffc48>

Независимые (условно) распределения

In [127]:
a = np.random.normal(0, size=50)
b = np.random.normal(1.2, size=190)
c = np.random.normal(0.7, 2, size=101)
d = np.random.normal(-1, 0.2, size=120)
In [128]:
plt.boxplot([a, b, c, d])
plt.show()
In [129]:
plt.boxplot([a, b, c, d],
            vert=False,
            labels=["Alpha", "Beta", "Gamma", "Delta"])
plt.axvline(0, ls="--", lw=1, color="k")
plt.show()

На этом всё!

Полную документацию NumPy смотрите на сайте: https://docs.scipy.org/doc/numpy

Полную документацию MPL смотрите на сайте: https://matplotlib.org/stable/contents.html

В NumPy и MPL есть еще множество потенциально полезных для вас функций, так что не поленитесь зайти и посмотреть :^)

folks.gif