Главная страница
Навигация по странице:

  • Случайные последовательности и массивы

  • Операции между массивом и скаляром.

  • Операции между массивами.

  • Введение в научный Python-1. Введение в научный Python


    Скачать 6.2 Mb.
    НазваниеВведение в научный Python
    Дата09.01.2020
    Размер6.2 Mb.
    Формат файлаpdf
    Имя файлаВведение в научный Python-1.pdf
    ТипДокументы
    #103229
    страница6 из 22
    1   2   3   4   5   6   7   8   9   ...   22
    3.
    Массивы и линейная алгебра
    В «научном» Python основу всех математических вычислений составляет пакет
    NumPy
    . Он представляет библиотеку типов и функций для работы с массивами и матрицами, и является мультимодульным пакетом. Перечислим некоторые из содержащихся в нем модулей: random (случайный), linalg (линейная алгебра), fft (Fast Fourier Transform – быстрое преобразование Фурье), polynomial
    (работа с полиномами) и многие другие.
    Вначале модуль NumPy следует загрузить. При этом для него можно создать более короткое имя.
    >>> import numpy as np
    После этого к любому объекту модуля можно обращаться, используя это короткое имя.

    66
    Важно также знать версию установленной у вас библиотеки. Это можно сделать командой
    >>> np.__version__
    '1.10.4'
    3.1
    Массивы
    Создание массивов. Основным объектом NumPy является массив элементов, как правило, чисел. Существует несколько способов создать массив. Один из них состоит в создании массива из списка с помощью функции array().
    >>> a=np.array([0.0,2.5,5.2])
    >>> a array([0.,2.5,5.2])
    Функция print(...) из ядра Python, печатает массив в виде списка
    >>> print(a)
    [0. 2.5 5.2]
    Вот как создается двумерный массив
    >>> b=np.array([[1,2,3],[4,5,6]])
    >>> b array([[1, 2, 3],
    [4, 5, 6]])
    Для доступа к элементам массива используются индексы. Нумерация индексов начинается с нуля. Обе следующие записи допустимы.
    >>> b[0,1]
    2
    >>> b[1][2]
    6
    Массивы – это объекты со своими атрибутами и методами. Атрибут ndim содержит размерность массива.
    >>> b.ndim
    2
    Количество элементов по каждой из координат возвращает атрибут shape.
    >>> b.shape
    (2, 3)
    Атрибут size содержит количество элементов в массиве, а функция len вычисляет размер массива по первой координате.
    >>> b.size
    6
    >>> len(b)
    2
    Перебирать элементы массива можно в цикле, например, так:
    >>> for i in a: print(i)
    0.0 2.5 5.2

    67
    Модуль NumPy предоставляет несколько различных числовых типов: int16, int32, int64, float32, float64
    . Массивы могут содержать элементы любого из них, но все элементы массива будут одного типа. Тип элементов массива можно узнать, используя атрибут dtype.
    >>> b.dtype dtype('int32')
    >>> a.dtype dtype('float64')
    В модуле имеются большое количество команд/функций создания массивов.
    Приведем здесь некоторые из них.
    Функция zeros()
    генерирует массив со всеми нулями, а функция ones() генерирует массив со всеми единицами. Размерность и количество элементов задается в аргументах этих функций.
    >>> c=np.zeros(5)
    >>> print(c)
    [0. 0. 0. 0. 0.]
    >>> A=5*np.ones([2,3])
    >>> print(A)
    [[ 5. 5. 5.]
    [ 5. 5. 5.]]
    Здесь умножение числа на массив соответствует умножению каждого элемента массива на число.
    При генерировании массива можно задать тип его элементов.
    >>> d=np.ones(3,dtype=np.int16) )
    >>> print(d)
    [1 1 1]
    Функция eye() генерирует единичную матрицу, размер которой передается через аргумент.
    >>> I=np.eye(3); print(I)
    [[ 1. 0. 0.]
    [ 0. 1. 0.]
    [ 0. 0. 1.]]
    Для создания одномерного массива последовательно идущих чисел в модуле numpy имеются функции arange() и linspace(). Функция arange(a,b,шаг) использует шаг для создания массива чисел, начинающихся значением a, и не превосходящих значение b.
    >>> a=np.arange(0.5,9.3,2.5)
    >>> print(a)
    [0.5 3.0 5.5 8.0]
    Массив N чисел, равномерно распределенных на отрезке [a,b], создается функцией linspace(a,b,N). Начальная и конечная точки включаются.
    >>> np.linspace(0,5,6) array([ 0., 1., 2., 3., 4., 5.])

    68
    Квадратный единичный массив можно создать функцией identity(N), где N размер массива N x N.
    >>> np.identity(3) array([[ 1., 0., 0.],
    [ 0., 1., 0.],
    [ 0., 0., 1.]])
    Функция diag(v[,k=0]) создает квадратный массив (матрицу), на диагонали которого стоят элементы вектора v (одномерного массива), а остальные элементы равны нулю. Заметим, что когда мы говорим о векторе или матрице, то на самом деле подразумеваем одномерный или двумерный массив (как типы
    Python понятия массива и матрицы различаются), или списки соответствующих размеров.
    >>> np.diag([1,2,3]) array([[1, 0, 0],
    [0, 2, 0],
    [0, 0, 3]])
    Необязательный аргумент k представляет номер (побочной) диагонали, на которую будут поставлены элементы вектора v. Аргумент k может быть отрицательным, тогда побочная диагональ располагается снизу от главной.
    >>> np.diag([1,2,3],1) array([[0, 1, 0, 0],
    [0, 0, 2, 0],
    [0, 0, 0, 3],
    [0, 0, 0, 0]])
    Построить массив, используя функцию над его индексами для вычисления элементов, можно следующим образом:
    >>> def g(i): return i**2
    >>> a=np.fromfunction(g,(5,),dtype=np.int32)
    # запятая после пятерки
    >>> print(a)
    [ 0 1 4 9 16]
    У функции fromfunction(...) обычно три аргумента. Первый – это идентификатор функции–генератора, которая в качестве аргументов принимает индексы элементов. Второй аргумент – кортеж размеров массива, в третьем необязательном аргументе указывается тип элементов. Для создания квадратного массива функция–генератор должна принимать два аргумента.
    >>> def f(i,j): return i**2+j**2
    >>> np.fromfunction(f, (3, 3), dtype=int) array([[0, 1, 4],
    [1, 2, 5],
    [4, 5, 8]])

    69
    В Python можно создавать неименованные lambda функции. При генерировании массивов их удобно использовать в качестве первого аргумента.
    >>> np.fromfunction(lambda i, j: i + j, (3, 3)) array([[ 0., 1., 2.],
    [ 1., 2., 3.],
    [ 2., 3., 4.]])
    Нам часто придется использовать двумерные массивы с идентичными строками или столбцами. Для создания таких массивов используется функция meshgrid().
    >>> x=np.array([1,2,3])
    >>> y=np.array([ -1,1])
    >>> X, Y = np.meshgrid(x, y)
    >>> print(X)
    [[1 2 3]
    [1 2 3]]
    >>> print(Y)
    [[-1 -1 -1]
    [ 1 1 1]]
    Здесь генерируются две матрицы/массива. Строки массива
    X
    состоят из элементов вектора x
    , а количество строк определяется длиной вектора y
    Наоборот, столбцы массива
    Y
    состоят из элементов вектора y
    , а количество столбцов определяется длиной вектора x
    Функция meshgrid() полезна для вычисления значения функций в узлах двумерной сетки, координаты узлов которой задаются парой векторов x и y.
    Для примера построим двумерный массив, элементы которого вычисляются в узлах сетки по формуле
    2 2
    j
    i
    j
    i
    y
    x
    z


    при
    2
    ,
    1
    ,
    0
    ,
    1
    ,
    2



    i
    x
    и
    2
    ,
    1
    ,
    0
    ,
    1
    ,
    2



    j
    y
    >>> x=np.linspace(-2,2,5)
    >>> y=np.linspace(-2,2,5)
    >>> print(y)
    [-2. -1. 0. 1. 2.]
    >>> X,Y=np.meshgrid(x,y)
    >>> print(X)
    [[-2. -1. 0. 1. 2.]
    [-2. -1. 0. 1. 2.]
    [-2. -1. 0. 1. 2.]
    [-2. -1. 0. 1. 2.]
    [-2. -1. 0. 1. 2.]]

    70
    >>> print(Y)
    [[-2. -2. -2. -2. -2.]
    [-1. -1. -1. -1. -1.]
    [ 0. 0. 0. 0. 0.]
    [ 1. 1. 1. 1. 1.]
    [ 2. 2. 2. 2. 2.]]
    >>> Z=X**2+Y**2
    >>> print(Z)
    [[ 8. 5. 4. 5. 8.]
    [ 5. 2. 1. 2. 5.]
    [ 4. 1. 0. 1. 4.]
    [ 5. 2. 1. 2. 5.]
    [ 8. 5. 4. 5. 8.]]
    Имея массивы координат вершин X,Y,Z, можно построить поверхность многогранника.
    >>> from matplotlib.pyplot import *
    >>> from mpl_toolkits.m plot3d import Axes3D
    >>> fig=figure()
    # открывает/создает графическое окно
    >>> ax=Axes3D(fig)
    # рисует 3–мерные координатные оси
    >>> ax.plot_surface(X,Y,Z,rstride=1,cstride=1)
    # рисует поверхность
    Графические функции мы будем обсуждать в следующей главе. Не вдаваясь в подробности, скажем, что здесь подключаются два графических модуля и затем вызываются функции, которые строят график многогранной поверхности по массивам X, Y, Z координат ее вершин.
    В модуле numpy имеется оператор mgrid[...], близкий по смыслу функции meshgrid(...) (его аргументы заключаются в квадратные скобки).
    >>> x1, y1 = np.mgrid[0:8:2, -10:0:4]
    >>> print(x1)
    [[0 0 0]
    [2 2 2]
    [4 4 4]
    [6 6 6]]

    71
    >>> print(y1)
    [[-10 -6 -2]
    [-10 -6 -2]
    [-10 -6 -2]
    [-10 -6 -2]]
    >>> x2, y2 = np.meshgrid(np.arange(0, 8, 2), np.arange( -10, 0, 4))
    >>> print(x2)
    [[0 2 4 6]
    [0 2 4 6]
    [0 2 4 6]]
    >>> print(y2)
    [[-10 -10 -10 -10]
    [ -6 -6 -6 -6]
    [ -2 -2 -2 -2]]
    Как видите, функция meshgrid(...) создает транспонированные массивы по сравнению с теми, которые создает оператор mgrid[...].
    Если результат действия последнего оператора mgrid[...] присвоить одной переменной
    >>> g = np.mgrid[0:8:2, -10:0:4]
    то она будет представлять массив из 2D массивов. Т.е. g[0] будет содержать массив x1, а g[1] – массив y1.
    Если в команде np.mgrid[start:stop:step] параметр step содержит мнимую единицу, т.е. имеет вид Nj, то N представляет количество точек на отрезке [start,stop] (а не шаг!), и начальная и конечная точки включаются в массив.
    >>> x3, y3 = np.mgrid[0:6:4j, -10:-2:3j]
    Массивы x3, y3 содержат те же значения, что и массивы x1, y1. В данном случае они отличаются типом элементов (вещественые и целые).
    >>> type(x1[0][0]) numpy.int32
    >>> type(x3[0][0]) numpy.float64
    Случайные последовательности и массивы. Часто приходится использовать объекты, созданные случайным образом. В Python имеется модуль random (не путать с модулем numpy.random
    ), который содержит функции, предназначенные для генерирования случайных чисел, символов, и т.д., а также последовательностей из них. Приведем краткое описание наиболее часто используемых функций этого модуля.
    >>> import random as rnd
    Функция rnd.seed() инициализирует генератор случайных чисел, используя системное время.
    Функция rnd.randrange(start,stop,step) возвращает случайно выбранное целое число X из диапазона start ≤ X < stop, где start,stop и step должны быть целыми числами.

    72
    >>> rnd.seed()
    >>> rnd.randrange(5,25,5)
    15
    Функция N=rnd.randint(A,B) возвращает случайное целое число N из диапазона A ≤ N ≤ B.
    >>> rnd.randint(5, 25)
    11
    Функция rnd.choice(последовательность) возвращает случайный элемент из непустой последовательности, которая может быть списком, кортежем, массивом и т.д.
    >>> rnd.choice([1,'x',"str",(21,3),[1,2,3]])
    'str'
    >>> rnd.choice(np.array([ -1,3,2,6]))
    3
    Функция rnd.shuffle(последовательность) случайным образом перемешивает последовательность. Функция не работает для неизменяемых объектов.
    >>> z=[1,'x',"str",(21,3),[1,2,3]]
    >>> rnd.shuffle(z);z
    [[1, 2, 3], 1, (21, 3), 'x', 'str']
    Функция rnd.random() возвращает одно случайное число из диапазона [0,1].
    >>> rnd.random()
    0.30184417938671937
    Функция rnd.sample(последовательность,k) возвращает список длины k случайно выбранных элементов из последовательности.
    >>> z=rnd.sample((1,'x',"str",(21,3),[1,2,3]), 3); z
    ['str',(21,3),[1, 2, 3]]
    Функция X=rnd.uniform(X0,X1) возвращает случайное число с плавающей точкой из интервала X0 < X < X1 (или X0 ≤ X ≤ X1, зависит от настроек округления).
    >>> rnd.uniform(1.3, 2.4)
    2.3132945207171103
    Для генерирования массивов случайных чисел предназначены функции модуля numpy.random. Они имеют сходный синтаксис с одноименными функциями модуля random,. Приведем несколько примеров.
    >>> import numpy as np
    Функция numpy.random.random(k) генерирует массив k случайных вещественных чисел из полуинтервала [0,1).
    >>> np.random.random(4)
    # массив 4–х вещественных чисел от 0 до 1
    array([0.1501402, 0.68299761, 0.5332606, 0.59519775])
    Имеется несколько похожих функций, отличающихся друг от друга в деталях.
    >>> np.random.rand(3)
    # массив 3–х вещественных чисел от 0 до 1 array([0.16960323, 0.59456467, 0.34565601])
    np.random.rand(2,3)
    # 2x3 массив вещественных чисел от 0 до 1

    73 array([[ 0.04864568, 0.24654989, 0.56020694],
    [ 0.38628115, 0.86663464, 0.09863981]])
    >>> np.random.sample()
    # одно вещественное число от 0 до 1 0.812962885304781
    >>> np.random.sample(3)
    # массив 3–х вещественных чисел от 0 до 1
    array([ 0.32872632, 0.21954113, 0.88342433])
    >>> np.random.sample((2, 3))
    # 2x3 массив вещественных чисел от 0 до 1
    array([[0.13162862, 0.65688322, 0.6176331 ],
    [0.6012843 , 0.16264842, 0.19002568]])
    >>> np.random.randint(3, 8, 5)
    # масcив 5–ти целых чисел 3≤N<8
    array([3, 4, 4, 3, 7])
    >>> np.random.random_integers(3, 8, 5)
    # маcсив 5–ти целых чисел 3≤N≤8
    array([8, 7, 3, 8, 3])
    >>> np.random.randint(3, 8, (2, 4))
    # 2x4 масcив целых чисел 3≤N<8
    array([[4, 5, 6, 7],
    [5, 6, 5, 3]])
    Функция numpy.random.uniform(x0,x1,k) генерирует массив вещественных чисел, равномерно распределенных на интервале (x0,x1).
    >>> np.random.uniform(3, 8, (2, 4))
    # 2x4 массив вещественных чисел array([[ 5.51213273, 4.95171824, 7.73454383, 3.37876069],
    [7.24894408, 7.70482718, 6.56001367, 4.54157435]])
    Функция numpy.random.shuffle(массив) выполняет случайное перемешивание элементов массива.
    >>> z = np.arange(8)
    >>> np.random.shuffle(z);z array([5, 3, 7, 6, 4, 2, 0, 1])
    Функция numpy.random. permutation(N) возвращает массив перемешанных случайным образом целых чисел 0≤n>>> np.random.permutation(8) array([7, 0, 4, 3, 5, 6, 2, 1])
    В модуле numpy.random. имеются и другие, реже используемые функции.
    Операции между массивом и скаляром. Операции +,–,*,/ между массивом и числом означает прибавление (вычитание) числа к каждому элементу массива, умножение (деление) на число каждого элемента массива.
    >>> a=np.array([1.0,2.0,3.0])
    >>> a+10 array([11., 12., 13.])
    >>> print(a*5)
    [ 5. 10. 15.]
    Можно возвести в «числовую» степень каждый элемент массива
    >>> a**2 array([ 1., 4., 9.])
    Допустимы операции составного присваивания типа массив+=число.
    >>> a+=10

    74
    >>> print(a)
    [ 11. 12. 13.]
    >>> b=np.array([[1,2],[3,4]])
    >>> b+=10
    >>> print(b)
    [[11 12]
    [13 14]]
    >>> b*=10
    >>> b array([[110, 120],
    [130, 140]])
    Допустимы и многие другие поэлементные операции между массивами и числами, например, побитовые.
    >>> b=np.array([[1,2],[3,4]])
    >>> print(b | 1)
    [[1 3]
    [3 5]]
    Операции между массивами. С массивами можно выполнять поэлементные арифметические операции. Размерности массивов должны быть одинаковыми, или один из массивов должен быть одноэлементным. Во втором случае операция выполняется как между массивом и скаляром. Если операнды имеют разный тип элементов, то результат приводится к «старшему» типу. Например, можно сложить поэлементно два массива.
    >>> a=np.array([1.0,2.0,3.0])
    >>> b=np.array([10,20,30])
    >>> print(a+b)
    [11. 22. 33.]
    Можно умножить поэлементно два массива. Это умножение не является скалярным (или матричным) произведением.
    >>> print(a*b)
    [10. 40. 90.]
    Можно разделить поэлементно два массива.
    >>> print(a/b)
    [ 0.1 0.1 0.1]
    Допустимо сложение массивов различной размерности.
    >>> a=np.array([1,2,3])
    >>> b=np.array([[1,2,3],[4,5,6]])
    >>> a+b array([[ 2., 4., 6.],
    [ 5., 7., 9.]])
    Каждый элемент первого массива складывается с соответствующими элементами внутренних массивов второго слагаемого. Это работает так же, как и сложение скаляра с массивом. Схематически это выглядит, например, так:
















    2 1
    2 1
    obj obj obj obj obj obj obj
    ,

    75 где объектами obj могут быть скаляры, массивы и другие объекты, для которых определена операция „+‟, например, строки. Здесь квадратные скобки обозначают массив, а не список. Сложение массивов a и b, приведенное выше, действует следующим образом:

     




     


     




























    9
    ,
    7
    ,
    5 6
    ,
    4
    ,
    2 6
    ,
    5
    ,
    4 3
    ,
    2
    ,
    1 3
    ,
    2
    ,
    1 3
    ,
    2
    ,
    1 6
    ,
    5
    ,
    4 3
    ,
    2
    ,
    1 3
    ,
    2
    ,
    1
    Вот как выглядит схема сложения вектора–строки (одномерного массива) и вектора–столбца (двумерного массива с одним столбцом).


     
     
     

      

      

      










































    9
    ,
    8
    ,
    7 8
    ,
    7
    ,
    6 7
    ,
    6
    ,
    5 6
    3
    ,
    2
    ,
    1 5
    3
    ,
    2
    ,
    1 4
    3
    ,
    2
    ,
    1 6
    5 4
    3
    ,
    2
    ,
    1
    Реализацией последней операции сложения являются следующие инструкции.
    >>> x=np.array([1,2,3]);x array([1, 2, 3])
    >>> y=np.array([[4],[5],[6]]);y array([[4],
    [5],
    [6]])
    >>> x+y array([[5, 6, 7],
    [6, 7, 8],
    [7, 8, 9]])
    Заметим, что существует простой способ преобразования вектора–строки y
    (одномерного массива) в вектор–столбец (двумерный массив с одним столбцом). Он реализуется командой y[:,None].
    >>> y = np.linspace(-1.,1.,3); y array([-1., 0., 1.])
    >>> z=y[:,None]; z array([[-1.],
    [ 0.],
    [ 1.]])
    Тогда допустимо следующее сложение:
    >>> x=np.array([1,2,3])
    >>> x+y[:,None]
    array([[ 0., 1., 2.],
    [ 1., 2., 3.],
    [ 2., 3., 4.]])
    Вот примеры других операций с массивами.
    >>> a=np.array([10,20,30])
    >>> b=np.array([2,4,6])
    >>> print(a**b)
    # поэлементное возведение в степень
    [ 100 160000 729000000]
    >>> b*=a
    # составное поэлементное умножение

    76
    >>> b array([ 20, 80, 180])
    >>> a+=b
    # составное поэлементное сложение
    >>> a array([ 30, 100, 210])
    >>> a=np.array([10.,20.,30.])
    >>> b=np.array([2,4,6])
    >>> a/=b
    # составное поэлементное деление
    >>> a array([ 5., 5., 5.])
    >>> a=np.array([2,3,5])
    >>> b=np.array([11,14,19])
    >>> print(b%a)
    # поэлементное вычисление остатка деления
    [1 2 4]
    Массивы можно поэлементно сравнивать. Результатом являются булевы массивы.
    >>> a=np.array([1,2,3])
    >>> c=np.array([0,3,2])
    >>> print(a[False True False]
    1   2   3   4   5   6   7   8   9   ...   22


    написать администратору сайта