Вы находитесь на странице: 1из 82

Лекция 2:

numpy

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 1


Мотивация

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 2


Python – это медленно

с = [] # 1D

for i in range(len(a)):
c.append(a[i] * b[i]

python
python python python

3
Писать много – не питонично

c = [] # 2D

for i in range(len(a)):
c.append([])
c1 = c[-1]
много for j in range(len(a[0])):
c1.append(a[i][j] * b[i][j]

много

много

4
Писать много – не питонично

c = [] # nD

raise Exception('Not implemented')

# Fire me please
# Kill me please

5
Математично, питонично, понятно

c = a * b # numpy

6
Numpy предлагает
● Работу с массивами
● с элементами определённого типа (типа C)
● Предопределённые поэлементные операции
● Математическую лаконичность
● Околосветовыесишные скорости

7
Пример: точки синуса в две строки

8
Взгляд на ndarray

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 9


Массив и его поля
numpy.ndarray # многомерный массив
переменные-члены ndarray:
ndim # количество размерностей
shape # кортеж размерностей
size # количество элементов
dtype # тип элемента
itemsize # sizeof элемента
data # буфер со всеми элементами

10
Массив и его поля
a.data
a.ndim == 3
a.shape == (5, 4, 3)
a.size == 60 == 5*4*3
1 3 22 4 6
4 эл.
3 8 1 7 2 a.dtype ==
a=
9 5 3 8 4 dtype('int64')
6 1 2 7 9 a.itemsize == 8
.
эл
3

5 элементов

постоянный размер элемента: длинный python’овский int не пройдёт 11


Заполнение массивов

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 12


Создание из python-ного списка
>>> import numpy as np

>>> a = np.array([2,3,4])
>>> a
array([2, 3, 4]) # тип - автоматически

>>> a.dtype
dtype('int64')

>>> b = np.array([1.2, 3.5, 5.1])


>>> b.dtype
dtype('float64') 13
Создание из python-ного списка
>>> c = np.array( [ [1, 2], [3, 4] ] )
>>> c
array([[ 1, 2],
[ 3, 4]])

>>> c = np.array( [ [1., 2], [3, 4] ] )


>>> c
array([[ 1., 2.],
[ 3., 4.]])

14
Явное задание типа
>>> c = np.array( [ [1,2], [3,4] ],
dtype=complex )
>>> c
array([[ 1.+0.j, 2.+0.j],
[ 3.+0.j, 4.+0.j]])

15
Создание из ничего
>>> np.zeros( (3,4) ) # тип - float64
array([[ 0., 0., 0., 0.], shape
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.]])

>>> np.ones( (2,3,4), dtype=np.int16 ) # иначе float64


array([[[ 1, 1, 1, 1],
[ 1, 1, 1, 1],
[ 1, 1, 1, 1]],
[[ 1, 1, 1, 1],
[ 1, 1, 1, 1],
[ 1, 1, 1, 1]]], dtype=int16)

>>> np.empty( (2,3) ) # массив неинициализированных


array([[ 3.73603959e-262, 6.02658058e-154, 6.55490914e-260],
[ 5.30498948e-313, 3.14673309e-307, 1.00000000e+000]])

см. identity, mgrid, eye и др. 16


Создание на интервале
# минимум максимум шаг
>>> np.arange( 10, 30, 5 )

array([10, 15, 20, 25]) # на [10, 30) с шагом 5

# один раз float – всегда float

>>> np.arange( 0, 2, 0.3 )

array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])

17
Создание на интервале (2)
# минимум максимум количество
>>> np.linspace( 0, 2, 9 )

array([ 0. , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 ,


1.75, 2. ]) # 9 чисел на [0; 2]

NB: arange не включает максимум


linspace включает максимум

см. logspace, mgrid, ogrid и др.

18
Создание случайного массива
>>> np.random.rand(3, 2) # равномерное на [0; 1)

array([[ 0.21409019, 0.57033403],


[ 0.25474206, 0.8790313 ],
[ 0.87042584, 0.79220326]])

>>> np.random.rand() # равномерное на [0; 1)

0.6102079062175166 # число

#np.random.randn - нормальное распределение (mu=0,sigma=1)


#np.random.randint – целые включая максимум
#np.random.random_integers – целые не включая максимум
# ...random_sample – на [0;1), shape передают в кортеже
# ...choice – случайный выбор готовых чисел из массива
# и др.
19
Операции над массивами
и функции, поднятые в мир функторов

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 20


Поэлементные операции
(арифметика и т.д.)
>>> a = np.array( [20,30,40,50] )
>>> b = np.arange( 4 )
>>> b
array([0, 1, 2, 3])

>>> c = a-b # a, b не меняются; создан новый массив


>>> c
array([20, 29, 38, 47])

>>> b**2
array([0, 1, 4, 9])

# работают +, -, *, /, //, %, divmod(), ** или pow(),


# <<, >>, &, ^, |, ~, ==, <, >, <=, >=, !=
21
Логика
>>> a = np.array([1, 2, 3])
>>> b = np.array([2, 3, 0])
>>> a < b
array([ True, True, False], dtype=bool)
>>> a & b
array([0, 2, 0])
>>> a < b < 3
ValueError: The truth value of an array with more than
one element is ambiguous. Use a.any() or a.all()
>>> (a < b) and (b < 3)
ValueError: The truth value of an array with more than
one element is ambiguous. Use a.any() or a.all()
>>> (a < b) & (b < 3)
array([ True, False, False], dtype=bool)
22
Матрицы: поэлементно и не очень
>>> A = np.array( [[1,1],
... [0,1]] )
>>> B = np.array( [[2,0],
... [3,4]] )
>>> A*B # поэлементно
array([[2, 0],
[0, 4]])
>>> A.dot(B) # как матрицы
array([[5, 4],
[3, 4]])
>>> np.dot(A, B) # как матрицы
array([[5, 4],
[3, 4]])
>>> A @ B # как матрицы
array([[5, 4],
[3, 4]]) 23
Поэлементно и с присваиванием
>>> a = np.ones((2,3), dtype=int)
>>> b = np.random.random((2,3))

>>> a *= 3
>>> a
array([[3, 3, 3],
[3, 3, 3]])

>>> b += a
>>> b
array([[ 3.417022 , 3.72032449, 3.00011437],
[ 3.30233257, 3.14675589, 3.09233859]])

24
Функции, работающие
поэлементно
>>> xs = np.arange(0, 5., 1)
>>> ys = np.sin(xs)
>>> zs = np.exp(xs)

>>> xs
array([ 0., 1., 2., 3., 4.])

>>> ys
array([ 0. , 0.84147098, 0.90929743, 0.14112001,
-0.7568025 ])

>>> zs
array([ 1. , 2.71828183, 7.3890561 ,
20.08553692, 54.59815003])

см. universal functions (ufunc) 25


Что стало с массивами - наглядно
xs = np.arange(0, 10, 0.01)

ys = np.sin(xs)

zs = ys ** 2 + xs / 3

ts = np.exp(zs)
Визуализация зависимости xs, ys, zs, ts от xs.
xs, ys, zs, ts - массивы 26
Upcasting: каст в более широкое
(по битам/диапазону) или точное число
>>> a = np.ones((2,3), dtype=int)
>>> b = np.random.random((2,3))

>>> a + b # a расширяется до float


array([[ 3.417022 , 3.72032449, 3.00011437],
[ 3.30233257, 3.14675589, 3.09233859]])

>>> a += b # float сам не сужается до int


Traceback (most recent call last):
...
TypeError: Cannot cast ufunc add output from
dtype('float64') to dtype('int64') with
˓→casting rule 'same_kind'

Вспомним C/C++: там тоже всё узкое и неточное кастится в широкое и точное, когда участвует в выражениях. 27
Ручной каст
>>> a = np.ones((2,3), dtype=int)
>>> b = np.random.random((2,3))

>>> a += b # float сам не сужается до int


