однострочники пайтон. Однострочники Python лаконичный и содержательный код by Кристи. Однострочники
Скачать 4.44 Mb.
|
Принцип работы Наши исходные данные состоят из оценок SAT абитуриентов в виде одно- мерного массива данных и еще одного массива с соответствующими именами абитуриентов. Например, Джон набрал на этом экзамене вполне приличную оценку в 1100, а Фрэнк показал великолепный результат — 1412. Наша задача — выяснить имена трех лучших абитуриентов. Для этого мы не просто отсортировали оценки SAT, а воспользовались функцией argsort() , чтобы получить массив с исходными индексами в новых, отсортированных позициях. Вот результаты работы функции argsort() для оценок SAT: print(np.argsort(sat_scores)) # [4 3 0 1 6 5 2] Индексы необходимо сохранить, чтобы узнать имена абитуриентов из массива students , соответствующие исходным позициям в массиве. На первой позиции результата находится индекс 4, поскольку у Джейн самая низкая оценка SAT, равная 989 баллам. Обратите внимание, что и sort() , и argsort() сортируют в порядке возрастания, от самых низких значений к самым высоким. Получив отсортированные индексы, можно узнать имена соответствующих абитуриентов с помощью доступа по индексу к массиву students : Когда использовать в NumPy функцию sort(), а когда — argsort() 103 print(students[np.argsort(sat_scores)]) # ['Jane' 'Joe' 'John' 'Bob' 'Carl' 'Frank' 'Alice'] Возможность библиотеки NumPy переупорядочивать последовательность с помощью расширенного доступа по индексу очень удобна. Если указать последовательность индексов, то NumPy запускает расширенный доступ по индексу и возвращает новый массив NumPy с элементами, переупорядо- ченными так, как указано в этой последовательности. Например, результат вычисления команды students[np.argsort(sat_scores)] равен students[[4 3 0 1 6 5 2]] , вследствие чего NumPy создает следующий новый массив: [students[4] students[3] students[0] students[1] students[6] students[5] students[2]] Из этого ясно, что у Джейн самые низкие оценки SAT, а у Алисы — самые высокие. Осталось только инвертировать список и извлечь из него трех лучших абитуриентов с помощью простого среза: ## Однострочник top_3 = students[np.argsort(sat_scores)][:-4:-1] ## Результат print(top_3) # ['Alice' 'Frank' 'Carl'] У Алисы, Фрэнка и Карла самые высокие оценки SAT: 1543, 1412 и 1343 соответственно. Итак, вы изучили приложение двух важных функций NumPy: sort() и argsort() . Далее вам предстоит еще больше улучшить свое знание до- ступа по индексу и срезов в NumPy, воспользовавшись булевым доступом по индексу и лямбда-функциями в практическом примере исследования данных. Фильтрация массивов с помощью лямбда-функций и булева доступа по индексу Встречающиеся на практике данные обычно зашумлены. Исследователям, собственно, и платят деньги за то, чтобы очистить данные от этого шума, сделать их удобными для восприятия и выяснить содержащийся в них смысл. А значит, фильтрация данных жизненно важна для практических 104 Глава 3. Наука о данных приложений науки о данных. В этом разделе показано, как создать простей- шую функцию для фильтрации из одной строки кода. Общее описание Для создания однострочной функции нам понадобятся лямбда-функции. Как вы помните из главы 2, это анонимные функции, которые можно описать в одной строке кода: lambda аргументы : выражение Разделенный запятыми список аргументов играет роль входных данных. Лямбда-функция вычисляет выражение и возвращает результат. Посмотрим, как решить поставленную задачу путем создания фильтрующей функции, описанной в виде лямбда-функции. Код Рассмотрим следующую задачу, показанную в листинге 3.24: создать функ- цию для фильтрации, принимающую на входе список книг x и их рейтинг y и возвращающую список потенциальных бестселлеров, рейтинг которых превышает заданное пороговое значение: y'>y Листинг 3.24. Однострочное решение, использующее лямбда-функции, преобразование типов и булевы операторы ## Зависимости import numpy as np ## Данные (строка = [название, рейтинг]) books = np.array([['Coffee Break NumPy', 4.6], ['Lord of the Rings', 5.0], ['Harry Potter', 4.3], ['Winnie-the-Pooh', 3.9], ['The Clown of God', 2.2], ['Coffee Break Python', 4.7]]) ## Однострочник predict_bestseller = lambda x, y : x[x[:,1].astype(float) > y] ## Результат print(predict_bestseller(books, 3.9)) Когда использовать в NumPy функцию sort(), а когда — argsort() 105 Прежде чем читать дальше, попробуйте догадаться, какие результаты даст этот код. Принцип работы Наши данные состоят из двумерного массива NumPy, каждая строка которого содержит название книги и средний рейтинг ее у читателей (число с плава- ющей точкой от 0.0 до 5.0). В этом наборе данных — шесть книг. Наша цель состоит в создании функции фильтрации, принимающей на входе набор данных о рейтингах книг x и пороговое значение рейтинга y и возвращающей список книг, рейтинг которых превышает это пороговое значение y . В данном случае мы установили пороговое значение равным 3.9 Для этого мы описали анонимную лямбда-функцию, возвращающую ре- зультат следующего выражения: x[x[:,1] .astype(float)> y] В массиве x должно быть два столбца, как и в нашем массиве рейтингов книг books . Для доступа к потенциальным бестселлерам мы воспользова- лись схемой расширенного доступа по индексу, которая похожа на схему из листинга 3.17. Во-первых, мы извлекли второй столбец с рейтингами книг и преоб- разовали его в массив значений с плавающей точкой с помощью метода astype(float) массива NumPy x . Это необходимо, поскольку исходный массив x состоит из данных различных типов (значения с плавающей точкой и строковые значения). Во-вторых, создали булев массив, содержащий значение True , если рейтинг книги в строке с соответствующим индексом превышает y . Обратите внимание, что значение с плавающей точкой y неявно транслируется на новый массив NumPy, поэтому формы обоих операндов булева оператора > одинаковы. Далее мы создали булев массив, элементы которого указывают для каждой книги, можно ли ее считать бестселлером: x[:,1].astype(float)> y = [ True True True False False True] . Таким образом, первые три книги и последняя — бестселлеры. В-третьих, мы воспользовались упомянутым булевым массивом в качестве массива индексов для исходного массива рейтингов книг, чтобы извлечь все 106 Глава 3. Наука о данных книги с рейтингом, превышающим пороговое значение. Точнее говоря, вос- пользовались булевым доступом по индексу x[[ True True True False False True]] , чтобы получить подмассив, содержащий только четыре книги, кото- рым соответствует значение True . И получаем следующий окончательный результат работы нашего однострочника: ## Результат print(predict_bestseller(books, 3.9)) """ [['Coffee Break NumPy' '4.6'] ['Lord of the Rings' '5.0'] ['Harry Potter' '4.3'] ['Coffee Break Python' '4.7']] """ Резюмируя: вы научились фильтровать данные с помощью одного только булева доступа по индексу и лямбда-функций. Далее мы займемся логиче- скими операторами и изучим полезный трюк для лаконичного написания операции логического И. Создание расширенных фильтров массивов с помощью статистических показателей, а также математических и логических операций В этом разделе вы познакомитесь с простейшим алгоритмом обнаруже- ния аномальных значений: наблюдаемое значение считается аномальным (outlier), если отличается от среднего более чем на стандартное отклоне- ние. Мы пройдемся по примеру анализа данных сайта в целях определения количества его активных пользователей, показателя отказов и средней длительности сеанса в секундах. (Показатель отказов (bounce rate) — это процент посетителей, которые уходят с сайта сразу же после посещения од- ной страницы. Высокий показатель отказов — плохой сигнал, означающий, что сайт, возможно, неинтересен или бесполезен.) Мы рассмотрим данные и выявим аномальные значения. Общее описание Чтобы решить задачу обнаружения аномальных значений, вам сначала нужно разобраться, что такое среднее значение и стандартное отклонение, Создание расширенных фильтров массивов с помощью статистических показателей 107 как вычислить абсолютное значение и выполнить операцию логическо- го И. Среднее значение и стандартное отклонение Во-первых, мы понемногу сформулируем определение аномального зна- чения на основе простейших статистических понятий. Предположим, что все наблюдаемые данные нормально распределены вокруг среднего значения. Например, рассмотрим следующую последовательность зна- чений данных: [ 8.78087409 10.95890859 8.90183201 8.42516116 9.26643393 12.52747974 9.70413087 10.09101284 9.90002825 10.15149208 9.42468412 11.36732294 9.5603904 9.80945055 10.15792838 10.13521324 11.0435137 10.06329581 --сокращено-- 10.74304416 10.47904781] Если построить гистограмму этой последовательности, то получится вот что (рис. 3.3). Рис. 3.3. Гистограмма последовательности значений данных 108 Глава 3. Наука о данных Эта последовательность напоминает нормальное распределение с матема- тическим ожиданием 10 и стандартным отклонением 1. Математическое ожидание, обозначаемое символом µ, представляет собой среднее значение по всем значениям последовательности. Стандартное отклонение, обозна- чаемое символом σ, представляет собой меру отклонения набора данных от среднего значения. По определению, в случае истинно нормального распределения данных 68,2 % всех точек данных попадает в интервал стан- дартного отклонения [ ω 1 = µ – σ, ω 2 = µ + σ]. Из этого следует определение аномальных значений: любое значение, не попадающее в упомянутый ин- тервал, — аномальное. В этом примере мы сгенерировали данные из нормального распределения с µ = 10 и σ = 1, в результате чего получается интервал ω 1 = µ – 1 = 9 и ω 2 = µ + 1 = 11. В дальнейшем мы просто предполагаем, что любое наблюдаемое значение, выходящее за пределы интервала, определяемого стандартным отклонением от математического ожидания, — аномальное. Применитель- но к нашим данным это означает, что любое значение, выходящее за рамки интервала [9, 11] — аномальное. Простой код, с помощью которого я сгенерировал данный график, приведен в листинге 3.25. Попробуйте найти в нем строки с описанием математиче- ского ожидания и стандартного отклонения. Листинг 3.25. Построение гистограммы с помощью библиотеки Matplotlib import numpy as np import matplotlib.pyplot as plt sequence = np.random.normal(10.0, 1.0, 500) print(sequence) plt.xkcd() plt.hist(sequence) plt.annotate(r"$\omega_1=9$", (9, 70)) plt.annotate(r"$\omega_2=11$", (11, 70)) plt.annotate(r"$\mu=10$", (10, 90)) plt.savefig("plot.jpg") plt.show() Код демонстрирует, как построить гистограмму с помощью библиотеки Matplotlib для Python. Однако для нас здесь это не главное; я лишь хотел подчеркнуть, как можно сгенерировать вышеупомянутую последователь- ность значений данных. Создание расширенных фильтров массивов с помощью статистических показателей 109 Достаточно просто импортировать библиотеку NumPy и воспользоваться модулем np.random , предоставляющим функцию normal(математическое_ ожидание, отклонение, форма) , создающую новый массив NumPy, значения которого выбраны из нормального распределения с заданными математи- ческим ожиданием и стандартным отклонением. Именно при ее вызове мы задаем математическое_ожидание=10.0 и отклонение=1.0 для создания данных в последовательности. В данном случае параметр форма=500 указывает, что мы хотим получить одномерный массив данных, включающий 500 точек данных. Оставшийся код импортирует специальный стиль отрисовки графи- ков plt.xkcd() , строит с помощью функции plt.hist(последовательность) гистограмму на основе сгенерированной последовательности с нужными метками и выводит полученный график. ПРИМЕЧАНИЕ Название графика xkcd взято с популярной страницы веб-комиксов xkcd (https://xkcd.com/). Прежде чем заняться исследованием нашего однострочника, вкратце рас- смотрим два оставшихся навыка, которые нам понадобятся, чтобы довести до конца решение нашей задачи. Поиск абсолютного значения Во-вторых, нам придется преобразовывать отрицательные значения в по- ложительные, чтобы проверить, отклоняется ли потенциальное аномальное значение от среднего более чем на стандартное отклонение. Нам важен только модуль отклонения, а не его знак. Это и называется абсолютным зна- чением. Функция библиотеки NumPy в листинге 3.26 создает новый массив NumPy, содержащий модули значений исходного массива. Листинг 3.26. Вычисление абсолютного значения в NumPy import numpy as np a = np.array([1, -1, 2, -2]) print(a) # [ 1 -1 2 -2] print(np.abs(a)) # [1 1 2 2] 110 Глава 3. Наука о данных Функция np.abs() преобразует отрицательные значения массива NumPy в соответствующие им положительные. Операция логического И В-третьих, следующая функция NumPy производит поэлементную опе- рацию логического И, объединяя два булевых массива a и b и возвращая массив, значения в котором представляют собой комбинацию отдельных булевых значений из тех массивов с помощью операции логического И (ли- стинг 3.27). Листинг 3.27. Применение к массивам NumPy операции логического И import numpy as np a = np.array([True, True, True, False]) b = np.array([False, True, True, False]) print(np.logical_and(a, b)) # [False True True False] Мы сочетаем элемент массива a с индексом i и элемент массива b с таким же индексом, обратившись к операции np.logical_and(a, b) . Результат представляет собой массив булевых значений, равных True , если оба опе- ранда a[i] и b[i] равны True , и False в противном случае. Это позволяет схлопывать несколько булевых массивов в один с помощью стандартных логических операций. Один из удобных сценариев применения этого — объ- единение массивов булевых фильтров, подобно тому, как это было сделано в предыдущем однострочнике. Обратите внимание: можно умножить и два булева массива a и b , что также эквивалентно логической операции np.logical_and(a, b) . Дело в том, что Python представляет значение True как целочисленное значение 1 (или даже любое отличное от 0 целочисленное значение), а значение False — как цело- численное значение 0 . Если умножить что-либо на 0 , то получится 0 , то есть False . Это значит, что True (целочисленное значение ≠ 0) получится только тогда, когда все операнды равны True С этими знаниями вы теперь полностью готовы понять следующий одно- строчный фрагмент кода. Создание расширенных фильтров массивов с помощью статистических показателей 111 Код Следующий однострочник находит все аномальные дни, для которых ста- тистические показатели отличаются более чем на стандартное отклонение от среднего значения. Листинг 3.28. Однострочное решение, использующее функции для математического ожидания, стандартного отклонения и булевы операторы с транслированием ## Зависимости import numpy as np ## Данные анализа сайта ## (строка = день), (столбцы = пользователи, отказы, длительность) a = np.array([[815, 70, 115], [767, 80, 50], [912, 74, 77], [554, 88, 70], [1008, 65, 128]]) mean, stdev = np.mean(a, axis=0), np.std(a, axis=0) # [811.2 76.4 88. ], [152.97764543 6.85857128 29.04479299] ## Однострочник outliers = ((np.abs(a[:,0] - mean[0]) > stdev[0]) * (np.abs(a[:,1] - mean[1]) > stdev[1]) * (np.abs(a[:,2] - mean[2]) > stdev[2])) ## Результат print(a[outliers]) Сможете догадаться, какие результаты выведет этот фрагмент кода? Принцип работы Набор данных состоит из строк, соответствующих различным дням, и трех столбцов, отражающих количество активных пользователей за день, пока- затель отказов и среднюю длительность сеанса в секундах соответственно. Для каждого столбца мы вычисляем среднее значение и стандартное от- клонение. Например, среднее значение столбца «Активных пользователей за день» равно 811,2, а его стандартное отклонение равно 152,97. Обратите внимание, что аргумент axis используется аналогично изложенному в раз- деле «Очистка каждого i-го элемента массива с помощью транслирования, присваивания срезу и изменения формы» на с. 94. 112 Глава 3. Наука о данных Наша задача — выявить аномальные по всем трем столбцам сайты. Что ка- сается столбца «Активных пользователей за день», то любое наблюдаемое значение меньше 811,2 – 152,97 = 658,23 или больше 811,2 + 152,23 = 963,43 считается аномальным. Однако целый день мы считаем аномальным только в том случае, если значения во всех трех наблюдаемых столбцах являются аномальными. Для этого мы объединяем три булевых массива с помощью оператора логиче- ского И. Результат представляет собой единственную строку, в которой все три столбца — аномальные значения: [[1008 65 128]] Резюмируя: вы научились использовать оператор логического И библиотеки NumPy в целях простейшего обнаружения аномальных значений с помощью простых статических средств из библиотеки NumPy. Далее вы узнаете о се- кретном ингредиенте успеха Amazon: адекватные рекомендации продуктов для покупки. Простейший анализ ассоциаций: купившие товар X покупают и товар Y Случалось ли вам покупать товары по рекомендациям Amazon? В основе алгоритмов рекомендации часто лежит методика так называемого анализа ассоциаций (association analysis). В этом разделе вы узнаете основные идеи такого анализа и окунетесь в бездну рекомендательных систем. |