- •Об авторе
- •О научном редакторе
- •От издательства
- •Введение
- •Использование Python для data science
- •Для кого эта книга?
- •О чем эта книга?
- •Глава 1. Базовые знания о данных
- •Категории данных
- •Неструктурированные данные
- •Структурированные данные
- •Слабоструктурированные данные
- •Данные временных рядов
- •Источники данных
- •Веб-страницы
- •Базы данных
- •Файлы
- •Получение
- •Очистка
- •Преобразование
- •Анализ
- •Хранение
- •Питонический стиль
- •Выводы
- •Глава 2. Структуры данных Python
- •Списки
- •Создание списка
- •Использование общих методов списков
- •Использование срезов
- •Использование списка в качестве очереди
- •Использование списка в качестве стека
- •Использование списков и стеков для обработки естественного языка
- •Расширение функциональности с помощью списковых включений
- •Кортежи
- •Список кортежей
- •Неизменяемость
- •Словари
- •Список словарей
- •Добавление элементов в словарь с помощью setdefault()
- •Преобразование JSON в словарь
- •Множества
- •Удаление дубликатов из последовательности
- •Общие операции с множеством
- •Упражнение № 1: продвинутый анализ тегов фотографий
- •Выводы
- •NumPy
- •Установка NumPy
- •Создание массива NumPy
- •Выполнение поэлементных операций
- •Использование статистических функций NumPy
- •Упражнение № 2: использование статистических функций numpy
- •pandas
- •Установка pandas
- •pandas Series
- •Упражнение № 3: объединение трех серий
- •pandas DataFrame
- •Упражнение № 4: использование разных типов join
- •scikit-learn
- •Установка scikit-learn
- •Получение набора образцов
- •Преобразование загруженного датасета в pandas DataFrame
- •Разделение набора данных на обучающий и тестовый
- •Преобразование текста в числовые векторы признаков
- •Обучение и оценка модели
- •Создание прогнозов на новых данных
- •Выводы
- •Глава 4. Доступ к данным из файлов и API
- •Импортирование данных с помощью функции open()
- •Текстовые файлы
- •Файлы с табличными данными
- •Упражнение № 5: открытие json-файлов
- •Двоичные файлы
- •Экспортирование данных в файл
- •Доступ к удаленным файлам и API
- •Как работают HTTP-запросы
- •Библиотека urllib3
- •Библиотека Requests
- •Упражнение № 6: доступ к api с помощью requests
- •Перемещение данных в DataFrame и из него
- •Импортирование вложенных структур JSON
- •Конвертирование DataFrame в JSON
- •Выводы
- •Глава 5. Работа с базами данных
- •Реляционные базы данных
- •Понимание инструкций SQL
- •Начало работы с MySQL
- •Определение структуры базы данных
- •Вставка данных в БД
- •Запрос к базе данных
- •Упражнение № 8: объединение «один-ко-многим»
- •Использование инструментов аналитики баз данных
- •Базы данных NoSQL
- •Документоориентированные базы данных
- •Упражнение № 9: вставка и запрос нескольких документов
- •Выводы
- •Глава 6. Агрегирование данных
- •Данные для агрегирования
- •Объединение датафреймов
- •Группировка и агрегирование данных
- •Просмотр конкретных агрегированных показателей по MultiIndex
- •Срез диапазона агрегированных значений
- •Срезы на разных уровнях агрегирования
- •Добавление общего итога
- •Добавление промежуточных итогов
- •Выбор всех строк в группе
- •Выводы
- •Глава 7. Объединение датасетов
- •Объединение встроенных структур данных
- •Объединение списков и кортежей с помощью оператора +
- •Объединение словарей с помощью оператора **
- •Объединение строк из двух структур
- •Реализация join-объединений списков
- •Конкатенация массивов NumPy
- •Объединение структур данных pandas
- •Конкатенация датафреймов
- •Удаление столбцов/строк из датафрейма
- •Join-объединение двух датафреймов
- •Выводы
- •Глава 8. Визуализация
- •Распространенные способы визуализации
- •Линейные диаграммы
- •Столбчатые диаграммы
- •Круговые диаграммы
- •Гистограммы
- •Построение графиков с помощью Matplotlib
- •Установка Matplotlib
- •Использование matplotlib.pyplot
- •Работа с объектами Figure и Axes
- •Создание гистограммы с помощью subplots()
- •Совместимость Matplotlib с другими библиотеками
- •Построение графиков для данных pandas
- •Отображение данных геолокации с помощью Cartopy
- •Выводы
- •Глава 9. Анализ данных о местоположении
- •Получение данных о местоположении
- •Преобразование стандартного вида адреса в геокоординаты
- •Получение геокоординат движущегося объекта
- •Анализ пространственных данных с помощью geopy и Shapely
- •Поиск ближайшего объекта
- •Поиск объектов в определенной области
- •Объединение двух подходов
- •Упражнение № 15: совершенствование алгоритма подбора машины
- •Получение непространственных характеристик
- •Объединение датасетов с пространственными и непространственными данными
- •Выводы
- •Глава 10. Анализ данных временных рядов
- •Регулярные и нерегулярные временные ряды
- •Общие методы анализа временных рядов
- •Вычисление процентных изменений
- •Вычисление скользящего окна
- •Вычисление процентного изменения скользящего среднего
- •Многомерные временные ряды
- •Обработка многомерных временных рядов
- •Анализ зависимости между переменными
- •Выводы
- •Глава 11. Получение инсайтов из данных
- •Ассоциативные правила
- •Поддержка
- •Доверие
- •Лифт
- •Алгоритм Apriori
- •Создание датасета с транзакциями
- •Определение часто встречающихся наборов
- •Генерирование ассоциативных правил
- •Визуализация ассоциативных правил
- •Получение полезных инсайтов из ассоциативных правил
- •Генерирование рекомендаций
- •Планирование скидок на основе ассоциативных правил
- •Выводы
- •Глава 12. Машинное обучение для анализа данных
- •Почему машинное обучение?
- •Типы машинного обучения
- •Обучение с учителем
- •Обучение без учителя
- •Как работает машинное обучение
- •Данные для обучения
- •Статистическая модель
- •Неизвестные данные
- •Пример анализа тональности: классификация отзывов о товарах
- •Получение отзывов о товарах
- •Очистка данных
- •Разделение и преобразование данных
- •Обучение модели
- •Оценка модели
- •Упражнение № 19: расширение набора примеров
- •Прогнозирование тенденций фондового рынка
- •Получение данных
- •Извлечение признаков из непрерывных данных
- •Генерирование выходной переменной
- •Обучение и оценка модели
- •Выводы
Списки 47
Расширение функциональности с помощью списковых включений
В главе 1 вы видели пример создания списка с помощью списковых включений. В этом разделе мы используем их для оптимизации алгоритма извлечения именных групп. Расширение функциональности решения часто требует значительного улучшения существующего кода. Однако в данном случае улучшения будут довольно компактными, поскольку речь идет о списковых включениях.
Взглянув на дерево синтаксических зависимостей, показанное на рис. 2.2, видим, что от каждого элемента фразы проведена синтаксическая дуга непосредственно к существительному structure. Однако именная группа может также строиться по другой схеме, когда слова внутри нее не связаны прямой синтаксической связью. Рисунок 2.3 иллюстрирует, как может выглядеть дерево зависимостей такой фразы. Обратите внимание, что наречие most является дочерним для прилагательного useful, а не существительного type, однако оно все еще является частью именной группы, в котором слово type является вершиной.
det
|
|
|
ad/mod |
amod |
||||
|
the |
most |
|
useful |
|
type |
||
|
|
|
|
|
|
|
|
|
|
DET |
|
ADV |
|
ADJ |
|
NOUN |
|
|
О |
|
На |
П а а- С |
- |
|||
|
|
|
|
|
|
|
|
Det: -а Ad/mod: -а Amod: -а а
Рис. 2.3. Дерево синтаксических зависимостей для более сложной именной группы
Улучшим скрипт из предыдущего раздела, чтобы он также мог извлекать именные группы из таких предложений, как то, что показано на рис. 2.3, где некоторые слова не связаны с существительным группы напрямую. Чтобы доработать алгоритм, сначала сравним деревья синтаксических зависимостей, изображенные на рис. 2.2 и 2.3, и найдем то, что их объединяет. Важное сходство заключается в том, что в обоих деревьях вершина для каждого зависимого слова в именной группе находится справа. Однако так бывает не всегда. Например, в предложении «List is a ubiquitous data structure in the Python programming language»1 слово structure является вершиной именной группы, но его собственная вершина — глагол is —
1«Список — это распространенная структура данных в языке программирования Python». — Примеч. пер.
48 Глава 2. Структуры данных Python
находится слева. Чтобы убедиться в этом, можно запустить следующий скрипт, который выведет вершину для каждого слова в предложении:
txt = 'List is a ubiquitous data structure in the Python programming language.' import spacy
nlp = spacy.load('en') doc = nlp(txt)
for t in doc:
print(t.text, t.head.text)
Наш новый алгоритм должен проходить по тексту в поисках слов, вершины для которых находятся справа, — вероятный признак того, что это именная группа. Идея в том, чтобы создать своего рода матрицу для предложения, показывающую, находится ли вершина для каждого конкретного слова справа. Для удобства чтения можно добавлять в матрицу слова, вершины для которых находятся справа, в том же виде, в каком они представлены в предложении, а все остальные слова заменять нулями. Тогда для предложения
List is arguably the most useful type in the Python programming language.
получим следующую матрицу:
['List', 0, 0, 'the', 'most', 'useful', 0, 0, 'the', 'Python', 'programming', 0, 0]
Такую матрицу можно создать с помощью списковых включений:
txt = 'List is arguably the most useful type in the Python programming language.'
import spacy
nlp = spacy.load('en') doc = nlp(txt)
head_lefts = [t.text if t in t.head.lefts else 0 for t in doc] print(head_lefts)
В этом фрагменте кода мы перебираем слова предложения в цикле внутри спискового включения, заменяя нулями те слова, вершины для которых не находятся справа .
Полученный список будет выглядеть так:
['List', 0, 0, 'the', 'most', 'useful', 0, 0, 'the', 'Python', 'programming', 0, 0]
Списки 49
Видим, что список содержит на один элемент больше, чем количество слов в предложении. Это происходит потому, что spaCy фактически разбивает текст на лексемы (tokens), которые могут быть как словами, так и знаками препинания. Последний 0 в списке — это точка в конце предложения.
Теперь нам нужен способ перемещения по этому списку, чтобы найти и извлечь именные группы. Создадим набор фрагментов текста, начинающихся с определенного места и продолжающихся до конца текста. В следующем фрагменте кода будем двигаться пословно от начала до конца текста, на каждой итерации создавая матрицу с позицией вершины:
for w in doc:
head_lefts = [t.text if t in t.head.lefts else 0 for t in doc[w.i:]] print(head_lefts)
Используем срез в объекте doc, чтобы получить нужный фрагмент . Этот механизм позволяет сдвигать крайнюю левую позицию итогового фрагмента на одно слово вправо на каждой итерации цикла for. Код формирует следующий набор матриц:
['List', 0, 0, 'the', 'most', 'useful', 0, 0, 'the', 'Python', 'programming', 0, 0] [0, 0, 'the', 'most', 'useful', 0, 0, 'the', 'Python', 'programming', 0, 0]
[0, 'the', 'most', 'useful', 0, 0, 'the', 'Python', 'programming', 0, 0] ['the', 'most', 'useful', 0, 0, 'the', 'Python', 'programming', 0, 0] ['most', 'useful', 0, 0, 'the', 'Python', 'programming', 0, 0] ['useful', 0, 0, 'the', 'Python', 'programming', 0, 0]
[0, 0, 'the', 'Python', 'programming', 0, 0] [0, 'the', 'Python', 'programming', 0, 0] ['the', 'Python', 'programming', 0, 0] ['Python', 'programming', 0, 0] ['programming', 0, 0]
[0, 0] [0]
Далее проанализируем каждый фрагмент в поисках первого встретившегося нуля. Слова до нуля (включительно) потенциально могут составлять именную группу. Код для этой операции:
for w in doc:
head_lefts = [t.text if t in t.head.lefts else 0 for t in doc[w.i:]]
i0 = head_lefts.index(0)
if i0 > 0:
noun = [1 if t.pos_== 'NOUN' or t.pos_== 'PROPN' else 0 for t in
50 Глава 2. Структуры данных Python
reversed(doc[w.i:w.i+i0 +1])]
try:
i1 = noun.index(1)+1 except ValueError:
pass print(head_lefts[:i0 +1])
print(doc[w.i+i0 +1-i1])
Приравниваем i0 к head_lefts.index(0), чтобы найти индекс первого нуля во фрагменте . Если нулевых элементов несколько, head_lefts.index(0) возвращает индекс первого элемента. Затем проверяем, что i0 > 0, чтобы отсеять фрагменты, которые не начинаются с элемента слева от вершины.
Далее используем еще одно списковое включение для обработки именных групп, которые должны быть отправлены в стек. В этом втором списковом включении внутри каждой потенциальной именной группы мы ищем просто существительное (noun) или имя собственное (proper noun). Проходимся по фрагменту в цикле в обратном порядке (от конца к началу), чтобы в первую очередь найти существительное или имя собственное, которое образует фрагмент и которое, следовательно, должно располагаться в конце фрагмента . При нахождении существительного или имени собственного в список отправляется 1, а при нахождении любого другого элемента — 0. Таким образом, первая 1 в списке указывает на положение главного существительного во фрагменте относительно конца этого фрагмента . Это понадобится при нахождении фрагмента текста, представляющего именную группу .
Пока что мы просто выводим сформированные фрагменты вместе с найденными в них существительными. Вывод будет таким:
['List', 0] List
['the', 'most', 'useful', 0] type
['most', 'useful', 0] type
['useful', 0] type
['the', 'Python', 'programming', 0] language
['Python', 'programming', 0] language
['programming', 0] language
Списки 51
Теперь можно включить новый код в решение из предыдущего раздела. Собрав все воедино, получим такой скрипт:
txt = 'List is arguably the most useful type in the Python programming language.'
import spacy
nlp = spacy.load('en') doc = nlp(txt)
stk = []
for w in doc:
head_lefts = [1 if t in t.head.lefts else 0 for t in doc[w.i:]] i0 = 0
try: i0 = head_lefts.index(0) except ValueError: pass
i1 = 0
if i0 > 0:
noun = [1 if t.pos_== 'NOUN' or t.pos_== 'PROPN' else 0 for t in reversed(doc[w.i:w.i+i0 +1])]
try: i1 = noun.index(1)+1 except ValueError: pass
if w.pos_ == 'NOUN' or w.pos_ == 'PROPN':stk.append(w.text)
elif (i1 > 0):
stk.append(w.text) elif stk:
chunk = '' while stk:
chunk = stk.pop() + ' ' + chunk print(chunk.strip())
Мы проходим по лексемам в предложении , создавая список head_lefts на каждой итерации . Напомню, что этот список представляет собой матрицу, содержащую нули для тех слов в предложении, синтаксическая вершина которых находится слева от них. Эти матрицы используются для определения именных групп. Из каждой найденной группы мы отправляем в стек существительное или имя собственное , а также любое другое слово, которое относится к этой группе, но не является существительным . Когда мы доходим до конца группы, мы извлекаем лексемы из стека, формируя фразу .
Скрипт выведет следующий результат:
List
the most useful type
the Python programming language