Traceback (most recent call last):
...
TypeError: Cannot cast ufunc add output from
dtype('float64') to dtype('int64') with
˓→casting rule 'same_kind'

>>> b.astype(int)
array([[3, 3, 3],
[3, 3, 3]])

>>> a += b.astype(int)

28
Подмассивы,
доступ к элементам

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 29


Доступ к отдельным элементам
>>> a=np.array([[1,2,3],
[4,5,6],
[7,8,9]])
>>> a[0] # "снятие" одного измерения
array([1, 2, 3])

>>> a[0][1]
2

>>> a[0,1] # 0,1 – кортеж координат


2
30
Подмассивы
>>> a[:,1]
array([2, 5, 8])

>>> a[1,:] # как a[1]


array([4, 5, 6])

>>> a[0:3:2, 0:2] как обычные слайсы для списков


в python, только по каждому измерению
array([[1, 2],
[7, 8]])

31
Подмассив: пропуск измерений
>>> a = np.array([[[1000, 1001],
[1010, 1011]],
[[1100, 1101],
[1110, 1111]]])

>>> a[..., 0] # аналогично a[:,:,0]


array([[1000, 1010],
[1100, 1110]])

>>> a[1, ..., 0] # аналогично a[1,:,0]


array([1100, 1110])

>>> a[...]
# получим содержимое массива a
32
Выборка из массива
>>> a = np.array([0,10,20,30,40,50,60,70])

>>> a[np.array([0, 2, 5])]


array([ 0, 20, 50]) массив индексов → массив
элементов с этими индексами

>>> a[np.array([[0, 2], [5, 6]])]


array([[ 0, 20], массив повторяет форму
[50, 60]]) массива индексов

>>> lt3 = a < 30 # массив bool'ов


>>> a[lt3] массив решений
“брать или не брать”
array([ 0, 10, 20])

33
Выборка из массива: nD
>>> a = np.array([[[1000, 1001],
[1010, 1011]],
[[1100, 1101],
[1110, 1111]]])

>>> i = np.array([[0, 1], [1, 1]]) # измерение 1


>>> j = np.array([[1, 0], [1, 0]]) # измерение 2
>>> k = np.array([[0, 0], [0, 1]]) # измерение 3
a[0,1,0]

a[1,0,0]

a[1,1,0]
a[1,0,1] [[a[0,1,0], a[1,0,0]],
[a[1,1,0], a[1,0,1]]]
>>> a[i,j,k]
array([[1010, 1100],
[1110, 1101]])

34
Выборка из массива: nD (2)
>>> idx = (i, j, k) >>> idx = [i, j, k]
>>> a[idx] >>> a[idx]
array([[1010, 1100], array([[1010, 1100],
[1110, 1100]]) [1110, 1100]])

>>> idx = (0, 1, 0) >>> idx = [0, 1, 0]


>>> a[idx] >>> a[idx]
1010 array([[[1000, 1001],
[1010, 1011]],

[[1100, 1101],
[1110, 1111]],

[[1000, 1001],
[1010, 1011]]])
# a[idx] эквивалентно
# a[np.array(idx)]
35
Итерация по массиву
>>> for x in a: print(x)
[[1000 1001]
[1010 1011]]
[[1100 1101]
[1110 1111]]

>>> for x in np.nditer(a): print(x)


1000
1001
1010
1011
1100
1101
1110
1111
Внимание: От быстрых скомпилированных реализаций
переходим к медленным циклам python!
36
Присваивание подмассиву
>>> a = np.array([[1, 2], [3, 4]])
>>> a
array([[1, 2],
[3, 4]])
>>> a[:,0] = 6
>>> a
array([[6, 2],
[6, 4]])
>>> a[1,:] += 10
>>> a
array([[ 6, 2],
[16, 14]])
# заполнение нулями
>>> a[a<16] = 0 a[…] = 0
>>> a
array([[ 0, 0],
[16, 0]]) 37
Присваивание подмассиву (2)
>>> a = np.array([[1, 2], [3, 4]])

>>> a[:,0] = np.array([10, 20])


>>> a
array([[10, 2],
[20, 4]])

>>> a[[0,0,0,0,1],[0,0,0,0,1]] = [-1,-2,-3,100,200]


>>> a
array([[100, 2],
a[0,0] = 100; a[1,1] = 200
[ 3, 200]])

>>> a[[0,0,0,0,1],[0,0,0,0,1]] += [-1,-2,-3,100,200]


>>> a
array([[200, 2],
[ 3, 400]]) a[0,0] += 100; a[1,1] += 200

38
Индекс в ndarray
● Значение или кортеж значений, где значение
● Целое число 0..shape[i]-1
● одномерный/многомерный ndarray целых
индексов
● одномерный ndarray булевых значений
● python slice objects (a:b или a:b:c)
● python ellipsis (...)
● numpy.newaxis (равно None, но нагляднее)
● Что-то ещё?

39
Функции над массивами,
статистики

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 40


Агрегатные функции
>>> a = np.random.random((2,3))
>>> a
array([[ 0.18626021, 0.34556073, 0.39676747],
[ 0.53881673, 0.41919451, 0.6852195 ]])

>>> a.sum()
2.5718191614547998

>>> a.min()
0.1862602113776709

>>> a.max()
0.6852195003967595
41
Агрегатные функции: по осям
>>> a = np.array([[1, 2, 3],
[4, 5, 6]])

>>> a.sum()
21

>>> a.sum(axis=0) сумма по одному измерению –


array([5, 7, 9]) N-1-мерный массив

>>> a.sum(axis=1)
array([ 6, 15])

сумма по одному измерению –


>>> a.sum(axis=(0,1)) N-2-мерный массив
21 42
Быть или не быть?
>>> a = np.array([[0, 1, 0],
[3, 4, 0]])
индексы ненулевых
элементов
>>> a.nonzero()
(array([0, 1, 1]), array([1, 0, 1]))

>>> a[np.nonzero(a)]
array([1, 3, 4])

>>> np.any(a > 0) есть ли True


в массиве (a > 0)?
True

>>> np.array([[True],[False]]).all(axis=0)
array([ True, False], dtype=bool)
43
Индексы минимумов/максимумов
>>> a = np.array([3, 3, 2])

>>> a.argmin()
2

>>> b = np.array([[3, 3, 2],


[4, 0, 3]])

>>> b.argmax(axis=0)
array([1, 0, 1])

>>> b[b.argmax(axis=0), np.arange(0,3,1)] # maxima


array([4, 3, 3])

44
Манипуляции

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 45


Склейка массивов
>>> a = np.floor(10*np.random.random((2,2)))
>>> a
array([[ 8., 8.],
[ 0., 0.]])

>>> b = np.floor(10*np.random.random((2,2)))
>>> b
array([[ 1., 8.],
[ 0., 4.]])

>>> np.vstack((a,b)) # вертикально


array([[ 8., 8.],
[ 0., 0.],
[ 1., 8.],
[ 0., 4.]])

>>> np.hstack((a,b)) # горизонтально


array([[ 8., 8., 1., 8.],
[ 0., 0., 0., 4.]]) 46
Увеличение размерности
>>> a = np.array([1, 2, 3])

>>> a
array([1, 2, 3])

>>> a[:, np.newaxis]


array([[1],
[2],
[3]])

>>> a[np.newaxis, :]
array([[1, 2, 3]])
47
Разделение массивов на части
>>> a = np.array([[1,2,3,4,5,6],[7,8,9,1,2,3]])

>>> a
array([[1, 2, 3, 4, 5, 6],
[7, 8, 9, 1, 2, 3]])

>>> np.hsplit(a, 3)
[array([[1, 2], делим на три части
[7, 8]]), array([[3, 4], array([[1, 2, 3, 4, 5, 6],
[9, 1]]), array([[5, 6], [7, 8, 9, 1, 2, 3]])
[2, 3]])]

>>> np.hsplit(a, [1,3]) делим по элементам 1 и 3


