Рубрики
Без рубрики

Анализ данных API с помощью MongoDB, Seaborn и Matplotlib

Автор оригинала: Dan Nelson.

Анализ данных API с помощью MongoDB, Seaborn и Matplotlib

Вступление

Обычно востребованным навыком для должностей разработчиков программного обеспечения является опыт работы с базами данных NoSQL, включая MongoDB. В этом уроке мы рассмотрим сбор данных с помощью API, хранение их в базе данных MongoDB и проведение некоторого анализа этих данных.

Однако, прежде чем перейти к коду, давайте рассмотрим MongoDB и API, чтобы убедиться, что мы понимаем, как мы будем иметь дело с данными, которые мы собираем.

MongoDB и NoSQL

MongoDB – это форма базы данных NoSQL , позволяющая хранить данные в нереляционных формах. Базы данных NoSQL лучше всего понять, сравнивая их с их предшественниками/конкурентами – базами данных SQL.

SQL расшифровывается как Structure Query Language и является одним из видов инструмента управления реляционными базами данных. Реляционная база данных-это база данных, которая хранит данные в виде серии ключей и значений, причем каждая строка в таблице данных имеет свой собственный уникальный ключ. Значения в базе данных могут быть получены путем поиска соответствующего ключа. Именно так базы данных SQL хранят данные, но базы данных NoSQL могут хранить данные нереляционными способами.

NoSQL расшифровывается как “Не только SQL”, что означает тот факт, что хотя SQL-запросы могут выполняться с помощью систем NoSQL, они также могут делать то, с чем борются базы данных SQL. Базы данных NoSQL имеют более широкий диапазон вариантов хранения данных, которые они обрабатывают, и поскольку данные менее жестко связаны, они могут быть извлечены несколькими способами, что делает некоторые операции более быстрыми. Базы данных NoSQL могут упростить добавление узлов или полей по сравнению с базами данных SQL.

Существует множество популярных фреймворков NoSQL, включая MongoDB , OrientDB , InfinityDB , Aerospike и CosmosDB . MongoDB-это один из специфических фреймворков NoSQL, который хранит данные в виде документов, действуя как ориентированная на документы база данных.

MongoDB популярен благодаря своей универсальности и легкой облачной интеграции, а также может использоваться для решения самых разнообразных задач. MongoDB хранит данные в формате JSON. Запросы к базам данных MongoDB также выполняются в формате JSON, и поскольку команды хранения и извлечения основаны на формате JSON, их легко запомнить и составить для MongoDB.

Что такое API?

API – это интерфейсы прикладного программирования, и их функция состоит в том, чтобы облегчить коммуникацию между клиентами и серверами. API часто создаются для облегчения сбора информации теми, кто менее опытен в языке, используемом разработчиками приложения.

API также могут быть полезными методами управления потоком информации с сервера, побуждая тех, кто заинтересован в доступе к его информации, использовать для этого официальные каналы, а не создавать веб-скребок. Наиболее распространенными API для веб-сайтов являются API REST (Representational State Transfer), которые используют стандартные HTTP-запросы и ответы для отправки, получения, удаления и изменения данных. Мы будем обращаться к REST API и делать наши запросы в формате HTTP для этого урока.

Какой API мы будем использовать?

API, который мы будем использовать, – это API GameSpot. GameSpot-один из крупнейших сайтов обзора видеоигр в Интернете, и его API можно найти здесь .

Подготовка К Установке

Прежде чем мы начнем, вы должны быть уверены, что получите ключ API для GameSpot. Вы также должны быть уверены, что у вас установлен MongoDB и его библиотека Python. Инструкции по установке Mongo можно найти здесь .

Библиотека PyMongo может быть установлена просто запустив:

$ pip install pymongo

Вы также можете установить программу MongoDB Compass , которая позволяет легко визуализировать и редактировать аспекты баз данных MongoDB с помощью графического интерфейса.

Создание базы данных MongoDB

Теперь мы можем начать наш проект с создания базы данных MongoDB. Во-первых, мы займемся импортом. Мы импортируем MongoClient из PyMongo, а также запросы и панды :

from pymongo import MongoClient
import requests
import pandas as pd

