Análisis de datos de la API con MongoDB, Seaborn y Matplotlib

    Introducción

    Una habilidad comúnmente solicitada para puestos de desarrollo de software es la experiencia con bases de datos NoSQL, incluido MongoDB. Este tutorial explorará la recopilación de datos utilizando una API, almacenándolos en una base de datos MongoDB y haciendo algunos análisis de los datos.

    Sin embargo, antes de saltar al código, tomemos un momento para repasar MongoDB y las API, para asegurarnos de que entendemos cómo manejaremos los datos que recopilamos.

    MongoDB y NoSQL

    MongoDB es una forma de base de datos NoSQL, que permite el almacenamiento de datos en formas no relacionales. Las bases de datos NoSQL se comprenden mejor comparándolas con sus progenitores / rivales: las bases de datos SQL.

    SQL significa Structure Query Language y es un tipo de herramienta de gestión de bases de datos relacionales. Una base de datos relacional es una base de datos que almacena datos como una serie de claves y valores, y cada fila de una tabla de datos tiene su propia clave única. Los valores de la base de datos se pueden recuperar buscando la clave correspondiente. Así es como las bases de datos SQL almacenan datos, pero las bases de datos NoSQL pueden almacenar datos de formas no relacionales.

    NoSQL significa “No solo SQL”, que se refiere al hecho de que aunque las consultas al estilo SQL se pueden realizar con sistemas NoSQL, también pueden hacer cosas con las que las bases de datos SQL luchan. Las bases de datos NoSQL tienen una gama más amplia de opciones de almacenamiento para los datos que manejan y, debido a que los datos están relacionados de forma menos rígida, se pueden recuperar de más formas, lo que agiliza algunas operaciones. Las bases de datos NoSQL pueden simplificar la adición de nodes o campos en comparación con las bases de datos SQL.

    Hay muchos marcos NoSQL populares, incluidos MongoDB , OrientDB , InfinityDB , Aerospike y CosmosDB . MongoDB es un marco NoSQL específico que almacena datos en forma de documentos, actuando como una base de datos orientada a documentos.

    MongoDB es popular debido a su versatilidad y fácil integración en la nube, y se puede usar para una amplia variedad de tareas. MongoDB almacena datos en formato JSON. Las consultas de las bases de datos de MongoDB también se realizan en formato JSON, y debido a que los comandos de almacenamiento y recuperación se basan en el formato JSON, es fácil recordar y componer comandos para MongoDB.

    ¿Qué son las API?

    Las API son interfaces de programación de aplicaciones y su función es facilitar las comunicaciones entre clientes y servidores. Las API se crean a menudo para facilitar la recopilación de información por parte de aquellos que tienen menos experiencia con el lenguaje utilizado por los desarrolladores de la aplicación.

    Las API también pueden ser métodos útiles para controlar el flujo de información desde un servidor, alentando a los interesados ​​en acceder a su información a utilizar canales oficiales para hacerlo, en lugar de construir un raspador web. Las API más comunes para sitios web son las API REST (Representational State Transfer), que utilizan solicitudes y respuestas HTTP estándar para enviar, recibir, eliminar y modificar datos. Accederemos a una API REST y realizaremos nuestras solicitudes en formato HTTP para este tutorial.

    ¿Qué API usaremos?

    La API que usaremos es la API de GameSpot. GameSpot es uno de los sitios de revisión de videojuegos más grandes de la web, y se puede acceder a su API aquí .

    Preparándose

    Antes de comenzar, debe asegurarse de obtener una clave API para GameSpot. También debe asegurarse de tener MongoDB y su biblioteca Python instalados. Las instrucciones de instalación de Mongo se pueden encontrar aquí .

    La biblioteca PyMongo se puede instalar simplemente ejecutando:

    $ pip install pymongo
    

    Es posible que también desee instalar el programa MongoDB Compass , que le permite visualizar y editar fácilmente el aspecto de las bases de datos MongoDB con una GUI.

    Creando la base de datos MongoDB

    Ahora podemos comenzar nuestro proyecto creando la base de datos MongoDB. Primero, manejaremos nuestras importaciones. Importaremos el MongoClientde PyMongo, así como requestsy pandas:

    from pymongo import MongoClient
    import requests
    import pandas as pd
    

    Al crear una base de datos con MongoDB, primero debemos conectarnos al cliente y luego usar el cliente para crear la base de datos que deseamos:

    client = MongoClient('127.0.0.1', 27017)
    db_name="gamespot_reviews"
    
    # connect to the database
    db = client[db_name]
    

    MongoDB puede almacenar múltiples colecciones de datos dentro de una sola base de datos, por lo que también necesitamos definir el nombre de la colección que queremos usar:

    # open the specific collection
    reviews = db.reviews
    

    Eso es. Se ha creado nuestra base de datos y colección y estamos listos para comenzar a insertar datos en ella. Eso fue bastante simple, ¿no?

    Usando la API

    Ahora estamos listos para utilizar la API de GameSpot para recopilar datos. Si echamos un vistazo a la documentación de la API aquí , podemos determinar el formato en el que deben estar nuestras solicitudes.

    Necesitamos hacer nuestras solicitudes a una URL base que contenga nuestra clave API. La API de GameSpot tiene varios recursos propios de los que podemos extraer datos. Por ejemplo, tienen un recurso que enumera datos sobre juegos como la fecha de lanzamiento y las consolas.

    Sin embargo, estamos interesados ​​en su recurso para reseñas de juegos y extraeremos algunos campos específicos del recurso API. Además, GameSpot te pide que especifiques un identificador de agente de usuario único al realizar solicitudes, lo que haremos mediante la creación de un encabezado que pasaremos a la requestsfunción:

    headers = {
        "user_agent": "[YOUR IDENTIFIER] API Access"
    }
    
    games_base = "http://www.gamespot.com/api/reviews/?api_key=[YOUR API KEY HERE]&format=json"
    

    Vamos a querer los siguientes campos de datos: id, title, score, deck, body, good, bad:

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

    GameSpot solo permite la devolución de 100 resultados a la vez. Por esta razón, para obtener una cantidad decente de revisiones para analizar, necesitaremos crear un rango de números y recorrerlos, obteniendo 100 resultados a la vez.

    Puede seleccionar cualquier número que desee. Elegí obtener todas sus reseñas, que tienen un límite de 14,900:

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

    Vamos a crear una función que une la URL base, la lista de campos que queremos devolver, un esquema de clasificación (ascendente o descendente) y el desplazamiento de la consulta.

    Tomaremos la cantidad de páginas que queremos recorrer y luego, por cada 100 entradas, crearemos una nueva URL y solicitaremos los datos:

    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")
    

    Recuerde que MongoDB almacena datos como JSON. Por esa razón, necesitamos convertir nuestros datos de respuesta al formato JSON usando el json()método.

    Después de que los datos se hayan convertido en JSON, obtendremos la propiedad “results” de la respuesta, ya que esta es la parte que realmente contiene nuestros datos de interés. Luego insert_one()revisaremos los 100 resultados diferentes e insertaremos cada uno de ellos en nuestra colección usando el comando de PyMongo. También puede ponerlos todos en una lista y usarlos insert_many()en su lugar.

    Ahora llamemos a la función y hagamos que recopile los datos:

    get_games(review_base, pages_list, review_fields, reviews)
    

    ¿Por qué no verificamos que nuestros datos se hayan insertado en nuestra base de datos como lo esperamos? Podemos ver la base de datos y su contenido directamente con el programa Compass:

    Podemos ver que los datos se han insertado correctamente.

    También podemos realizar algunas recuperaciones de bases de datos e imprimirlas. Para hacer eso, crearemos una lista vacía para almacenar nuestras entradas y usaremos el .find()comando en la colección “reviews”.

    Al usar la findfunción de PyMongo, la recuperación también debe formatearse como JSON. Los parámetros dados a la findfunción tendrán un campo y un valor.

    De forma predeterminada, MongoDB siempre devuelve el _idcampo (su propio campo de ID único, no el ID que extrajimos de GameSpot), pero podemos decirle que lo suprima especificando un 0valor. Los campos que queremos devolver, como el scorecampo en este caso, deben recibir un 1valor:

    scores = []
    
    for score in list(reviews.find({}, {"_id":0, "score": 1})):
        scores.append(score)
    
    print(scores[:900])
    

    Esto es lo que se extrajo e imprimió con éxito:

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

    También podemos convertir los resultados de la consulta en un marco de datos fácilmente usando Pandas:

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

    Esto es lo que se devolvió:

       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
    

    Antes de comenzar a analizar algunos de los datos, tomemos un momento para ver cómo podríamos potencialmente unir dos colecciones. Como se mencionó, GameSpot tiene múltiples recursos para extraer datos, y es posible que deseemos obtener valores de una segunda base de datos como la base de datos de Juegos.

    MongoDB es una base de datos NoSQL, por lo que, a diferencia de SQL, no tiene la intención de manejar las relaciones entre bases de datos y unir campos de datos. Sin embargo, hay una función que puede aproximarse a una base de datos de unirse – lookup().

    La lookup()función imita una unión a una base de datos y se puede realizar especificando una canalización, que contiene la base de datos desde la que desea unir elementos, así como los campos que desea tanto de los documentos de entrada ( localField) como de los documentos “de” ( foreignField).

    Finalmente, elige un apodo para convertir los documentos extranjeros y se mostrarán bajo este nuevo nombre en nuestra tabla de respuesta a la consulta. Si tuviera una segunda base de datos llamada gamesy quisiera unirlas en una consulta, podría hacerlo así:

    pipeline = [{
        '$lookup': {
            'from': 'reviews',
            'localField': 'id',
            'foreignField': 'score',
            'as': 'score'
        }
    },]
    
    for doc in (games.aggregate(pipeline)):
        print(doc)
    

    Analizando los datos

    Ahora podemos analizar y visualizar algunos de los datos que se encuentran dentro de nuestra base de datos recién creada. Asegurémonos de tener todas las funciones que necesitaremos para el análisis.

    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
    

    Digamos que queremos hacer un análisis de las palabras que se encuentran en las reseñas de juegos de GameSpot. Tenemos esa información en nuestra base de datos, solo tenemos que obtenerla.

    Podemos comenzar recopilando las 40 reseñas principales (o el número que desee) de nuestra base de datos utilizando la find()función como antes, pero esta vez especificaremos que queremos ordenar por scorevariable y que ordenaremos en orden descendente:

    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)
    

    Convertiremos esa respuesta en un marco de datos de Pandas y lo convertiremos en una cadena. Luego, extraeremos todos los valores dentro de la <p>etiqueta HTML que contiene el texto de revisión, lo que haremos con 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])
    

    Consulte la printdeclaración para ver que se ha recopilado el texto de revisión:

    [<p>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...]
    

    Ahora que tenemos los datos del texto de revisión, queremos analizarlos de varias formas diferentes. Intentemos tener algo de intuición sobre qué tipo de palabras se usan comúnmente en las 40 reseñas principales. Podemos hacer esto de varias formas diferentes:

    Sin embargo, antes de que podamos hacer cualquier análisis de los datos, tenemos que preprocesarlos.

    Para preprocesar los datos, queremos crear una función para filtrar las entradas. Los datos de texto todavía están llenos de todo tipo de etiquetas y caracteres no estándar, y queremos eliminarlos obteniendo el texto sin formato de los comentarios de revisión. Usaremos expresiones regulares para sustituir los caracteres no estándar con espacios en blanco.

    También usaremos algunas palabras vacías de NTLK (palabras muy comunes que agregan poco significado a nuestro texto) y las eliminaremos de nuestro texto creando una lista para contener todas las palabras y luego agregando palabras a esa lista solo si no están en nuestra lista de palabras vacías.

    Nube de palabras

    Tomemos un subconjunto de las palabras de revisión para visualizarlas como un corpus. Si es demasiado grande al generarlo, puede causar algunos problemas con la nube de palabras.

    Por ejemplo, he filtrado las primeras 5000 palabras:

    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:]
    

    Ahora podemos crear una nube de palabras muy fácilmente utilizando una biblioteca de WordCloud prefabricada que se encuentra aquí .

    Esta nube de palabras nos brinda información sobre qué tipo de palabras se usan comúnmente en las reseñas principales:

    Desafortunadamente, todavía está lleno de palabras comunes, por lo que sería una buena idea filtrar las palabras de revisión con un esquema de filtrado tf-idf, pero para los propósitos de esta simple demostración, esto es suficientemente bueno.

    De hecho, tenemos alguna información sobre los tipos de conceptos de los que se habla en las reseñas de juegos: jugabilidad, historia, personajes, mundo, acción, ubicaciones, etc.

    Podemos confirmar por nosotros mismos que estas palabras se encuentran comúnmente en las reseñas de juegos al mirar una de las 40 reseñas principales que seleccionamos: la reseña de Mike Mahardy de Uncharted 4 :

    Efectivamente, la revisión analiza la acción, el juego, los personajes y la historia.

    El tamaño de las palabras nos da una idea de la frecuencia con la que aparecen las palabras en estas reseñas, pero también podemos contar la frecuencia con la que aparecen ciertas palabras.

    Mostrador

    Podemos obtener una lista de las palabras más comunes dividiendo las palabras y agregándolas a un diccionario de palabras junto con su recuento individual, que se incrementará cada vez que se vea la misma palabra.

    Entonces solo necesitamos usar Countery la most_common()función:

    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)
    

    Aquí está el recuento de algunas de las palabras más comunes:

    [('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) ...]
    

    Reconocimiento de entidad nombrada

    También podemos hacer el reconocimiento de entidades con nombre usando en_core_web_smun modelo de lenguaje incluido con spaCy . Aquí se enumeran los diversos conceptos y características lingüísticas que se pueden detectar .

    Necesitamos tomar la lista de entidades y conceptos nombrados detectados del documento (lista de palabras):

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

    Podemos imprimir las entidades encontradas, así como un recuento de las entidades.

    # 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))
    

    Esto es lo que está impreso:

    [('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) ...]
    

    Digamos que queremos trazar los términos reconocidos más comunes para diferentes categorías, como personas y organizaciones. Solo necesitamos crear una función para obtener los recuentos de las diferentes clases de entidades y luego usarla para obtener las entidades que deseamos.

    Obtendremos una lista de entidades / personas, organizaciones y GPE (ubicaciones) nombradas:

    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')
    

    Ahora todo lo que tenemos que hacer es graficar los conteos con una función:

    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)
    

    Echemos un vistazo a los gráficos que se generaron.

    Como era de esperar de las entidades nombradas, la mayoría de los resultados devueltos son nombres de personajes de videojuegos. Esto no es perfecto, ya que clasifica erróneamente algunos términos como “Xbox” como una entidad con nombre en lugar de una organización, pero esto aún nos da una idea de qué personajes se discuten en las principales críticas.

    La trama de la organización muestra algunos desarrolladores y editores de juegos adecuados como Playstation y Nintendo, pero también etiqueta cosas como “480p” como una organización.

    Arriba está el gráfico de las GPE o ubicaciones geográficas. Parece que “Hollywood” y “Miami” aparecen a menudo en las reseñas de juegos. (¿Configuración para juegos? ¿O tal vez el crítico está describiendo algo dentro del juego como estilo Hollywood?)

    Como puede ver, llevar a cabo el reconocimiento de entidades con nombre y el reconocimiento de conceptos no es perfecto, pero puede darle algo de intuición sobre qué tipo de temas se tratan en un cuerpo de texto.

    Trazar valores numéricos

    Finalmente, podemos intentar trazar valores numéricos de la base de datos. Vamos a obtener los valores de puntuación de la colección de reseñas, contarlos y luego graficarlos:

    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()
    

    Arriba está el gráfico del número total de puntuaciones de revisión otorgadas, que van de 0 a 9,9. Parece que los puntajes más comunes fueron 7 y 8, lo que tiene sentido intuitivamente. Siete a menudo se considera promedio en una escala de revisión de diez puntos.

    Conclusión

    Recopilar, almacenar, recuperar y analizar datos son habilidades que tienen una gran demanda en el mundo actual, y MongoDB es una de las plataformas de bases de datos NoSQL más utilizadas.

    Saber cómo utilizar las bases de datos NoSQL y cómo interpretar los datos en ellas le permitirá realizar muchas tareas comunes de análisis de datos.

    Etiquetas:

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *