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

  • Очистка каждого i-го элемента массива с помощью транслирования, присваивания срезу и изменения формы

  • Когда использовать в NumPy функцию sort(), а когда — argsort()

  • Рис. 3.1.

  • однострочники пайтон. Однострочники Python лаконичный и содержательный код by Кристи. Однострочники


    Скачать 4.44 Mb.
    НазваниеОднострочники
    Анкороднострочники пайтон
    Дата22.04.2022
    Размер4.44 Mb.
    Формат файлаpdf
    Имя файлаОднострочники Python лаконичный и содержательный код by Кристи.pdf
    ТипКнига
    #490720
    страница9 из 21
    1   ...   5   6   7   8   9   10   11   12   ...   21
    Листинг 3.16. Выборочный (булев) доступ по индексу в NumPy import numpy as np a = np.array([[1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]])
    indices = np.array([[False, False, True],
    [False, False, False],
    [True, True, False]])
    print(a[indices])
    # [3 7 8]
    Мы создали два массива: a
    , содержащий двумерные числовые данные (мо- жете считать его массивом данных), и indices
    , содержащий булевы значения
    (можете считать его массивом индексов). В NumPy замечательно то, что можно использовать булев массив для весьма выборочного доступа к мас- сиву данных. Попросту говоря, мы создали новый массив, содержащий только те элементы массива данных a
    , для которых в соответствующих ме- стах массива индексов indices содержатся значения
    True
    . Например, если indices[i,j]==True
    , то наш новый массив содержит значение a[i,j]
    . Анало- гично, если indices[i,j]==False
    , то наш новый массив не содержит значения a[i,j]
    . Таким образом, итоговый массив содержит три значения:
    3
    ,
    7
    и
    8
    В следующем однострочнике воспользуемся этой возможностью, чтобы провести небольшой анализ социальной сети.

    92
    Глава 3. Наука о данных
    Код
    В листинге 3.17 мы найдем имена суперзвезд Instagram более чем со 100 мил- лионами подписчиков!
    Листинг 3.17. Однострочное решение, использующее срезы, типы массивов и булевы операторы
    ## Зависимости import numpy as np
    ## Данные: популярные учетные записи Instagram (миллионы подписчиков)
    inst = np.array([[232, "@instagram"],
    [133, "@selenagomez"],
    [59, "@victoriassecret"],
    [120, "@cristiano"],
    [111, "@beyonce"],
    [76, "@nike"]])
    ## Однострочник superstars = inst[inst[:,0].astype(float) > 100, 1]
    ## Результат print(superstars)
    Как обычно, проверьте, сможете ли мысленно произвести вычисления этого однострочника, прежде чем читать пояснения.
    Принцип работы
    Наши данные состоят из двумерного массива, inst
    , каждая строка которого описывает известного блогера Instagram. Первый столбец отражает количе- ство их подписчиков (в миллионах), а вторая — имена в Instagram. Из этих данных мы хотим извлечь имена известных блогеров Instagram, у которых более чем 100 миллионов подписчиков.
    Существует несколько способов решить эту задачу в одной строке кода. Вот простейший подход:
    ## Однострочник superstars = inst[inst[:,0].astype(float) > 100, 1]
    Разберем этот однострочник по частям. Внутреннее выражение вычисляет булево значение, указывающее, превышает ли 100 миллионов количество подписчиков каждого из наших блогеров:

    Фильтрация двумерных массивов с помощью булева доступа по индексу
    93
    print(inst[:,0].astype(float) > 100)
    # [ True True False True True False]
    Количество подписчиков содержится в первом столбце, так что мы восполь- зуемся срезом для доступа к этим данным: inst[:,0]
    возвращает все строки, но только в первом столбце. Впрочем, поскольку массив данных содержит различные типы данных (целочисленные и строковые значения), NumPy автоматически выбирает для массива нечисловой тип данных. Дело в том, что числовой не подошел бы для строковых значений, поэтому NumPy преоб- разует данные в тип, способный отражать все данные из массива (строковые и целочисленные). Необходимо произвести числовое сравнение значений из первого столбца массива данных с числом 100, для чего мы сначала пре- образуем полученный массив в тип данных с плавающей точкой с помощью
    .astype(float)
    1
    Далее необходимо проверить, превышают ли значения в массиве NumPy с плавающей точкой целочисленное значение 100. В данном случае NumPy автоматически приводит два операнда в одинаковую форму с помощью транслирования, чтобы произвести поэлементное сравнение. Результат пред- ставляет собой массив булевых значений, из которого видно, что у четырех из наших влиятельных блогеров более 100 миллионов подписчиков.
    Теперь можно на основе этого булева массива (называемого также массивом
    индексов с маскированием (mask index array)) выбрать блогеров более чем со 100 миллионами подписчиков (строки) с помощью булева доступа по индексу:
    inst[inst[:,0].astype(float) > 100, 1]
    А поскольку нам нужны только имена этих популярных блогеров, мы вы- бираем из результата второй столбец в качестве окончательного результата и сохраняем его в переменной superstars
    В итоге получаем следующий список блогеров более чем со 100 миллионами подписчиков из нашего набора данных:
    # ['@instagram' '@selenagomez' '@cristiano' '@beyonce']
    Подводя итог: мы воспользовались такими понятиями NumPy, как срезы, транслирование, булев доступ по индексу и преобразование типов данных,
    1
    Возможно, лучше было привести к целочисленному типу, например int16.

    94
    Глава 3. Наука о данных чтобы решить небольшую задачу исследования данных в сфере анализа социальных медиа. Далее вам предстоит увидеть еще одну сферу приложе- ния — интернет вещей.
    Очистка каждого i-го элемента массива
    с помощью транслирования, присваивания
    срезу и изменения формы
    Реальные данные редко бывают «чистыми» по многим причинам, включая поврежденные и сбойные датчики, они могут содержать ошибки и про- пущенные значения. В этом разделе вы научитесь производить небольшие операции очистки для устранения ошибочных точек данных.
    Общее описание
    Представьте, что вы установили в саду датчик температуры. Каждое вос- кресенье вы приносите его домой для снятия показаний. А значит, отдаете себе отчет в неточности воскресных показаний, поскольку часть дня они отражают температуру в доме, а не в саду.
    Вы хотели бы очистить данные, заменив все воскресные показания датчика средним значением за предыдущие семь дней (воскресное показание вы тоже учитываете, поскольку нельзя сказать, что оно совсем неточное). Прежде чем заняться кодом, посмотрим, что нам понадобится для работы.
    Присваивание срезам
    При использовании возможности присваивания срезам NumPy (см. раздел
    «Работа с массивами NumPy: срезы, транслирование и типы массивов» на с. 77) с левой стороны уравнения указываются значения, которые необходи- мо заменить, а справа — значения, которыми их заменяют. В листинге 3.18 приведен небольшой пример, который освежит вашу память.
    Листинг 3.18. Простой пример создания списка и присваивания срезу import numpy as np a = np.array([4] * 16)
    print(a)
    # [4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4]

    Очистка каждого i-го элемента массива с помощью транслирования
    95
    a[1::] = [42] * 15
    print(a)
    # [ 4 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42]
    Этот фрагмент кода создает массив, в котором 16 раз повторяется значение
    4
    С помощью присваивания срезу мы заменяем последние 15 значений на
    42
    . Напомним, что нотация a[начало:конец:шаг]
    служит для выбора по- следовательности, начинающейся с индекса
    начало
    , оканчивающейся на индексе
    конец
    (не включая его), причем состоящей только из элементов
    шаг
    последовательности. Если какие-либо из этих параметров не указаны,
    NumPy использует значения по умолчанию. Нотация a[1::]
    заменяет все элементы последовательности, кроме первого. В листинге 3.19 показано, как применять присваивание срезу вместе с уже неоднократно встречавшейся вам функциональной возможностью.
    Листинг 3.19. Присваивание срезу в NumPy import numpy as np a = np.array([4] * 16)
    a[1:8:2] = 16
    print(a)
    # [ 4 16 4 16 4 16 4 16 4 4 4 4 4 4 4 4]
    Здесь мы заменяем каждое второе значение между индексами 1 и 8 (не вклю- чая последний). Как видите, для замены выбранных элементов достаточно указать единственное значение,
    16
    , благодаря — да, вы правы! — трансли-
    рованию. Правая сторона уравнения автоматически преобразуется в массив
    NumPy той же формы, что и массив слева.
    Изменение формы
    Прежде чем говорить о нашем однострочнике, вам нужно познакомиться с важной функцией NumPy — x.reshape((a,b))
    , — которая преобразует мас- сив NumPy x
    в новый массив NumPy с a
    строк и b
    столбцов (то есть формы
    (a,b)
    ). Пример выглядит так:
    a = np.array([1, 2, 3, 4, 5, 6])
    print(a.reshape((2, 3)))
    '''
    [[1 2 3]
    [4 5 6]]
    '''

    96
    Глава 3. Наука о данных
    Если количество столбцов определяется однозначно, можно позволить
    NumPy сделать это автоматически. Пусть нам нужно изменить форму мас- сива из шести элементов на двумерный массив из двух строк. NumPy может сама вычислить, исходя из равного 6 количества элементов исходного мас- сива, что столбцов должно быть три. Пример таков:
    a = np.array([1, 2, 3, 4, 5, 6])
    print(a.reshape((2, -1)))
    '''
    [[1 2 3]
    [4 5 6]]
    '''
    Значение
    –1
    для соответствующего столбцам аргумента функции reshape указывает NumPy на необходимость заменить его правильным количеством столбцов (в данном случае три).
    Аргумент axis
    Наконец, рассмотрим следующий фрагмент кода, в котором вы познакоми- тесь с аргументом axis
    . Пусть дан массив solar_x с ежедневными котиров- ками компании SolarX Илона Маска. Мы хотим вычислить средний курс акций утром, днем и вечером. Как это реализовать?
    import numpy as np
    # котировки акций по дням
    # [утро, полдень, вечер]
    solar_x = np.array(
    [[1, 2, 3], # сегодня
    [2, 2, 5]]) # вчера
    # полдень — взвешенное среднее print(np.average(solar_x, axis=0))
    # [1.5 2. 4. ]
    Массив solar_x состоит из курсов акций компании SolarX. Он включает две строки (по одной на день) и три столбца (по одному на каждый курс акций).
    Пусть нам нужно вычислить средний курс акций для утра, дня и вечера.
    В общих чертах мы хотим схлопнуть все значения в каждом столбце путем их усреднения. Другими словами, вычислить среднее значение по оси 0.
    Именно это и означает аргумент axis=0

    Очистка каждого i-го элемента массива с помощью транслирования
    97
    Код
    Вот и все, что нужно знать для решения следующей задачи (листинг 3.20): заменить каждое седьмое значение в заданном массиве значений темпера- туры средним значением за последние семь дней (включая значение этого седьмого дня).
    Листинг 3.20. Однострочное решение, использующее операции усреднения и изменения формы, присваивания срезу и аргумент axis
    ## Зависимости import numpy as np
    ## Данные
    ## Данные с датчиков (Пнд, Вт, Ср, Чт, Пт, Сб, Вс)
    tmp = np.array([1, 2, 3, 4, 3, 4, 4,
    5, 3, 3, 4, 3, 4, 6,
    6, 5, 5, 5, 4, 5, 5])
    ## Однострочник tmp[6::7] = np.average(tmp.reshape((-1,7)), axis=1)
    ## Результат print(tmp)
    Можете вычислить результат выполнения этого фрагмента кода?
    Принцип работы
    Исходные данные поступили в виде одномерного массива показаний дат- чиков.
    Во-первых, мы создали массив tmp
    , содержащий одномерную последова- тельность показаний датчиков. В каждой строке описано семь значений измерений датчиков для семи дней недели.
    Во-вторых, с помощью присваивания срезу мы заменяем все воскресные значения этого массива. Поскольку воскресенье — седьмой день, мы выби- раем соответствующие воскресенью значения, начиная с седьмого элемента исходного массива tmp
    , с помощью выражения tmp[6::7]
    В-третьих, мы изменяем форму нашего одномерного массива показаний дат- чиков на двумерный массив, содержащий семь столбцов и три строки, что

    98
    Глава 3. Наука о данных упрощает вычисление средней температуры за неделю, для замены воскрес- ных данных. Благодаря изменению формы мы можем теперь агрегировать все семь значений каждой строки в одно среднее значение. Для изменения формы передаем в tmp.reshape()
    кортеж значений
    –1
    и
    7
    , указывая тем самым NumPy, что количество строк (ось координат 0) необходимо вычис- лить автоматически. Проще говоря, мы указываем, что столбцов должно быть семь, а NumPy создает массив с таким количеством строк, которое бы удовлетворяло этому условию. В нашем случае после смены формы полу- чается следующий массив:
    print(tmp.reshape((-1,7)))
    """
    [[1 2 3 4 3 4 4]
    [5 3 3 4 3 4 6]
    [6 5 5 5 4 5 5]]
    """
    У нас теперь есть по строке для каждой недели и по столбцу для каждого дня недели.
    Теперь можно вычислить среднее значение за семь дней, схлопнув каждую строку в одно число с помощью функции np.average()
    с аргументом axis=1
    , указывающим NumPy схлопнуть вторую ось в одно среднее значение. Обра- тите внимание, что значение за воскресенье также включено в вычисляемое среднее (см. постановку задачи в начале этого раздела). Ниже представлен результат правой половины уравнения:
    print(np.average(tmp.reshape((-1,7)), axis=1))
    # [3. 4. 5.]
    Задача нашего однострочника состоит в замене трех воскресных значений температуры. Все остальные значения менять не нужно. Посмотрим, как можно добиться этого. После замены всех воскресных показаний датчиков окончательный результат работы нашего однострочника должен выглядеть следующим образом:
    # [1 2 3 4 3 4 3 5 3 3 4 3 4 4 6 5 5 5 4 5 5]
    Обратите внимание, что в итоге получается снова одномерный массив
    NumPy со всеми показаниями датчиков температуры. Но все «неправиль- ные» значения заменены теми, которые лучше отражают реальность.

    Когда использовать в NumPy функцию sort(), а когда
    argsort()
    99
    Резюмируя: данный однострочник иллюстрирует понятие формы массива и ее изменения, а также использование свойства axis в агрегирующих функ- циях наподобие np.average()
    . И несмотря на некоторую специфичность этого конкретного их приложения, они могут пригодиться во множестве ситуаций. Далее мы расскажем вам о чрезвычайно широком понятии: сор- тировке в NumPy.
    Когда использовать в NumPy функцию sort(),
    а когда
    argsort()
    Сортировка удобна и даже необходима во множестве ситуаций. Скажем, вы хотите найти на полке книгу «Лаконичный Python. Однострочники и регу- лярные выражения». Правда же, искать ее будет намного проще, если книги на полке отсортированы по алфавиту?
    Общее описание
    Сортировка — центральный элемент более сложных приложений, таких как коммерческие расчеты, планирование процессов в операционных системах
    (очереди по приоритету) и поисковые алгоритмы. К счастью, библиотека
    NumPy предоставляет самые разнообразные алгоритмы сортировки. По умолчанию используется популярный алгоритм быстрой сортировки.
    В главе 6 вы узнаете, как реализовать алгоритм быстрой сортировки само- стоятельно. Однако в следующем однострочнике мы будем придерживаться более высокоуровневого подхода и рассматривать функцию сортировки как
    «черный ящик», на входе которого — массив NumPy, а на выходе — все он же, но уже отсортированный.
    На рис. 3.1 приведен алгоритм преобразования неотсортированного массива в отсортированный — цель функции sort()
    NumPy.
    Но зачастую бывает необходимо получить массив индексов, преобразую- щий неупорядоченный массив в отсортированный. Например, пусть индекс элемента 1 неупорядоченного массива — 7. Поскольку элемент 1 — первый элемент отсортированного массива, его индекс 7 будет первым элементом индексов отсортированного массива. Именно для этого и служит функция argsort()
    : она создает новый массив индексов исходного массива после сор- тировки (см. пример на рис. 3.1). Попросту говоря, этими индексами можно

    100
    Глава 3. Наука о данных воспользоваться для сортировки элементов исходного массива. С помощью данного массива можно восстановить как отсортированный, так и исходный массив.
    Рис. 3.1. Различие между функциями sort() и argsort()
    Листинг 3.21 демонстрирует использование в NumPy функций sort()
    и argsort()
    Листинг 3.21. Функции sort() и argsort() в в NumPy import numpy as np a = np.array([10, 6, 8, 2, 5, 4, 9, 1])
    print(np.sort(a))
    # [ 1 2 4 5 6 8 9 10]
    print(np.argsort(a))
    # [7 3 5 4 1 2 6 0]
    Мы создали неупорядоченный массив a
    , отсортировали его с помощью вызова np.sort(a)
    , а также получили исходные индексы в новом отсор- тированном порядке с помощью вызова np.argsort(a)
    . Функция sort()
    библиотеки NumPy отличается от функции sorted()
    языка Python тем, что может сортировать и многомерные массивы!
    На рис. 3.2 приведены два способа сортировки двумерного массива.
    У данного массива — две оси координат: ось 0 (строки) и ось 1 (столбцы).
    Сор тировать можно либо по оси 0 (так называемая вертикальная сорти-
    ровка), либо по оси 1 (так называемая горизонтальная сортировка). Вообще говоря, ключевое слово axis задает направление, по которому происходит операция NumPy. Листинг 3.22 демонстрирует технические подробности.

    Когда использовать в NumPy функцию sort(), а когда
    argsort()
    101
    Рис. 3.2. Сортировка по разным осям координат
    Листинг 3.22. Сортировка по различным осям import numpy as np a = np.array([[1, 6, 2],
    [5, 1, 1],
    [8, 0, 1]])
    print(np.sort(a, axis=0))
    """
    [[1 0 1]
    [5 1 1]
    [8 6 2]]
    """
    print(np.sort(a, axis=1))
    """
    [[1 2 6]
    [1 1 5]
    [0 1 8]]
    """
    Необязательный аргумент axis служит для сортировки массива NumPy по конкретной оси. Сначала мы отсортировали по столбцам, начиная с мини- мального значения. А затем — по строкам. В этом главное преимущество функции sort()
    библиотеки NumPy по сравнению со встроенной функцией sorted()
    языка Python.
    Код
    Следующий однострочник выясняет имена трех абитуриентов с самыми высокими оценками SAT. Обратите внимание, что нам нужны имена аби- туриентов, а не отсортированные оценки SAT. Взгляните на данные и по- пытайтесь сами найти однострочное решение. И лишь затем разберите листинг 3.23.

    102
    Глава 3. Наука о данных
    Листинг 3.23. Однострочное решение, включающее функцию argsort() и срез с отрицательным значением шага
    ## Зависимости import numpy as np
    ## Данные: оценки за экзамен SAT для различных абитуриентов sat_scores = np.array([1100, 1256, 1543, 1043, 989, 1412, 1343])
    students = np.array(["John", "Bob", "Alice", "Joe", "Jane", "Frank", "Carl"])
    ## Однострочник top_3 = students[np.argsort(sat_scores)][:-4:-1]
    ## Результат print(top_3)
    Как обычно, попробуйте догадаться, какими будут результаты.
    1   ...   5   6   7   8   9   10   11   12   ...   21


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