NumPy, pandas и SciPy

Массивы, таблицы и численные методы для данных эксперимента: устройство ndarray, индексация, типы, группировка, временные ряды, интегралы, уравнения и подгонка кривых

Вячеслав Федоров

Лекция 10

Разработка и применение ПО

в физических исследованиях

np

Содержание

От массива чисел до таблиц, временных рядов и численных методов

01

Массив NumPy

02

Индексы и векторы

03

Типы и файлы

04

Таблицы pandas

05

Группы и время

06

Численные методы

Цель лекции

Обрабатывать данные эксперимента операциями над целыми массивами и таблицами и готовыми численными методами, без циклов Python

Сигналы, поля и ансамбли частиц хранятся в массивах NumPy, журналы приборов, каталоги и результаты серий измерений — в таблицах pandas, а интегралы, уравнения движения и подгонку моделей вычисляет SciPy. Цикл по элементам выполняет скомпилированный код. Задача разработчика — записать расчёт как операцию над массивом или вызов готового метода и проверить результат прямым вычислением или точным решением.

Научный

стек Python

Обработка и анализ данных эксперимента

pandas

таблицы

SciPy

численные методы

Matplotlib

графики

scikit-learn

машинное обучение

NumPy: ndarray — числа одного типа подряд в памяти и операции над ними на C

Пояснение

Массив ndarray — общий формат данных: SciPy, Matplotlib и scikit-learn принимают и возвращают массивы NumPy, столбец pandas хранит данные в массиве.

Для физика

Курс: NumPy, pandas и SciPy — эта лекция, графики — следующая, машинное обучение — глава книги «Машинное обучение».

Массив NumPy

Список и массив, устройство ndarray, создание массивов

01

Массив NumPy

Индексы и векторы

Типы и файлы

Таблицы pandas

Группы и время

Численные методы

Список

и массив

list: ссылки на объекты в куче

8 Б

8 Б

8 Б

8 Б

8 Б

24 Б

24 Б

24 Б

24 Б

24 Б

объекты float, по 24 байта каждый

ndarray float64: числа подряд в одном буфере

1.0

2.0

3.0

4.0

5.0

8 байт на число, без заголовков объектов

listndarray
хранениессылки на объектычисла подряд
миллион float32,4 МБ8 МБ
тип элементовлюбой у каждогоодин на массив
циклинтерпретаторскомпилированный

Пояснение

Размер массива задаётся при создании, тип элементов один на весь массив, операции записываются над массивом целиком.

Устройство

ndarray

m: форма (3, 4)

0.

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

строка → +32 байта

столбец → +8 байт

m.T: шаги (8, 32)

буфер: 12 чисел float64, 96 байт подряд

0.

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

адрес m[i, j] = начало + 32·i + 8·j

АтрибутЗначение у m
dtypefloat64
shape(3, 4)
ndim2
strides(32, 8)
itemsize8
nbytes96

Пояснение

Транспонирование и срезы создают представление: новый заголовок над тем же буфером; reshape — тоже, если позволяют шаги, иначе копирует данные.

Создание

массивов

np.array([1, 2, 3], dtype=np.float32)
np.zeros((3, 4)), np.ones(5), np.full(3, 7.0)
np.empty(1000)          # память не заполняется
np.eye(3), np.diag([1, 2, 3])
np.arange(0, 1, 0.25)   # задан шаг
np.linspace(0, 1, 5)    # задано число точек
np.logspace(0, 3, 4)    # 1, 10, 100, 1000
 
rng = np.random.default_rng(42)
rng.normal(0.0, 1.0, size=(1000, 3))
 
m.reshape(2, 6), m.ravel(), m.copy()

Пояснение

Для дробного шага число точек arange зависит от округления; когда известно число точек, применяется linspace.

Пояснение

Случайные числа — генератор default_rng с явным зерном: расчёт воспроизводится. np.random.rand и np.random.seed — устаревший интерфейс.

Важно

np.empty не обнуляет память: в массиве остаются прежние значения.

Демонстрация:

устройство массива

01

Миллион чисел списком: размер списка и объектов

02

Тот же миллион массивом: nbytes, dtype, itemsize

03

