Введение#
Где и как применяются численные методы#
Любое моделирование
• Интерполяция
• Численное решение дифференциальных уравнений
• Теория погрешностей
• Умение составлять численный алгоритм для математической задачи
• …
Анализ реальных данных
• Регрессия (аппроксимация)
• Оптимизация (поиск минимумов, максимумов)
• Случайные процессы
• Численное интегрирование
• …
Современные алгоритмы (прим. нейронные сети)
Статистика
Параллельное программирование
Оптимизация
…
Как быстро по~д~нять Python?#
На случай, если вы сомневаетесь в своих силах, крайне рекоммендую потратить часов 5 на освоение базового курса Python на pythontutor.ru.
Постарайтесь прорешать как можно больше задач и закрепить синтаксис.
Крайне желательно установить себе jupyter notebook на ноутбук, но можно использовать онлайн редакторы (google colab и др.)
https://colab.research.google.com/notebooks/intro.ipynb
Чтобы там работать, нужно перейти по ссылке, дать разрешение на доступ к своему гугл-диску, ввести код:
from google.colab import drive
drive.mount(„/content/drive/“)
После этого войти с помощью гугл-аккаунта, появится код доступа, его надо ввести в появившуюся строку ввода
Если всё сделать правильно, то появится сообщение «Mounted at /content/drive/»
В Питоне есть огромное количество библиотек для анализа данных (описание некоторых ниже) с очень хорошей документацией.
NumPy — библиотека для работы с массивами и матрицами, в том числе матричные операции.
SciPy — библиотека для выполнения научных и инженерных расчётов.
ScikitLearn (sklearn) — библиотека алгоритмов машинного обучения с множеством примеров и наборами данных.
Matplotlib — библиотека для визуализации данных.
SymPy - библиотека для символьных вычислений.
Желающие могут изучить популярный пакет Pandas для работы с табличными данными, но в нашем курсе он не понадобится.
Numpy, Matplotlib - наше всё#
В курсе будут использоваться некоторые важные библиотеки, без которых жить ну совсем тяжело. Они упростят все аспекты решений задач и позволят визуализировать результат.
В целом, использование сторонних библиотек поощрается при выполнении ДЗ, если не оговорено иное.
Numpy#
import numpy as np
основная библиотека для операций с массивами числовых данных, матрицами и объектами с большим количеством индексов
быстрые матричные операции
np_array = np.array([1, 2, 3, 4]) # Основной объект: numpy array (одинаковый тип чисел на весь массив)
np_array
array([1, 2, 3, 4])
np_array = np.array([1, 2, 3, 4.]) # Чем отличается от предыдущего?
np_array
array([1., 2., 3., 4.])
np_array.shape # Размерность массива
(4,)
np_array = np_array.reshape((2, 2)) # изменим размерность массива
np_array.shape
(2, 2)
np_array
array([[1., 2.],
[3., 4.]])
np_array = np_array.reshape((1, -1)) # Превратим матрицу обратно в строку
np_array
array([[1., 2., 3., 4.]])
np_array = np_array.reshape((-1, 1)) # Или столбец
np_array
array([[1.],
[2.],
[3.],
[4.]])
Удобное создание массивов#
# np.arange(a, b, s) - выводит одномерный массив чисел начиная с a (включительно) до b (невключительно) с шагом s
np.arange(1, 10, 0.2)
array([1. , 1.2, 1.4, 1.6, 1.8, 2. , 2.2, 2.4, 2.6, 2.8, 3. , 3.2, 3.4,
3.6, 3.8, 4. , 4.2, 4.4, 4.6, 4.8, 5. , 5.2, 5.4, 5.6, 5.8, 6. ,
6.2, 6.4, 6.6, 6.8, 7. , 7.2, 7.4, 7.6, 7.8, 8. , 8.2, 8.4, 8.6,
8.8, 9. , 9.2, 9.4, 9.6, 9.8])
# np.linspace(a, b, N) - равно делит [a, b] на N-1 часть и выводит массив с N граничными точками
np.linspace(1, 2, 10)
array([1. , 1.11111111, 1.22222222, 1.33333333, 1.44444444,
1.55555556, 1.66666667, 1.77777778, 1.88888889, 2. ])
# np.logspace(a, b, base) - то же самое, что и linspace, но делит на
print(np.logspace(1, 2, 5))
[ 10. 17.7827941 31.6227766 56.23413252 100. ]
np.ones((5,2))
array([[1., 1.],
[1., 1.],
[1., 1.],
[1., 1.],
[1., 1.]])
np.zeros((2, 3))
array([[0., 0., 0.],
[0., 0., 0.]])
np.eye(3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
Случайные массивы#
np.random.rand(2, 3) # Равномерное распределение на [0, 1]
array([[0.58349704, 0.03717281, 0.49240429],
[0.38980893, 0.15188871, 0.45001384]])
np.random.normal(4, 5, size=(4, 5)) # Гауссово распределение
array([[ 4.12365561, -3.03305192, -12.15134102, 7.83903711,
3.15015423],
[ -5.27771412, 6.0569352 , 5.53217522, 4.44533889,
15.98563729],
[ 5.51015709, 8.49372852, 2.59555899, 5.26353021,
8.67348281],
[ -8.51103734, 7.98617451, -1.32595877, 6.56653338,
8.50131234]])
Индексация и взятие среза#
a = np.arange(27).reshape(3, 9)
a
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8],
[ 9, 10, 11, 12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23, 24, 25, 26]])
# В качестве срезов можно извлекать как столбцы так и строки
print(a[:, 0], a[:, 0].shape) # Извлекаем столбец, равносильно a[0:3, 0]
[ 0 9 18] (3,)
a[1:3, 2] # Можно извлечь часть столбца
array([11, 20])
a[0:2, 3:7] # Срез из строк и срез каждой строки
array([[ 3, 4, 5, 6],
[12, 13, 14, 15]])
a[0, 1] # Или просто обратиться к элементу
1
Помним про специфику копирования массивов в питоне#
A = np.array([1, 2, 3, 4])
B = A
print(A, B)
B[0] = -100
print(A, B)
[1 2 3 4] [1 2 3 4]
[-100 2 3 4] [-100 2 3 4]
A = np.array([1, 2, 3, 4])
B = A.copy()
print(A, B)
B[0] = -100
print(A, B)
[1 2 3 4] [1 2 3 4]
[1 2 3 4] [-100 2 3 4]
Обычные операции с матрицами выполняются поэлементно!#
C = A**2
print(A, C)
[1 2 3 4] [ 1 4 9 16]
np.sin(A)
array([ 0.84147098, 0.90929743, 0.14112001, -0.7568025 ])
A = A.reshape((2, 2))
A
array([[1, 2],
[3, 4]])
A > 2 # Создание масок
array([[False, False],
[ True, True]])
A[A > 2] = 0 # Маски могут выполнять роль индексов
A
array([[1, 2],
[0, 0]])
np.array([1, 2, 3]) / np.array([1, 2, 1])
array([1., 1., 3.])
Матричные операции#
np.dot([1, 2, 3], [1, 0, 1]) # Скалярное произведение
4
print(np_array, np_array.T) # Транспонирование
[[1.]
[2.]
[3.]
[4.]] [[1. 2. 3. 4.]]
print(np.array([1, 0]))
print("@")
print(A)
print("-----------")
np.array([1, 0]) @ A # Матричное умножение
[1 0]
@
[[1 2]
[0 0]]
-----------
array([1, 2])
A = np.array([[1, 1, 1], [1, 1, 1]])
B = np.array([[2, 2, 2], [2, 2, 2]])
print(A, "\n\n", B)
np.concatenate((A, B), axis=0) # Конкатенация массивов
[[1 1 1]
[1 1 1]]
[[2 2 2]
[2 2 2]]
array([[1, 1, 1],
[1, 1, 1],
[2, 2, 2],
[2, 2, 2]])
np.concatenate((A, B), axis=1)
array([[1, 1, 1, 2, 2, 2],
[1, 1, 1, 2, 2, 2]])
np.concatenate((B, A), axis=1)
array([[2, 2, 2, 1, 1, 1],
[2, 2, 2, 1, 1, 1]])
Матричные операции оптимизированы и выполняются гораздо быстрее, чем питоновские циклы
При выполении математических операций с numpy массивами никогда не следует пользоваться питоновскими циклами и другими операциями, которые работают поэлементно. Если вам кажется, что это невозможно, то с высокой вероятностью вы не правы
Однако в некоторых случаях это действительно невозможно. Тогда используют особые средства ускорения циклов, которые основаны на том, чтобы в Python использовать типы данных из C, компиллировать функции Python. Позже в этом семестре мы их тоже будем изучать.
long_array = np.random.normal(size=(10000 * 1000))
%%time
result = long_array * long_array
CPU times: user 46.9 ms, sys: 0 ns, total: 46.9 ms
Wall time: 62.6 ms
%%time
result = [x * y for x, y in zip(long_array, long_array)]
CPU times: user 844 ms, sys: 266 ms, total: 1.11 s
Wall time: 1.31 s
Собственные числа и вектора матрицы#
np.linalg.eig(
np.array([[1, 2, 3], [1, 0, 1], [4, -5, 2]])
)
(array([ 4.30277564, -2. , 0.69722436]),
array([[-7.35289262e-01, -7.07106781e-01, -7.61041891e-01],
[-3.10857367e-01, 1.03725802e-16, -5.01677599e-01],
[-6.02260242e-01, 7.07106781e-01, 4.11260047e-01]]))
И так далее#
Если вам потребовалась какая-то операция над матрицами или другими массивами, то с высокой вероятностью она уже реализована в numpy.
Если вам потребовалось какое-то хитрое взятие индексов у объекта numpy, скорее всего, есть элегантный способ сделать это без привлечения функций или с минимальным количеством операций numpy
См. np.mean
, np.std
, np.unique
, np.where
, np.repeat
, np.unravel_index
итд.
Также к блокноту прилагается шпаргалка с основными функциями numpy.
Matplotlib#
Библиотека для отрисовки всевозможных графиков (и анимаций)
import matplotlib.pyplot as plt
# Обычный график
xs = np.linspace(0, 6, 50)
sin_ys = np.sin(xs)
cos_ys = np.cos(xs)
plt.plot(xs, sin_ys)
plt.plot(xs, cos_ys)
[<matplotlib.lines.Line2D at 0x7fa8cee88430>]
# C наворотами
plt.figure(figsize=(5,5))
plt.title('Cosine and sine graph')
plt.plot(xs, sin_ys, label='sin x')
plt.fill_between(xs, sin_ys - 0.1, sin_ys + 0.1, alpha=0.5)
plt.plot(xs, cos_ys, '--', c='green', label='cos x')
plt.xlim(0, 5)
plt.ylim(-1, 0.9)
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
# Отображение точек на графике
xs = np.linspace(0, 0.7, 30)
ys = xs**2 - 0.5 * xs
ys_shifted = ys + np.random.normal(scale=0.01, size=xs.shape)
plt.scatter(xs, ys_shifted, c='r')
plt.plot(xs, ys)
plt.show()
# Гистограмма
np_array = np.random.normal(size=1000 * 1000)
plt.hist(np_array, bins=100)
plt.show()
# После некоторой практики можно и выпендриваться (скопируйте этот код в свой блокнот для запуска)
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from ipywidgets import interact
import matplotlib
# Функции для координат x, y и z в зависимости от t
def x_func(t):
return np.cos(t)
def y_func(t):
return np.sin(t)
def z_func(t):
return t
# Функция для рисования 3D графика с цветными сегментами
def plot_colored_spiral(azimuth, elevation):
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
t = np.linspace(0, 10, 100)
colors = ["red", "orange", "yellow", "green", "blue", "purple"] # Генерация цветов радуги
segment_length = len(t) // 6
for i in range(6):
start_idx = i * segment_length
end_idx = (i + 1) * segment_length
color_segment = colors[i]
ax.plot(x_func(t[start_idx:end_idx]),
y_func(t[start_idx:end_idx]),
z_func(t[start_idx:end_idx]),
color=color_segment, lw=5)
ax.view_init(elev=elevation, azim=azimuth)
plt.show()
# Создание интерактивных ползунков
interact(plot_colored_spiral, azimuth=(0, 360), elevation=(-90, 90))
<function __main__.plot_colored_spiral(azimuth, elevation)>
plotly#
Для интерактивных виджетов желательно использовать библиотеку plotly
- она сохраняет все состояния виджета при выполнении, тем самым устраняя проблемы подвисания. Питон всё же медленный. Удобнее написать рабочий прототип с ipywidgets
и перевести на plotly
используя какой-нибудь чат бот.
import numpy as np
import plotly.graph_objects as go
# Функции для координат x, y и z в зависимости от t
def x_func(t):
return np.cos(t)
def y_func(t):
return np.sin(t)
def z_func(t):
return t
# Функция для рисования 3D графика с цветными сегментами
def plot_colored_spiral(azimuth, elevation):
fig = go.Figure()
t = np.linspace(0, 10, 100)
colors = ["red", "orange", "yellow", "green", "blue", "purple"] # Генерация цветов радуги
segment_length = len(t) // 6
for i in range(6):
start_idx = i * segment_length
end_idx = (i + 1) * segment_length
color_segment = colors[i]
fig.add_trace(go.Scatter3d(
x=x_func(t[start_idx:end_idx]),
y=y_func(t[start_idx:end_idx]),
z=z_func(t[start_idx:end_idx]),
mode='lines',
line=dict(color=color_segment, width=5),
showlegend=False
))
fig.update_layout(scene=dict(
xaxis=dict(title='X'),
yaxis=dict(title='Y'),
zaxis=dict(title='Z')
))
fig.update_layout(scene_camera=dict(eye=dict(x=-1.25, y=-1.25, z=1.25),
center=dict(x=0, y=0, z=0),
up=dict(x=0, y=0, z=1),
projection=dict(type='perspective')),
scene=dict(aspectmode='cube'))
# Установка размеров канваса
fig.update_layout(width=600, height=600)
fig.show(width=600, height=600) # Размещение по центру
# Создание интерактивных виджетов
plot_colored_spiral(azimuth=180, elevation=30) # Начальное значение