[array([[1], array([[1, 2, 3, 4, 5, 6],
[7]]), array([[2, 3], [7, 8, 9, 1, 2, 3]])
[8, 9]]), array([[4, 5, 6],
[1, 2, 3]])]
48
Работа с формой
>>> a = np.arange(0, 6, 1)
>>> a
array([0, 1, 2, 3, 4, 5])

>>> b = a.reshape((2,3)) # переосмысление измерений


>>> b
array([[0, 1, 2],
[3, 4, 5]])

>>> b.T # транспонирование


array([[0, 3],
[1, 4],
[2, 5]])

>>> b.ravel() # сведение к одному измерению


array([0, 1, 2, 3, 4, 5])
49
Работа с формой
>>> a = np.arange(0, 6, 1)
>>> a
array([0, 1, 2, 3, 4, 5])

>>> b = a.reshape((2,3)) # переосмысление измерений


>>> b
array([[0, 1, 2],
[3, 4, 5]])

>>> c = b.copy() # копирование массива


>>> c.resize((2,2)) # изменение размера самого массива
>>> c
array([[0, 1],
[2, 3]])

# reshape возвращает новый массив, resize изменяет старый

50
Broadcasting

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 51


Broadcasting на примере
>>> a = np.array([[1, 2, 3],
[4, 5, 6]])
>>> b = np.array([10, 20, 30])

>>> a + np.array([b, b]) # 2D + 2D


array([[11, 22, 33],
[14, 25, 36]])

>>> a + b # 2D + 1D
array([[11, 22, 33], b само расширилось
[14, 25, 36]]) до двух измерений

52
Правила броадкастинга
● Для вызова функций, работающих
поэлементно
1.В начала всех форм "маломерных" массивов
добавятся единицы.
2.Все массивы с размером 1 по некоторому
измерению будут вести себя как массивы с
размером, равным максимальному размеру
входного массива по этому измерению, причём
будут выдавать один и тот же элемент по этому
измерению.

53
Правила броадкастинга: пример
● Хотим сложить A и B с формами (2,3,4,5) и
(4,5) соответственно
1.B перейдёт в B' с формой (1, 1, 4, 5)
2.B' перейдёт в B'' с формой (2, 3, 4, 5),
• причём B''[i, j, k, l] == B''[i', j', k, l]
• для всех i,i' из 0..1; j,j' из 0..2; k из 0..3 и l из 0..4

54
Broadcasting
(математические выкладки)
>>> a = np.array([[1, 2, 3], # (2, 3)
[4, 5, 6]])
>>> b = np.array([10, 20, 30]) # (3,)

>>> b1 = b[np.newaxis, :] # (3,) -> (1, 3)


>>> b1
array([[10, 20, 30]])

>>> b2 = b1.repeat(a.shape[0], axis=0) # (1, 3) -> (2, 3)


>>> b2
array([[10, 20, 30],
[10, 20, 30]])

>>> a + b2 # эквивалентно a + b
array([[11, 22, 33],
[14, 25, 36]])
55
Из файла и в файл

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 56


Чтение/запись массива
numpy.fromfile(файл_или_имя_файла,
dtype=тип_массива,
count=сколько_считывать,
sep=разделитель) # '' для бин.файла

ndarray.tofile(файл_или_имя_файла,
sep=разделитель, # '' для бин.файла
format=строка_формата)

numpy.loadtxt, numpy.savetxt – более уместные


варианты для текстовых файлов

57
Запись и чтение массива
>>> a = np.array([[2., 3.1, 4], [0, 3, 9]]);

>>> a.tofile('array.txt', ',', '%3.1f')

>>> f = open('array.txt')
>>> f.read()
'2.0,3.1,4.0,0.0,3.0,9.0'
>>> f.close()

>>> a1 = np.fromfile('array.txt', float, sep=',')


>>> a1
array([ 2. , 3.1, 4. , 0. , 3. , 9. ])

>>> a1 = a1.reshape((2,3))
58
Строение ndarray,
ссылки и значения,
работа над формами

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 59