Матрица 3×4: форма и шаги

04

Транспонирование: шаги и общая память

05

Непрерывность транспонированного массива

Что наблюдается

Список занимает 32,4 МБ, массив — 8 МБ. После транспонирования шаги (32, 8) становятся (8, 32), память общая, данные не скопированы.

root@lab — запись со стенда

Индексы и векторы

Срезы и представления, маски, оси, broadcasting, линейная алгебра

02

Массив NumPy

Индексы и векторы

Типы и файлы

Таблицы pandas

Группы и время

Численные методы

Индексация

и срезы

a = np.arange(24).reshape(4, 6)

выделено a[1:3, ::2]

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

Важно

a[i][j] создаёт промежуточную строку; в NumPy пишут a[i, j].

a[1, 2]          # элемент: 8
a[1]             # строка, форма (6,)
a[:, 0]          # столбец, форма (4,)
a[1:3, ::2]      # форма (2, 3)
a[::-1]          # строки в обратном порядке
a[..., 0]        # то же, что a[:, 0]
a[:, None]       # новая ось: (4, 1, 6)

Пояснение

Срез — представление: запись в срез меняет исходный массив.

Маски

и списки индексов

x = np.arange(10)
mask = x > 5               # массив bool
x[mask]                    # [6 7 8 9]
x[(x % 2 == 0) & (x > 5)]  # [6 8]
x[[0, 2, 4]]               # [0 2 4]
np.where(x > 5, x, 0)      # замена без цикла
x[x > 5] = 0               # запись в x

ОперацияРезультат
срез x[2:5]представление
маска x[x > 5]копия
список x[[0, 2]]копия
x[маска] = …запись в x

Важно

and, or и not к массивам не применяются: условия соединяют операторами &, |, ~ и заключают в скобки.

Демонстрация:

срезы и копии

01

Срез и запись в него

02

Выборка по маске и изменение выбранного

03

Присваивание по маске

04

Общая память: срез с шагом и список индексов

Что наблюдается

Запись в срез обнулила элементы x; изменение выборки по маске x не затронуло; x[x > 5] *= 2 изменило x. Срез с шагом делит память с x, список индексов — нет.

root@lab — запись со стенда

Векторные

операции и оси

Выражение для data формы (1000, 3)Форма результата
data.mean()() — одно число
data.mean(axis=0)(3,) — по каналам
data.mean(axis=1)(1000,) — по измерениям
data.mean(axis=0, keepdims=True)(1, 3)
data.cumsum(axis=0)(1000, 3)

Для физика

Строки — измерения, столбцы — каналы: axis=0 сворачивает измерения и даёт по числу на канал.

np.sqrt(x), np.exp(-x**2)
x * y + 1
np.maximum(x, 0)
np.sin(2 * np.pi * f * t)
 
x.sum(), x.min(), x.argmax()
x.std(ddof=1)   # выборочное

Пояснение

Универсальная функция (ufunc) применяется к каждому элементу в скомпилированном цикле.

Демонстрация:

оси и агрегирование

01

Генератор случайных чисел с зерном 42

02

Тысяча измерений трёх каналов: средние 1, 5 и −2, шум 0,1

03

Средние и отклонения по каналам

04

Среднее по строкам: форма результата

05

Хвост распределения и гистограмма первого канала

Что наблюдается

Средние 0,999, 4,997 и −2,004 и отклонения около 0,1 воспроизводят параметры генератора; 25 значений первого канала больше 1,2.

root@lab — запись со стенда

Broadcasting

01

С последней оси

формы операндов сравниваются справа налево

02

Равны или 1

ось длины 1 растягивается до длины другого операнда

03

Недостающие оси

слева дописываются оси длины 1

d = r[:, None, :] - r[None, :, :]   # (N, N, 3)
dist = np.sqrt((d**2).sum(axis=-1)) # (N, N)

ОперандыРезультат
(4, 3) и (3,)(4, 3)
(4, 1) и (3,)(4, 3)
(N, 1, 3) и (1, N, 3)(N, N, 3)
(4, 3) и (4,)ошибка

Важно

Операнды не копируются, но результат занимает полную форму: (N, N, 3) из float64 при N = 10 000 — 2,2 ГиБ.

Демонстрация:

попарные расстояния

01

Тысяча частиц со случайными координатами

02

Попарные расстояния двумя циклами Python по спискам

03

Те же расстояния через broadcasting

04

Через матричное произведение r @ r.T

05

Сверка результатов

Что наблюдается

Циклы — 107,6 мс, broadcasting — 13,1 мс, в 8 раз быстрее; r @ r.T — 2,5 мс, в 43 раза, но с расхождением 3e-8. Массив d занимает 22,9 МиБ.

root@lab — запись со стенда

Линейная

алгебра

ЗадачаФункция
матричное произведениеA @ B, np.matmul
система A x = bnp.linalg.solve(A, b)
собственные значенияnp.linalg.eigh, eig
SVD, ранг, нормаnp.linalg.svd, matrix_rank, norm
спектр сигналаnp.fft.rfft, rfftfreq
свёртка по индексамnp.einsum('ij,jk->ik', A, B)

Важно

Систему решают solve, а не inv(A) @ b: быстрее и точнее.

Для физика

Матрица перехода через магнитную структуру — произведение матриц элементов: M = Mn @ … @ M1.

Пояснение

Интегрирование, оптимизация и подгонка кривых — в SciPy, шестая часть лекции.

Типы и файлы

Типы элементов, переполнение и точность, NaN, чтение и запись массивов

03

Массив NumPy

Индексы и векторы

Типы и файлы

Таблицы pandas

Группы и время

Численные методы

Типы

элементов

dtypeБайтДиапазон или точность
bool1True, False
int8, uint81−128…127, 0…255
int324±2,1 млрд
int648±9,2e18
float324около 7 значащих цифр
float648около 16 значащих цифр
complex12816пара float64
<U1040строка до 10 символов
object8ссылка на объект Python

Пояснение

По умолчанию целые — int64, вещественные — float64; тип задаётся аргументом dtype или методом astype.

Пояснение

NumPy 2: тип результата не зависит от значения числа Python — uint8 + 100 остаётся uint8, uint8 + 300 — ошибка.

Важно

Смешение строк и чисел даёт массив строк: np.array([1, 2.5, '3']) имеет тип <U32.

Переполнение

и точность

>>> np.array([1, 2, 70000], dtype=np.uint16)
OverflowError: Python integer 70000
out of bounds for uint16
>>> np.array([1, 2, 70000]).astype(np.uint16)
array([   1,    2, 4464], dtype=uint16)
>>> np.array([200, 250], dtype=np.uint8) + 100
array([44, 94], dtype=uint8)
>>> np.float32(16777216) + np.float32(1)
np.float32(1.6777216e+07)

01

Конструктор

с NumPy 2.0 отвергает число вне диапазона типа

02

astype и арифметика

переполняются без сообщений: остаток по модулю 2^16 и 2^8

03

float32

24 двоичных разряда мантиссы: 2^24 + 1 не представимо

Для физика

Счётчик событий в uint16 или время t += dt во float32 дают ошибку без единого сообщения.

Демонстрация:

типы и переполнение

01

Число 70000 в uint16: конструктор и astype

02

Сложение в uint8

03

Предел точности float32

04

arange с дробным шагом и linspace

05

NaN: сравнение и среднее

Что наблюдается

70000 → ошибка или 4464; 200 + 100 в uint8 = 44. 2^24 + 1 во float32 = 2^24. arange(0.5, 0.8, 0.1) даёт 4 точки вместо 3. nan не равен себе, nanmean пропускает его.

root@lab — запись со стенда

Чтение

и запись

ФорматФункцииОсобенности
.npynp.save, np.loadдвоичный, тип и форма в заголовке
.npznp.savez, savez_compressedнесколько массивов в архиве
текстsavetxt, loadtxt, genfromtxtчитается в редакторе, втрое больше
HDF5, Parqueth5py, pandasбольшие наборы, частичное чтение

Пояснение

np.load(..., mmap_mode='r') отображает файл в память: читаются только нужные части.

Важно

loadtxt требует полных строк; genfromtxt заменяет пропуски на nan.

Демонстрация:

текст и двоичный формат

