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

  • Обнаружение аномальных значений с помощью условного поиска по массиву, фильтрации и транслирования

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


    Скачать 4.44 Mb.
    НазваниеОднострочники
    Анкороднострочники пайтон
    Дата22.04.2022
    Размер4.44 Mb.
    Формат файлаpdf
    Имя файлаОднострочники Python лаконичный и содержательный код by Кристи.pdf
    ТипКнига
    #490720
    страница8 из 21
    1   ...   4   5   6   7   8   9   10   11   ...   21
    ПРИМЕЧАНИЕ
    При повышении размерности массива (например, при переходе от дву- мерного к трехмерному массиву) новая ось становится осью 0, а i-я ось массива более низкой размерности становится (i + 1)-й осью массива более высокой размерности.

    Работа с массивами NumPy: срезы, транслирование и типы массивов
    81
    В листинге 3.9 мы выводим атрибуты shape тех же самых массивов из ли- стинга 3.8.
    Листинг 3.9. Формы одномерного, двумерного и трехмерного массивов NumPy import numpy as np a = np.array([1, 2, 3, 4])
    print(a)
    """
    [1 2 3 4]
    """
    print(a.shape)
    # (4,)
    b = np.array([[2, 1, 2], [3, 2, 3], [4, 3, 4]])
    print(b)
    """
    [[2 1 2]
    [3 2 3]
    [4 3 4]]
    """
    print(b.shape)
    # (3, 3)
    c = np.array([[[1, 2, 3], [2, 3, 4], [3, 4, 5]],
    [[1, 2, 4], [2, 3, 5], [3, 4, 6]]])
    print(c)
    """
    [[[1 2 3]
    [2 3 4]
    [3 4 5]]
    [[1 2 4]
    [2 3 5]
    [3 4 6]]]
    """
    print(c.shape)
    # (2, 3, 3)
    Как видите, атрибуты shape содержат намного больше информации, чем атрибуты ndim
    . Каждый атрибут shape представляет собой кортеж с числом элементов по каждой из осей координат:
    массив a
    — одномерный, так что его кортеж shape содержит один эле- мент, отражающий количество столбцов (четыре элемента);
    массив b
    — двумерный, поэтому его кортеж shape содержит два эле- мента, перечисляющих количество столбцов и строк;

    82
    Глава 3. Наука о данных массив c
    — трехмерный, так что его кортеж shape содержит три эле- мента, по одному для каждой оси. Ось 0 содержит два элемента (каж- дый элемент — двумерный массив), ось 1 — три элемента (каждый из которых — одномерный массив), а ось 2 — три элемента (каждый из которых — целочисленное значение).
    Теперь, когда вы разобрались с атрибутом shape
    , вам будет легче понять общую идею транслирования: приведение двух массивов к одной форме путем переупорядочивания их элементов. Посмотрим, как происходит транслирование. Оно автоматически исправляет поэлементные операции над массивами NumPy различной формы. Например, оператор умножения
    *
    , примененный к массивам NumPy, обычно выполняет поэлементное умноже- ние. Но что произойдет, если данные слева и справа от него не совпадают по форме (скажем, операнд слева представляет собой массив NumPy, а справа — значение с плавающей точкой)? В этом случае NumPy не выдаст ошибку, а автоматически создаст новый массив из данных, расположенных справа.
    Размер и размерность этого нового массива — те же, что и у массива слева, он содержит те же значения с плавающей точкой.
    Таким образом, транслирование представляет собой преобразование массива низкой размерности в массив более высокой размерности для осуществления поэлементных операций.
    Однородные значения
    Массивы NumPy — однородны (homogenous), то есть типы данных у всех значений массива одинаковы. Ниже представлен неполный список воз- можных типов данных массивов:
    bool
    — булев тип данных в Python (1 байт);
    int
    — целочисленный тип данных в Python (размер по умолчанию —
    4 или 8 байт);
    float
    — тип данных с плавающей точкой в Python (размер по умол- чанию — 8 байт);
    complex
    — тип данных для комплексных чисел в Python (размер по умолчанию — 16 байт);
    np.int8
    — целочисленный тип данных (1 байт);
    np.int16
    — целочисленный тип данных (2 байта);

    Работа с массивами NumPy: срезы, транслирование и типы массивов
    83
    np.int32
    — целочисленный тип данных (4 байта);
    np.int64
    — целочисленный тип данных (8 байт);
    np.float16
    — тип данных с плавающей точкой (2 байта);
    np.float32
    — тип данных с плавающей точкой (4 байта);
    np.float64
    — тип данных с плавающей точкой (8 байт).
    В листинге 3.10 показано создание массивов NumPy с различными типами.
    Листинг 3.10. Массивы NumPy с различными типами import numpy as np a = np.array([1, 2, 3, 4], dtype=np.int16)
    print(a) # [1 2 3 4]
    print(a.dtype) # int16
    b = np.array([1, 2, 3, 4], dtype=np.float64)
    print(b) # [1. 2. 3. 4.]
    print(b.dtype) # float64
    В этом коде два массива, a
    и b
    . Тип данных первого из них — np.int16. Числа в этом массиве — типа integer (после числа нет десятичной точки). Если точнее, то результат вывода свойства dtype массива a
    — int16.
    Тип данных второго массива — np.float64. Так что даже если создать массив, в основе которого лежит список целых чисел, NumPy все равно преобразует его тип в np.float64.
    Из вышеизложенного можно сделать два важных вывода: NumPy позволяет управлять типом данных, причем типы данных массивов NumPy — одно- родны.
    Код
    Итак, имеются данные по многим специальностям, и нужно повышать зарплаты одних только исследователей данных на 10 % раз в два года. Со- ответствующий код приведен в листинге 3.11.
    Задумайтесь на минуту о результатах выполнения этого фрагмента кода.
    Как вы думаете, что изменится? Какой тип данных будет у полученного в результате массива? Что выведет данный код?

    84
    Глава 3. Наука о данных
    Листинг 3.11. Однострочное решение, использующее срезы и присваивания срезам
    ## Зависимости import numpy as np
    ## Данные: годовые зарплаты в тысячах долларов (за 2025, 2026 и 2027 гг.)
    dataScientist = [130, 132, 137]
    productManager = [127, 140, 145]
    designer = [118, 118, 127]
    softwareEngineer = [129, 131, 137]
    employees = np.array([dataScientist,
    productManager,
    designer,
    softwareEngineer])
    ## Однострочник employees[0,::2] = employees[0,::2] * 1.1
    ## Результат print(employees)
    Принцип работы
    В этом фрагменте кода вы попадаете в 2024 год. Во-первых, вы создаете мас- сив NumPy, каждая строка которого содержит ожидаемую годовую зарплату одного специалиста (исследователя данных, руководителя по программ- ному продукту, дизайнера или разработчика программного обеспечения).
    А каждый столбец отражает соответствующие годовые зарплаты за 2025,
    2026 и 2027 годы. Полученный в результате массив NumPy включает четыре строки и три столбца.
    Вы нашли средства, чтобы поощрить самых важных специалистов в компании.
    Вы верите в будущее data science, поэтому решили вознаградить незаметных героев вашей компании: исследователей данных. Вам нужно обновить массив
    NumPy так, чтобы только зарплаты исследователей данных возрастали на 10 % через год (без капитализации процентов) начиная с 2025 года.
    Вы разработали следующий замечательный однострочник:
    employees[0,::2] = employees[0,::2] * 1.1
    Он выглядит просто и аккуратно, а результаты его работы — следующие:
    [[143 132 150]
    [127 140 145]

    Работа с массивами NumPy: срезы, транслирование и типы массивов
    85
    [118 118 127]
    [129 131 137]]
    Несмотря на свою простоту, однострочник использует три интересных про- двинутых понятия.
    Срезы
    Во-первых, мы воспользуемся срезами и присваиванием срезам. В этом примере с помощью среза мы извлечем каждое второе значение из первой строки массива NumPy employees
    . Далее выполним некоторые модификации и обновим каждое второе значение первой строки с помощью присваива- ния срезу. Синтаксис присваивания срезу не отличается от самого среза, за исключением одного важного нюанса: в этом случае срез указывается с левой стороны оператора присваивания. Соответствующие элементы бу- дут заменены элементами, указанными справа от оператора присваивания.
    В представленном фрагменте кода мы заменяем содержимое первой строки массива NumPy обновленными данными о зарплатах.
    Транслирование
    Во-вторых, мы воспользуемся транслированием для автоматического ис- правления поэлементных операций над массивами NumPy различной формы.
    В нашем однострочнике левый операнд — массив NumPy, а правый — значение с плавающей точкой. Опять же, NumPy автоматически создает новый массив того же размера и размерности, что и массив слева от оператора присваива- ния, и заполняет его, по сути, копиями этого значения с плавающей точкой.
    Фактически NumPy производит вычисление наподобие следующего:
    np.array([130 137]) * np.array([1.1, 1.1])
    Типы массивов
    В-третьих, наверное, вы поняли, что тип данных результата — не float, а integer, даже если вы выполняете операции над числами с плавающей точкой. При создании массива NumPy понимает, что тот содержит толь- ко целочисленные значения, поэтому полагает, что массив должен быть типа integer. Никакие операции над массивом типа integer не меняют типа данных, вследствие чего NumPy будет округлять значения до целочислен- ных. Опять же, узнать тип массива можно с помощью свойства dtype
    :

    86
    Глава 3. Наука о данных print(employees.dtype)
    # int32
    employees[0,::2] = employees[0,::2] * 1.1
    print(employees.dtype)
    # int32
    Итак, вы узнали о срезах, присваивании срезам, транслировании и типах массивов NumPy — впечатляющее достижение для однострочного фрагмента кода. Закрепим достигнутый успех, решив небольшую, но практичную за- дачу исследования данных: выявление аномальных значений в измерениях загрязнений для различных городов.
    Обнаружение аномальных значений с помощью
    условного поиска по массиву, фильтрации
    и транслирования
    В этом однострочнике мы будем изучать данные о загрязненности воздуха в городах. А именно, по представленному двумерному массиву NumPy с дан- ными измерений загрязнений (столбцы) для нескольких городов (строки) мы найдем города с загрязнением выше среднего. Полученные при чтении этого раздела навыки пригодятся вам при поиске аномальных значений в различных наборах данных.
    Общее описание
    Индекс качества воздуха (Air Quality Index, AQI) служит для оценки опас- ности вредного воздействия на здоровье и часто применяется для сравнения качества воздуха в различных городах. В следующем однострочнике мы будем исследовать AQI четырех городов: Гонконга, Нью-Йорка, Берлина и Монреаля.
    Данный однострочник выявляет города, загрязненные выше среднего, то есть такие, максимальное значение AQI которых выше общего среднего значения по всем измерениям всех городов.
    Важная составляющая нашего решения: поиск элементов в массиве NumPy, удовлетворяющих заданному условию. Это распространенная задача в data science, с которой вы будете сталкиваться очень часто.

    Обнаружение аномальных значений с помощью условного поиска по массиву
    87
    Итак, разберемся, как найти элементы массива, удовлетворяющие опреде- ленному условию. NumPy предоставляет функцию nonzero()
    для поиска индексов элементов в массиве, которые не равны нулю. В листинге 3.12 приведен пример.
    Листинг 3.12. Функция nonzero import numpy as np
    X = np.array([[1, 0, 0],
    [0, 2, 2],
    [3, 0, 0]])
    print(np.nonzero(X))
    Результат представляет собой кортеж из двух массивов NumPy:
    (array([0, 1, 1, 2], dtype=int64), array([0, 1, 2, 0], dtype=int64))
    Первый массив содержит индексы строк, а второй — индексы столбцов ненулевых элементов. В исходном двумерном массиве содержится четыре ненулевых элемента: 1, 2, 2 и 3, на позициях
    X[0,0]
    ,
    X[1,1]
    ,
    X[1,2]
    и
    X[2,0]
    Как же с помощью функции nonzero()
    найти в массиве элементы, удов- летворяющие определенному условию? Для этого обратимся еще к одной замечательной возможности NumPy: булевым операциям над массивами, выполняемым с помощью транслирования (листинг 3.13)!
    Листинг 3.13. Транслирование и поэлементные булевы операторы в NumPy import numpy as np
    X = np.array([[1, 0, 0],
    [0, 2, 2],
    [3, 0, 0]])
    print(X == 2)
    """
    [[False False False]
    [False True True]
    [False False False]]
    """
    Транслирование происходит при копировании (по существу) целочисленно- го значения
    2
    в новый массив той же формы, что и исходный. Далее NumPy

    88
    Глава 3. Наука о данных производит поэлементное сравнение всех целочисленных значений со зна- чением
    2
    и возвращает полученный в результате булев массив.
    В нашем основном коде для поиска элементов, удовлетворяющих определен- ному условию, мы воспользуемся сочетанием функции nonzero()
    и операций над булевыми массивами.
    Код
    В листинге 3.14 мы найдем в наборе данных города с максимумами загряз- нения, превышающими среднее значение.
    Листинг 3.14. Однострочное решение, использующее транслирование, булевы операторы и выборочный доступ по индексу
    ## Зависимости import numpy as np
    ## Данные: измерения индекса качества воздуха, AQI (строка = город)
    X = np.array(
    [[ 42, 40, 41, 43, 44, 43 ], # Гонконг
    [ 30, 31, 29, 29, 29, 30 ], # Нью-Йорк
    [ 8, 13, 31, 11, 11, 9 ], # Берлин
    [ 11, 11, 12, 13, 11, 12 ]]) # Монреаль cities = np.array(["Hong Kong", "New York", "Berlin", "Montreal"])
    ## Однострочник polluted = set(cities[np.nonzero(X > np.average(X))[0]])
    ## Результат print(polluted)
    Можете определить, какими будут результаты выполнения этого кода?
    Принцип работы
    Массив данных
    X
    содержит четыре строки (по одной для каждого города) и шесть столбцов (по одному для каждого отрезка измерения — в данном случае дня). Строковый массив cities содержит четыре названия городов в том порядке, в каком те встречаются в массиве с данными.
    Вот однострочник для поиска городов, в которых наблюдается уровень AQI выше среднего:

    Обнаружение аномальных значений с помощью условного поиска по массиву
    89
    ## Однострочник polluted = set(cities[np.nonzero(X > np.average(X))[0]])
    Чтобы понять, как он работает в целом, необходимо сначала разобраться в каждой из его составных частей. Проанализируем его, начав изнутри. В его сердцевине находится операция над булевым массивом (листинг 3.15).
    Листинг 3.15. Операция над булевым массивом с помощью транслирования print(X > np.average(X))
    """
    [[ True True True True True True]
    [ True True True True True True]
    [False False True False False False]
    [False False False False False False]]
    """
    Чтобы привести оба операнда к одной форме с помощью транслирования, мы воспользовались булевым выражением. Для вычисления среднего по всем элементам нашего массива NumPy значения AQI мы задействуем функцию np.average()
    . Далее булево выражение производит поэлементное сравне- ние, и получается булев массив, содержащий
    True
    , если соответствующее измерение превышает среднее значение AQI.
    Благодаря генерации этого булева массива мы знаем в точности, какие эле- менты удовлетворяют условию «выше среднего», а какие — нет.
    Напомним, что значение
    True языка Python представлено значением
    1
    типа integer, а
    False

    0
    . На самом деле тип объектов
    True и
    False
    — bool
    — явля- ется подклассом int
    . Таким образом, каждое булево значение является также и целочисленным значением. Благодаря этому мы можем воспользоваться функцией nonzero()
    для поиска всех удовлетворяющих условию индексов строк и столбцов, вот так:
    print(np.nonzero(X > np.average(X)))
    """
    (array([0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2], dtype=int64),
    array([0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 2], dtype=int64))
    """
    Получаем два кортежа, первый — с индексами строк ненулевых элементов, а второй — с индексами соответствующих им столбцов.
    Нам нужны только названия городов со значениями AQI выше среднего, и ничего больше, поэтому нас интересуют только индексы строк, которыми

    90
    Глава 3. Наука о данных мы можем воспользоваться для извлечения символьных названий городов из нашего строкового массива с помощью расширенного доступа по индексу
    (advanced indexing) — методики доступа по индексу, позволяющей описывать не непрерывную последовательность индексов массива.
    Таким образом можно обращаться к произвольным элементам данного мас- сива NumPy, указывая последовательность либо целых чисел (выбираемых индексов), либо булевых значений (для выбора тех индексов, для которых соответствующее булево значение равно
    True
    ):
    print(cities[np.nonzero(X > np.average(X))[0]])
    """
    ['Hong Kong' 'Hong Kong' 'Hong Kong' 'Hong Kong' 'Hong Kong' 'Hong Kong'
    'New York' 'New York' 'New York' 'New York' 'New York' 'New York' 'Berlin']
    """
    Как видите, в полученной последовательности строковых значений немало повторов, поскольку в числе измерений AQI Гонконга и Нью-Йорка много значений выше среднего.
    Осталось только убрать эти повторы. Для этого мы преобразуем нашу последовательность во множество Python, в котором по определению от- сутствуют дублирующиеся значения, и получим краткую сводку названий всех городов, степень загрязнения воздуха в которых превышает средние значения AQI.
    УПРАЖНЕНИЕ 3.1
    Вернитесь к примеру с налогообложением в разделе
    «Простейшие операции с двумерными массивами
    » на с. 72 и извлеките из матрицы имя сотрудника с самой высокой зарплатой, применив вышеупомянутую методику выборочного булева доступа по индексу. Краткое резюме задачи: как найти человека с максимальным доходом после уплаты налогов в группе людей при заданных годовых зарплатах и ставках на- логообложения?
    Резюмируя: вы научились использовать булевы выражения для массивов
    NumPy (опять же, с помощью транслирования) и функцию nonzero()
    для поиска строк или столбцов, удовлетворяющих определенным условиям. По- занимавшись охраной окружающей среды в этом однострочнике, перейдем к влиятельным блогерам в социальных медиа.

    Фильтрация двумерных массивов с помощью булева доступа по индексу
    91
    Фильтрация двумерных массивов с помощью
    булева доступа по индексу
    В этом разделе вы закрепите свои навыки доступа к массивам по индексу и транслирования на примере извлечения пользователей Instagram более чем со 100 миллионами подписчиков из небольшого набора данных. А именно, мы выясним имена всех известных блогеров более чем со 100 миллионами подписчиков по заданному двумерному массиву блогеров (строки), в кото- ром первый столбец задает имя блогера в виде строкового значения, а вто- рой — количество подписчиков этого блогера.
    Общее описание
    Массивы NumPy расширяют простой тип данных списка дополнительной функциональностью, например многомерными срезами и многомерным до- ступом по индексу. Взгляните на фрагмент кода в листинге 3.16.
    1   ...   4   5   6   7   8   9   10   11   ...   21


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