Массив и его строение
numpy.ndarray # многомерный массив
параметры, нужные для создания ndarray:
shape # кортеж размерностей
dtype # тип элемента
buffer # буфер со всеми элементами
offset # смещение в массиве
strides # шаги в буфере
order # порядок размещения элементов

60
Массив и его строение
buffer
buffer+offset shape == (5, 4, 3)
strides == (5*4*8,
4*8,
1 3 22 4 6
4 эл.
8)
3 8 1 7 2
a=
9 5 3 8 4
itemsize == 8
6 1 2 7 9 offset == 0
.
эл
3

5 элементов

61
strides (на примере 3D)
strides[0]: strides[1]:
1 3 22 4 6 6
3 8 1 7 2 размер 2 размер

4 эл.
* элемента * элемента

4 эл.
9 5 3 8 4 4
6 1 2 7 9 9
5 элементов

Чтобы добраться до элемента (i, j, k),


strides[2]: надо пройти
i двумерных слоёв плюс
1 * размер элемента j одномерных “колбас” плюс
k элементов

В массиве (M, N, K)
M*N*e – толщина слоя
N*e – размер одномерной “колбасы”
e – размер элемента

a[i,j,k] = *(a + MNe + Ne + e) 62


strides + slice (на примере 3D)
Пусть a.strides = (d1, d2, d3),
a.shape = (S1, S2, S3)
a.offset = z
a[i,j,k] = a + z + i*d1 + j*d2 + k*d3

Если b = a[:m,:n,:p] # откусили конец


То b.shape = (m, n, p)
b.strides = (d1, d2, d3)
b.offset = z
b.base = a
# Индексы в b остались теми же, что и в a

Доказательство:
b[i,j,k] = a + z + i*d1 + j*d2 + k*d3 = a[i,j,k]

63
strides + slice (на примере 3D)
Пусть a.strides = (d1, d2, d3),
a.shape = (S1, S2, S3)
a.offset = z
a[i,j,k] = a + z + i*d1 + j*d2 + k*d3

Если b = a[m:,n:,p:] # откусили начало


То b.shape = (S1-m, S2-n, S3-p)
b.strides = (d1, d2, d3)
b.offset = z + d1*m + d2*n + d3*p
b.base = a
# индексы в b на m,n,p меньше, чем в a

Доказательство:
b[i,j,k] = a + z + d1*m + d2*n + d3*p + i*d1 + j*d2 + k*d3
= a + z + d1*(m+i) + d2*(n+j) + d3*(p+k) = a[i+m, j+n, p+k]

64
strides + slice (на примере 3D)
Любой слайс можно описать последовательностью
односторонних слайсов, например
a[m1:m2, n1:n2, k1:k2] =
a[m1:, n1:, k1:][:m2-m1, :n2-n1, :k2-k1]

Следовательно, слайсы математически требуют


только изменения формы, страйдов и смещения в
буфере, после чего могут обращаться к тому же
буферу.

В numpy слайсы не вызывают копирования и


возвращают объект, который ссылается на тот же
буфер.
65
strides, транспонирование и
порядок
>>> a=np.array([[1,2,3],[4,5,6]])

>>> a.strides
(12, 4) # порядок как в C: a[i,j+1] следует за a[i,j]

>>> a.T.strides
(4, 12)

>>> b=np.array([[1,2,3],[4,5,6]], order='F')

>>> b.strides
(4, 8) # порядок Fortran: a[i+1,j] следует за a[i,j]

>>> b.T.strides
(8, 4)
66
Когда numpy копирует?
● numpy не копирует
● когда простые присваивания
– b = a # python assignment, b – ссылка на a
● когда массив передают в функцию
– f(a) # в python объекты передаются по ссылке

67
Когда numpy копирует?
● numpy возвращает view
● когда явно вызывают "view"
– c = a.view() # c – view: у c свои shape, strides, offset, но
c ссылается на тот же буфер, что и a
● когда берут подмассивы
– s = a[:,1:3] # s – view
● иногда, когда вызывают reshape/ravel/T