01

Миллион чисел в текст и в .npy: размеры

02

Время чтения: loadtxt и load

03

Текстовый журнал с пропусками

04

loadtxt и genfromtxt на пропусках

Что наблюдается

Текст — 24,3 МиБ, .npy — 7,6 МиБ; loadtxt — 139 мс, load — 0,7 мс. На пропуске loadtxt останавливается с ValueError, genfromtxt подставляет nan.

root@lab — запись со стенда

Таблицы pandas

Series и DataFrame, чтение и осмотр, отбор строк и столбцов, копирование при записи

04

Массив NumPy

Индексы и векторы

Типы и файлы

Таблицы pandas

Группы и время

Численные методы

Series

и DataFrame

df.head(4): индекс слева, у каждого столбца свой тип

0

1

2

3

Survived

0

1

1

1

int64

Pclass

3

1

3

1

int64

Sex

male

female

female

female

str

Age

22.0

38.0

26.0

35.0

float64

Fare

7.2500

71.2833

7.9250

53.1000

float64

df['Age'] — Series: значения столбца и тот же индекс

Пояснение

Series — одномерный массив с индексом; DataFrame — столбцы-Series с общим индексом.

Пояснение

Столбец хранится массивом NumPy или Arrow, поэтому операции над столбцом векторные.

Важно

pandas 3.0: строки по умолчанию имеют тип str, копирование при записи включено всегда.

Чтение

и осмотр таблицы

import pandas as pd
 
df = pd.read_csv("titanic.csv")
df.shape       # (891, 12)
df.head(3)     # первые строки
df.info()      # типы и число непустых
df.describe()  # сводка по числовым
df["Pclass"].value_counts()
df.isna().sum()   # пропуски

ИсточникФункция
CSV, TSVread_csv(sep=…)
Excelread_excel
Parquetread_parquet
HDF5read_hdf
SQLread_sql
JSONread_json

Пояснение

Аргументы read_csv usecols, dtype, parse_dates, na_values и nrows позволяют читать только нужное и сразу с верными типами.

Демонстрация:

осмотр таблицы

01

Чтение titanic.csv и размер таблицы

02

Первые строки пяти столбцов

03

info: типы и число непустых

04

Сводка по возрасту

Что наблюдается

891 строка и 12 столбцов, строки — тип str. Возраст известен у 714 пассажиров, каюта — у 204, порт — у 889; средний возраст 29,7 года.

root@lab — запись со стенда

Отбор

строк и столбцов

df["Age"]                 # Series
df[["Age", "Fare"]]       # DataFrame
df.loc[78, "Name"]        # по метке
df.iloc[0, 3]             # по номеру
df[(df["Sex"] == "female") & (df["Age"] > 30)]
df.query("Pclass == 1 and Age < 18")
df.sort_values("Age").loc[78]  # метка

ИндексируетПравая граница среза
locметки индекса и именавключается
ilocномера позиций с нуляне включается

Важно

После сортировки или фильтрации метки строк не совпадают с номерами: loc[78] и iloc[78] — разные строки.

Копирование

при записи

# цепочка присваиваний: df не меняется
df[df["Age"] > 60]["Fare"] = 0
 
# одна операция над df: df меняется
df.loc[df["Age"] > 60, "Fare"] = 0
 
sub = df[df["Pclass"] == 1]   # копия
sub["Fare"] = sub["Fare"] * 2  # df прежний

01

Результат индексации

в pandas 3.0 любой ведёт себя как копия

02

Изменение таблицы

только операцией над ней самой: df.loc[маска, столбец] = …

03

Копия по требованию

столбец и срез делят данные с таблицей до первой записи

Пояснение

Цепочку присваиваний pandas 3.0 отмечает предупреждением ChainedAssignmentError; SettingWithCopyWarning удалён.

Демонстрация:

отбор и запись

01

Строка по метке: loc

02

Сортировка: метки и номера строк

03

Отбор по условию и query

04

Цепочка присваиваний

05

Присваивание через loc

Что наблюдается

После сортировки loc[78] — возраст 0,83, iloc[78] — 15. Цепочка присваиваний вызвала ChainedAssignmentError и не изменила df; присваивание через loc обнулило 22 значения.