При создании базы данных с помощью MongoDB нам сначала нужно подключиться к клиенту, а затем использовать клиент для создания нужной нам базы данных:

client = MongoClient('127.0.0.1', 27017)
db_name = 'gamespot_reviews'

# connect to the database
db = client[db_name]

MongoDB может хранить несколько коллекций данных в одной базе данных, поэтому нам также нужно определить имя коллекции, которую мы хотим использовать:

# open the specific collection
reviews = db.reviews

Вот и все. Наша база данных и коллекция уже созданы, и мы готовы начать вставлять в нее данные. Это было довольно просто, не так ли?

Использование API

Теперь мы готовы использовать API GameSpot для сбора данных. Взглянув на документацию по API here , мы можем определить формат, в котором должны быть наши запросы.

Нам нужно сделать наши запросы к базовому URL-адресу, который содержит наш ключ API. API GameSpot имеет множество собственных ресурсов, из которых мы можем извлекать данные. Например, у них есть ресурс, который перечисляет данные об играх, таких как дата выпуска и консоли.

Однако нас интересует их ресурс для обзоров игр, и мы вытащим несколько конкретных полей из ресурса API. Кроме того, GameSpot просит вас указать уникальный идентификатор user agent при выполнении запросов, что мы сделаем, создав заголовок, который мы передадим в функцию requests :

headers = {
    "user_agent": "[YOUR IDENTIFIER] API Access"
}

games_base = "http://www.gamespot.com/api/reviews/?api_key=[YOUR API KEY HERE]&format=json"

Нам понадобятся следующие поля данных: id , title , score , deck , body , good , bad :

review_fields = "id,title,score,deck,body,good,bad"

GameSpot позволяет возвращать только 100 результатов за один раз. По этой причине, чтобы получить достаточное количество отзывов для анализа, нам нужно будет создать диапазон чисел и перебирать их, получая 100 результатов за раз.

Вы можете выбрать любое число, которое хотите. Я решил получить все их отзывы, которые заканчиваются на 14 900:

pages = list(range(0, 14900))
pages_list = pages[0:14900:100]

Мы создадим функцию, которая объединит базовый URL-адрес, список полей, которые мы хотим вернуть, схему сортировки (по возрастанию или по убыванию) и смещение для запроса.

Мы возьмем количество страниц, которые хотим просмотреть, а затем для каждых 100 записей создадим новый URL-адрес и запросим данные:

def get_games(url_base, num_pages, fields, collection):

    field_list = "&field_list=" + fields + "&sort=score:desc" + "&offset="

    for page in num_pages:
        url = url_base + field_list + str(page)
        print(url)
        response = requests.get(url, headers=headers).json()
        print(response)
        video_games = response['results']
        for i in video_games:
            collection.insert_one(i)
            print("Data Inserted")

Напомним, что MongoDB хранит данные в формате JSON. По этой причине нам нужно преобразовать наши ответные данные в формат JSON с помощью метода json () .

После того как данные будут преобразованы в JSON, мы получим свойство “результаты” из ответа, так как это та часть, которая на самом деле содержит интересующие нас данные. Затем мы рассмотрим 100 различных результатов и вставим каждый из них в нашу коллекцию с помощью команды insert_one() из PyMongo. Вы также можете поместить их все в список и использовать вместо этого insert_many () .

Давайте теперь вызовем функцию и попросим ее собрать данные:

get_games(review_base, pages_list, review_fields, reviews)

Почему бы нам не проверить, что наши данные были вставлены в нашу базу данных так, как мы этого ожидаем? Мы можем просматривать базу данных и ее содержимое непосредственно с помощью программы Compass:

Мы видим, что данные были правильно вставлены.

Мы также можем сделать некоторые извлечения из базы данных и распечатать их. Для этого мы просто создадим пустой список для хранения ваших записей и используем команду .find() в коллекции “отзывы”.

При использовании функции find из PyMongo поиск также должен быть отформатирован в формате JSON. Параметры, заданные функции find , будут иметь поле и значение.

По умолчанию MongoDB всегда возвращает поле _id (свое собственное уникальное поле ID, а не идентификатор, который мы вытащили из GameSpot), но мы можем сказать ему, чтобы он подавил это, указав 0 ценность. Поля, которые мы хотим вернуть, например поле score в данном случае, должны быть заданы 1 значение:

scores = []

for score in list(reviews.find({}, {"_id":0, "score": 1})):
    scores.append(score)

print(scores[:900])

Вот что было успешно вытащено и напечатано:

[{'score': '10.0'}, {'score': '10.0'}, {'score': '10.0'}, {'score': '10.0'}, {'score': '10.0'}, {'score': '10.0'}, {'score': '10.0'}, {'score': '10.0'} ...

Мы также можем легко преобразовать результаты запроса в фрейм данных с помощью Pandas:

scores_data = pd.DataFrame(scores, index=None)
print(scores_data.head(20))

Вот что было возвращено:

   score
0   10.0
1   10.0
2   10.0
3   10.0
4   10.0
5   10.0
6   10.0
7   10.0
8   10.0
9   10.0
10  10.0
11  10.0
12  10.0
13  10.0
14  10.0
15  10.0
16  10.0
17   9.9
18   9.9
19   9.9

Прежде чем мы начнем анализировать некоторые данные, давайте рассмотрим, как мы могли бы потенциально объединить две коллекции вместе. Как уже упоминалось, GameSpot имеет несколько ресурсов для извлечения данных, и мы можем захотеть получить значения из второй базы данных, такой как база данных Игр.

MongoDB-это база данных NoSQL, поэтому, в отличие от SQL, она не предназначена для обработки отношений между базами данных и объединения полей данных вместе. Однако существует функция, которая может аппроксимировать соединение с базой данных – lookup() .

Функция lookup() имитирует соединение с базой данных, и это можно сделать, указав конвейер, который содержит базу данных, из которой вы хотите объединить элементы, а также поля, которые вы хотите получить как из входных документов ( localField ), так и из документов “from” ( foreignField ).

Наконец, вы выбираете псевдоним для преобразования иностранных документов, и они будут отображаться под этим новым именем в нашей таблице ответов на запросы. Если бы у вас была вторая база данных под названием games и вы хотели бы объединить их вместе в запросе, это можно было бы сделать следующим образом:

pipeline = [{
    '$lookup': {
        'from': 'reviews',
        'localField': 'id',
        'foreignField': 'score',
        'as': 'score'
    }
},]

for doc in (games.aggregate(pipeline)):
    print(doc)

Анализ данных

Теперь мы можем приступить к анализу и визуализации некоторых данных, найденных в нашей недавно созданной базе данных. Давайте убедимся, что у нас есть все функции, необходимые для анализа.

from pymongo import MongoClient
import pymongo
import pandas as pd
from bs4 import BeautifulSoup
import re
from nltk.corpus import stopwords
from wordcloud import WordCloud
import matplotlib.pyplot as plt
from collections import Counter
import string
import en_core_web_sm
import seaborn as sns

Допустим, мы хотим провести некоторый анализ слов, найденных в обзорах игр GameSpot. У нас есть эта информация в нашей базе данных, мы просто должны ее получить.

Мы можем начать с сбора топ-40 (или любого другого числа, которое вы хотите) отзывов из нашей базы данных с помощью функции find () , как и раньше, но на этот раз мы укажем, что хотим сортировать по переменной score и что мы должны сортировать в порядке убывания:

d_name = 'gamespot_reviews'
collection_name = 'gamespot'

client = MongoClient('127.0.0.1', 27017)
db = client[d_name]

reviews = db.reviews
review_bodies = []

for body in list(reviews.find({}, {"_id":0, "body": 1}).sort("score", pymongo.DESCENDING).limit(40)):
    review_bodies.append(body)

Мы превратим этот ответ в фрейм данных Панд и преобразуем его в строку. Затем мы извлекем все значения в теге HTML, содержащем текст обзора, который мы сделаем с помощью BeautifulSoup :

reviews_data = pd.DataFrame(review_bodies, index=None)

def extract_comments(input):
    soup = BeautifulSoup(str(input), "html.parser")
    comments = soup.find_all('p')
    return comments

review_entries = extract_comments(str(review_bodies))
print(review_entries[:500])

См. заявление print , чтобы увидеть, что текст обзора был собран:

[

For anyone who hasn't actually seen the game on a TV right in front of them, the screenshots look too good to be true. In fact, when you see NFL 2K for the first time right in front of you...]

Теперь, когда у нас есть текстовые данные обзора, мы хотим проанализировать их несколькими различными способами. Давайте попробуем получить некоторое представление о том, какие слова обычно используются в топ-40 обзоров. Мы можем сделать это несколькими различными способами:

Однако прежде чем мы сможем провести какой-либо анализ данных, мы должны предварительно обработать их.

Для предварительной обработки данных мы хотим создать функцию фильтрации записей. Текстовые данные по-прежнему полны всевозможных тегов и нестандартных символов, и мы хотим удалить их, получив необработанный текст комментариев обзора. Мы будем использовать регулярные выражения для замены нестандартных символов пробелами.

Мы также используем некоторые стоп-слова из NTLK (очень распространенные слова, которые добавляют мало смысла в наш текст) и удаляем их из нашего текста, создавая список для хранения всех слов, а затем добавляя слова в этот список только в том случае, если их нет в нашем списке стоп-слов.

Облако слов

Давайте возьмем подмножество слов обзора для визуализации в виде корпуса. Если он слишком велик при генерации, это может вызвать некоторые проблемы с облаком слов.

Например, я отфильтровал первые 5000 слов:

stop_words = set(stopwords.words('english'))

def filter_entries(entries, stopwords):

    text_entries = BeautifulSoup(str(entries), "lxml").text
    subbed_entries = re.sub('[^A-Za-z0-9]+', ' ', text_entries)
    split_entries = subbed_entries.split()

    stop_words = stopwords

    entries_words = []

    for word in split_entries:
        if word not in stop_words:
            entries_words.append(word)

    return entries_words

review_words = filter_entries(review_entries, stop_words)
review_words = review_words[5000:]

Теперь мы можем очень легко создать облако слов , используя предварительно созданную библиотеку WordCloud , найденную здесь .

Это облако слов действительно дает нам некоторую информацию о том, какие слова обычно используются в лучших обзорах:

К сожалению, он все еще полон общих слов, поэтому было бы неплохо сделать фильтрацию обзорных слов с помощью схемы фильтрации tf-idf , но для целей этой простой демонстрации этого достаточно.

На самом деле у нас есть некоторая информация о том, о каких концепциях говорится в обзорах игр: игровой процесс, сюжет, персонажи, мир, действие, локации и т. Д.

Мы можем подтвердить для себя, что эти слова обычно встречаются в обзорах игр, посмотрев на один из 40 лучших обзоров, которые мы выбрали: Майк Махарди обзор Uncharted 4 :

Конечно же, в обзоре обсуждаются действия, игровой процесс, персонажи и история.

Размер слов дает нам интуицию о том, как часто слова появляются в этих обзорах, но мы также можем просто подсчитать, как часто появляются определенные слова.

Счетчик

Мы можем получить список наиболее распространенных слов, разделив слова и добавив их в словарь слов вместе с их индивидуальным количеством, которое будет увеличиваться каждый раз, когда будет видно одно и то же слово.

Затем нам просто нужно использовать Counter и функцию most_common() :

def get_word_counts(words_list):
    word_count = {}

    for word in words_list:
        word = word.translate(translator).lower()
        if word not in stop_words:
            if word not in word_count:
                word_count[word] = 1
            else:
                word_count[word] += 1

    return word_count

review_word_count = get_word_counts(review_words)
review_word_count = Counter(review_word_count)
review_list = review_word_count.most_common()
print(review_list)

Вот подсчеты некоторых из наиболее распространенных слов:

[('game', 1231), ('one', 405), ('also', 308), ('time', 293), ('games', 289), ('like', 285), ('get', 278), ('even', 271), ('well', 224), ('much', 212), ('new', 200), ('play', 199), ('level', 195), ('different', 195), ('players', 193) ...]

Распознавание Именованных сущностей

Мы также можем сделать распознавание именованных сущностей с помощью en_core_web_sm , языковой модели, включенной в space . Различные понятия и лингвистические особенности, которые можно обнаружить, перечислены здесь .

Нам нужно захватить список обнаруженных именованных сущностей и понятий из документа (список слов):

doc = nlp(str(review_words))
labels = [x.label_ for x in doc.ents]
items = [x.text for x in doc.ents]

Мы можем распечатать найденные объекты, а также их количество.

# Example of named entities and their categories
print([(X.text, X.label_) for X in doc.ents])

# All categories and their counts
print(Counter(labels))

# Most common named entities
print(Counter(items).most_common(20))

Вот что напечатано:

[('Nintendo', 'ORG'), ('NES', 'ORG'), ('Super', 'WORK_OF_ART'), ('Mario', 'PERSON'), ('15', 'CARDINAL'), ('Super', 'WORK_OF_ART'), ('Mario', 'PERSON'), ('Super', 'WORK_OF_ART') ...]

Counter({'PERSON': 1227, 'CARDINAL': 496, 'ORG': 478, 'WORK_OF_ART': 204, 'ORDINAL': 200, 'NORP': 110, 'PRODUCT': 88, 'GPE': 63, 'TIME': 12, 'DATE': 12, 'LOC': 12, 'QUANTITY': 4 ...]

[('first', 147), ('two', 110), ('Metal', 85), ('Solid', 82), ('GTAIII', 78), ('Warcraft', 72), ('2', 59), ('Mario', 56), ('four', 54), ('three', 42), ('NBA', 41) ...]

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

Мы получим список именованных сущностей/людей, организаций и GPS (местоположения):

def word_counter(doc, ent_name, col_name):
    ent_list = []
    for ent in doc.ents:
        if ent.label_ == ent_name:
            ent_list.append(ent.text)
    df = pd.DataFrame(data=ent_list, columns=[col_name])
    return df

review_persons = word_counter(doc, 'PERSON', 'Named Entities')
review_org = word_counter(doc, 'ORG', 'Organizations')
review_gpe = word_counter(doc, 'GPE', 'GPEs')

Теперь все, что нам нужно сделать, это построить подсчеты с помощью функции:

def plot_categories(column, df, num):
    sns.countplot(x=column, data=df,
                  order=df[column].value_counts().iloc[0:num].index)
    plt.xticks(rotation=-45)
    plt.show()

plot_categories("Named Entities", review_persons, 30)
plot_categories("Organizations", review_org, 30)
plot_categories("GPEs", review_gpe, 30)

Давайте взглянем на графики, которые были сгенерированы.

Как и следовало ожидать от именованных сущностей, большинство возвращаемых результатов – это имена персонажей видеоигр. Это не идеально, так как он неправильно классифицирует некоторые термины, такие как “Xbox”, как именованную сущность, а не организацию, но это все же дает нам некоторое представление о том, какие персонажи обсуждаются в лучших обзорах.

Сюжет организации показывает некоторых правильных разработчиков игр и издателей, таких как Playstation и Nintendo, но он также помечает такие вещи, как “480p”, как организацию.

Выше приведен график для Gps или географических местоположений. Похоже, что “Голливуд” и “Майами” часто всплывают в обзорах игр. (Настройки для игр? Или, может быть, рецензент описывает что-то в игре как голливудский стиль?)

Как вы можете видеть, распознавание именованных сущностей и распознавание понятий не является совершенным, но оно может дать вам некоторое представление о том, какие темы обсуждаются в тексте.

Построение Числовых Значений

Наконец, мы можем попробовать построить числовые значения из базы данных. Давайте получим значения баллов из коллекции отзывов, подсчитаем их, а затем построим график:

scores = []

for score in list(reviews.find({}, {"_id":0, "score": 1})):
    scores.append(score)
scores = pd.DataFrame(scores, index=None).reset_index()

counts = scores['score'].value_counts()

sns.countplot(x="score", data=scores)
plt.xticks(rotation=-90)
plt.show()

Выше приведен график для общего количества приведенных оценок обзора, работающих от 0 до 9,9. Похоже, что наиболее часто задаваемые баллы были 7 и 8, что интуитивно понятно. Семь часто считается средним по десятибалльной шкале оценки.

Вывод

Сбор, хранение, извлечение и анализ данных-это навыки, которые очень востребованы в современном мире, и MongoDB является одной из наиболее часто используемых платформ баз данных NoSQL.

Знание того, как использовать базы данных NoSQL и как интерпретировать данные в них, позволит вам выполнять многие общие задачи анализа данных.