68
Когда numpy копирует?
● numpy копирует
● когда явно вызывают copy
– d = a.copy() # у d всё своё, даже буфер
● иногда, когда вызывают reshape/ravel/T

69
пара слов о scipy

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 70


SciPy
● Библиотека для научных и инженерных
расчётов
● поиск минимумов и максимумов функций;
● вычисление интегралов функций;
● поддержка специальных функций;
● обработка сигналов;
● обработка изображений;
● работа с генетическими алгоритмами;
● решение обыкновенных дифференциальных
уравнений;
● и др.

https://ru.wikipedia.org/wiki/SciPy 71
numpy + scipy = друзья
>>> import numpy; import scipy; import scipy.stats

>>> a = np.array([1,3,9])

>>> scipy.stats.gmean(a) # среднее геометрическое


3.0000000000000004

>>> scipy.stats.moment(a, 5) # пятый момент


599.17695473251081

72
Заключение

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 73


Do's & don'ts (1)
● Создание массива
● a = np.array([1,2,3,4]) # нормально
● a = np.array(1,2,3,4) # плохо
● A – массив на 10МБ
● A + (1 + 2 + 3) # нормально
● A + 1 + 2 + 3 # тратит память
# на промежуточные массивы
● A = np.empty((10, 20))
● x = 2 + A[5][5] # не инициализированное
● random_number = A[6][6] # не случайное
● не используйте неинициализированные
значения 74
Do's & don'ts (2)
● Заполнение нулями
● a.fill(0) # нормально
● a = 0 # присваивает 0 (python)
● Работа по ссылке
● a # какой-то массив
● b = f(a) # какая-то функция
● b[0] = 2 # плохо надеяться, что a[0] == 2
● b[0] = 2 # плохо надеяться, что a[0] != 2
● не надо надеяться, надо читать мануал
● см. Numpy User Guide, 2.4 Copies and Views

75
Do's & don'ts (3)
● Проход по массиву
● b = np.sin(a) # нормально
● b = np.array([math.sin(x)
for x in a]) # тормозит
● b = []
for x in a:
b.append(math.sin(x)) # тормозит
● Оставайтесь в рамках numpy.ndarray
● Индексация
● a[2,3,4] # элемент (2,3,4)
● a[(2,3,4)] # элемент (2,3,4)
● a[[2,3,4]] # три элем. с инд. 2, 3 и 4 76
Послесловие от любителя C++
● Не стоит думать, что это какое-то python-
специфичное волшебство
● C++ позволяет
● перегружать операторы [] и ()
● использовать наследование и динамический
полиморфизм
● использовать шаблоны и статический
полиморфизм
● компилировать быстрый код
● написать аналог numpy, который будет
ненамного более громоздким
77
C++: библиотека xtensor
#include <iostream>
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"

xt::xarray<double> arr1
{{1.0, 2.0, 3.0},
{2.0, 5.0, 7.0},
{2.0, 5.0, 7.0}};

xt::xarray<double> arr2
{5.0, 6.0, 7.0};

xt::xarray<double> res = xt::view(arr1, 1) + arr2;

std::cout << res; // Outputs: {7, 11, 14}


http://quantstack.net/xtensor 78
Литература
● https://docs.scipy.org/doc/
● Numpy User Guide
– https://docs.scipy.org/doc/numpy/numpy-user-1.13.0.pdf
● Numpy Reference Guide
– https://docs.scipy.org/doc/numpy/numpy-ref-1.13.0.pdf

На данных слайдах были использованы некоторые примеры из документации. 79


Это ещё не всё
Грозин заведует специальным курсом

Материалы: http://inp.nsk.su/~grozin/python/

python * numpy * matplotlib * pandas * mpmath * SymPy * cython * plumbum * Iminuit * PyQt5
80
Благодарности
● Автор выражает благодарность
Соседкину А. П. за помощь.

81
.

Пугачёв Константин Владимирович, ИЯФ СО РАН, K.V.Pugachev@inp.nsk.su (2017) 82

Вам также может понравиться