root@lab — запись со стенда

Группы и время

Группировка, объединение и пропуски, временные ряды

05

Массив NumPy

Индексы и векторы

Типы и файлы

Таблицы pandas

Группы и время

Численные методы

Группировка:

split–apply–combine

разбиение

свёртка

df

891 строка

Pclass 1

216 строк

Pclass 2

184 строки

Pclass 3

491 строка

0,630

mean(Survived)

0,473

mean(Survived)

0,242

mean(Survived)

объединение: Series с индексом Pclass

df.groupby("Pclass")["Survived"].mean()
g = df.groupby(["Sex", "Pclass"])
g["Survived"].agg(["mean", "size"])
df.pivot_table(values="Survived",
               index="Sex", columns="Pclass")
pd.cut(df["Age"], [0, 12, 18, 40, 80])
df.groupby("Pclass")["Age"].transform("median")

Пояснение

size считает строки группы, count — непустые значения столбца.

Важно

apply с axis=1 — цикл Python по строкам: сначала ищется векторная операция.

Демонстрация:

группировка

01

Доля выживших по классам

02

Сводная таблица: пол и класс

03

Возрастные группы через pd.cut

04

Заполнение возраста медианой класса

Что наблюдается

Выжили 63, 47 и 24 % пассажиров трёх классов; женщины первого класса — 97 %, мужчины третьего — 14 %. transform заполнил все 177 пропусков возраста.

root@lab — запись со стенда

Объединение

и пропуски

m = df.merge(ports, on="Embarked", how="left",
             validate="m:1", indicator=True)
pd.concat([run1, run2], ignore_index=True)
 
df.isna().sum()             # пропуски по столбцам
df.dropna(subset=["Age"])   # строки без пропуска
df["Embarked"].fillna("S")  # подстановка значения
s.ffill(), s.interpolate()  # по соседним точкам

howРезультат
innerстроки с ключом в обеих таблицах
leftвсе строки левой, NaN без пары
rightвсе строки правой
outerвсе строки обеих

Важно

Сводки пропускают NaN: средний возраст считается по 714 пассажирам из 891.

Пояснение

Пропуск: NaN в числах и строках, pd.NA в Int64 и boolean, NaT в датах.

Временные

ряды

log = pd.read_csv("vacuum.csv",
    parse_dates=["time"], index_col="time")
log.resample("5min").agg(["mean", "max"])
log["p"].rolling("1min").mean()
log.interpolate(method="time")
log.loc["2026-10-02 12:00":"2026-10-02 12:30"]

МетодЧто делает
resampleравномерная сетка, свёртка по интервалам
rollingокно до текущей точки
shift, diffсдвиг и разность соседних
interpolateзаполнение пропусков; по времени — с method='time'

Для физика

Журнал вакуума, тока пучка или температуры: показания с меткой времени, неравномерные и с пропусками.

Демонстрация:

журнал установки

01

Начало файла vacuum.csv

02

Чтение с индексом времени

03

Пауза в записи и пропуски

04

Свёртка по 10 минутам

05

Всплеск давления и интерполяция тока

Что наблюдается

1708 показаний, разрешение — микросекунды; самая длинная пауза — 3 мин 4 с, 17 пропусков тока. Максимум давления 434 нПа приходится на интервал с 12:40.

root@lab — запись со стенда

Численные методы

SciPy: константы, интегралы и уравнения, минимум и корень, подгонка кривых, интерполяция

06

Массив NumPy

Индексы и векторы

Типы и файлы

Таблицы pandas

Группы и время

Численные методы

Подмодули

и константы

ПодмодульЗадачи
constantsконстанты CODATA, единицы
integrateинтегралы, задача Коши
optimizeминимум, корни, подгонка
interpolateинтерполяция таблиц
linalgсистемы, разложения, спектр
signal, fftфильтры, спектры сигналов
stats, specialраспределения, спецфункции

Пояснение

Многие методы реализуют алгоритмы QUADPACK, ODEPACK, MINPACK и LAPACK; аргументы и результаты — массивы NumPy.

from scipy import constants as C
 
