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 鈥嬧媏n 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 鈥嬧媏n 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 *