C.c, C.h, C.k, C.e      # точные в СИ
C.physical_constants["electron mass"]
# (9.1093837139e-31, 'kg', 2.8e-40)
 
E = 13.6 * C.eV         # эВ в джоули
C.h * C.c / E / C.nano  # 91.2 нм
C.find("Bohr")          # поиск по названию

Для физика

Формулы записываются в СИ, а данные вводятся в привычных единицах через множители eV, nano, milli.

Закон Планка:

интеграл и корень

from scipy import integrate, optimize
 
# интеграл x^3/(e^x - 1) от 0 до inf равен pi^4/15
f = lambda x: x**3 * np.exp(-x) / (1 - np.exp(-x))
I, err = integrate.quad(f, 0, np.inf)
sigma = 2 * np.pi * C.k**4 / (C.h**3 * C.c**2) * I
 
# максимум спектра: (x - 5) e^x + 5 = 0
g = lambda x: (x - 5) * np.exp(x) + 5
x = optimize.brentq(g, 1, 10)   # g(1) < 0 < g(10)
b = C.h * C.c / (x * C.k)       # lambda_max * T = b

Важно

e^x переполняет float64 при x > 709: множитель e^-x в числителе и знаменателе устраняет переполнение.

Пояснение

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

Пояснение

brentq ищет корень на отрезке, на концах которого функция имеет разные знаки; root решает системы.

Задача Коши:

solve_ivp

from scipy.integrate import solve_ivp
 
def rhs(t, y, g, w0):       # y = [x, v]
    x, v = y
    return [v, -2 * g * v - w0**2 * x]
 
sol = solve_ivp(rhs, (0, 10), [1.0, 0.0],
                args=(0.3, 2 * np.pi),
                t_eval=np.linspace(0, 10, 501),
                rtol=1e-8, atol=1e-10)
x, v = sol.y                # форма (2, 501)

МетодПрименение
RK45по умолчанию, нежёсткие задачи
DOP853высокая точность
Radau, BDFжёсткие задачи
LSODAавтоматический выбор, ODEPACK

Важно

По умолчанию rtol = 1e-3 и atol = 1e-6: около трёх верных знаков. Допуски задаются явно.

Демонстрация:

Планк и осциллятор

01

Константа: значение, единица, погрешность

02

Интеграл Планка через quad

03

Переполнение e^x в исходной записи

04

Постоянные Стефана—Больцмана и Вина

05

Осциллятор: допуски solve_ivp

Что наблюдается

Интеграл совпал с точным значением до 3e-15, σ и b — с CODATA. С допусками по умолчанию ошибка решения 2e-3, с rtol = 1e-8 — 1e-8 при 4796 вычислениях правой части вместо 428.

root@lab — запись со стенда

Минимум

и подгонка

lj = lambda r: 4 * (r**-12 - r**-6)
res = optimize.minimize(lj, x0=1.5)
res.x, res.fun            # [1.1225], -1.0
 
def model(t, n0, tau):    # t, затем параметры
    return n0 * np.exp(-t / tau)
 
popt, pcov = optimize.curve_fit(model, t, y,
    p0=(5, 1), sigma=dy, absolute_sigma=True)
perr = np.sqrt(np.diag(pcov))   # погрешности

АргументыПогрешности из pcov
без sigmaточки равноценны; масштаб по разбросу остатков
sigma=dydy — относительные веса; масштаб по χ²
sigma=dy, absolute_sigma=Truedy — ошибки измерений; без масштаба

Важно

Без p0 все параметры начинаются с 1: для нелинейной модели p0 задаётся явно.

Измерение

эмиттанса

Пучок

ε, β0, α0

Линза

k = 1/f

l = 1,2 м

Экран

размер σ

σ²(k) = ε·(R11²·β0 − 2·R11·R12·α0 + R12²·γ0)
R11 = 1 − k·l,  R12 = l,  γ0 = (1 + α0²)/β0

Для физика

Скан: 25 значений k от −1,5 до 1,5 1/м, ошибка размера 20 мкм; минимум модели 0,158 мм при k = 1,08 1/м.

01

Парабола по k

три коэффициента дают ε, β0 и α0

02

Веса после возведения в квадрат

ошибка σ² равна 2σ·dσ и мала у перетяжки

03

Подгонка с весами

sigma = 2σ·20 мкм, absolute_sigma=True

Важно

Преобразование данных, выпрямляющее модель, меняет и веса точек; тот же эффект даёт логарифмирование экспоненты.

Демонстрация:

подгонка эмиттанса

01

25 измерений размера с ошибкой 20 мкм

02

Подгонка σ² без весов

03

Веса sigma = 2σ·20 мкм

04

absolute_sigma=True: ошибки измерений

05

χ²/dof, корреляция, перетяжка

Что наблюдается

Без весов ε = 0,126 ± 0,045 мкм, с весами и absolute_sigma=True — 0,119 ± 0,009 мкм, в пять раз точнее. χ²/dof = 0,74. Перетяжка: 0,166 мм без весов и 0,157 мм с весами при 0,158 мм у модели.

root@lab — запись со стенда

Интерполяция

таблицы

from scipy import interpolate
 
V = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])  # мВ
T = np.array([0.0, 25.3, 50.1, 76.4, 101.8, 128.0])
np.interp(2.5, V, T)            # 63.25
spl = interpolate.CubicSpline(V, T)
spl(2.5)                        # 63.21
spl.derivative()(2.5)           # 26.5 °C/мВ
np.interp(6.0, V, T), spl(6.0)  # 128.0, 158.1

np.interpCubicSpline
между узламиотрезки, изломгладкая кривая
за таблицейкрайнее значениепродолжение полинома
производнаяступенчатаяspl.derivative()

Важно

Интерполяция проходит через каждую точку, включая шум: шумные данные сглаживаются или подгоняются моделью.

Пояснение

interp1d отнесён к устаревшим интерфейсам: вместо него np.interp, CubicSpline, make_interp_spline.

Итоги

лекции

01

Массив NumPy — числа одного типа подряд; форма и шаги задают, как читать буфер.

02

Срез — представление, маска и список индексов — копия; оси и broadcasting заменяют циклы.

03

Тип элементов определяет память, диапазон и точность; переполнение и округление происходят без сообщений.

04

Таблица pandas — столбцы-массивы с индексом; меняется только операцией над ней самой.

05

groupby, merge, resample и rolling заменяют циклы по строкам; apply — последнее средство.

06

SciPy — проверенные методы; допуски solve_ivp и веса curve_fit задаются явно, погрешности берутся из pcov.

Упражнения

для самопроверки

01

Энергии частиц

массив .npy: гистограмма, среднее и разброс по осям, отбор по маске

02

Матрицы перехода

произведение матриц элементов канала через @ и сверка с циклом

03

Журнал установки

CSV с датами: resample по минутам, скользящее среднее, поиск пропусков

04

Пассажиры «Титаника»

доля выживших по полу, классу и возрасту; заполнение возраста медианой группы

05

Скан линзой

подгонка σ(k) напрямую с ошибкой 20 мкм и сравнение с подгонкой σ²

Пояснение

Каждый векторный расчёт сверяется с прямым циклом на небольших данных, численный — с точным решением.

Для физика

Проект курса: данные эксперимента читаются в массивы и таблицы, а не в списки.

Источники

1

Книга курса: главы «Научные библиотеки Python», «NumPy и pandas», «SciPy», приложение «Массивы NumPy»

phys-dev.github.io/soft-dev-book

2

NumPy — документация

numpy.org/doc/stable

3

pandas — документация и учебник для начинающих

pandas.pydata.org/docs

4

Что нового в pandas 3.0

pandas.pydata.org/docs/whatsnew/v3.0.0.html

5

SciPy — документация

docs.scipy.org/doc/scipy

6

Harris C. R. et al. Array programming with NumPy. – Nature, 2020. – Vol. 585

doi.org/10.1038/s41586-020-2649-2

7

McKinney W. Python for Data Analysis. – 3rd ed. – O'Reilly, 2022

wesmckinney.com/book

8

Rougier N. From Python to NumPy. – 2017

labri.fr/perso/nrougier/from-python-to-numpy

Спасибо за внимание

Вопросы

phys-dev.github.io/soft-dev-book

pd