Realizando un Análisis Avanzado de Datos de Eventos de Facebook con una Base de Datos Vectorial

En la actual era digital, los profesionales de todos los sectores deben mantenerse al día con los eventos venideros, conferencias y talleres. Sin embargo, encontrar de manera eficiente eventos que coincidan con los intereses de uno en medio del vasto océano de información en línea presenta un desafío significativo.

Este blog presenta una solución innovadora a este desafío: una aplicación integral diseñada para raspar datos de eventos de Facebook y analizar los datos rastreados utilizando MyScale. Si bien MyScale está comúnmente asociado con la pila tecnológica RAG o utilizado como base de datos vectorial, sus capacidades se extienden más allá de estos ámbitos. Utilizaremos MyScale para el análisis de datos, aprovechando su funcionalidad de búsqueda vectorial para analizar eventos que son semánticamente similares, lo que proporciona mejores resultados e insights.

Puede notar que Grok AI utilizó la base de datos vectorial Qdrant como motor de búsqueda para recuperar información en tiempo real de X (anteriormente conocido como Twitter) datos. También puede evaluar el poder de las bases de datos vectoriales de esta manera con MyScale integrando MyScale con otras plataformas como Apify para mejorar las tareas diarias a través del desarrollo de aplicaciones personalizadas simples.

Así que en este blog, desarrollemos una aplicación que solo toma el nombre de una ciudad como entrada y raspa todos los eventos relacionados de Facebook. Posteriorment, realizaremos el análisis de datos y la búsqueda semántica utilizando las avanzadas capacidades vectoriales de SQL de MyScale.

Herramientas y Tecnologías

Usaremos varias herramientas, incluyendo Apify, MyScale y OpenAI, para desarrollar esta aplicación útil.

  • Apify: Una plataforma popular de web scraping y automatización que simplifica significativamente el proceso de recopilación de datos. Proporciona la capacidad de raspar datos y, posteriormente, alimentarlo a los LLMs. Esto nos permite entrenar a los LLMs con datos en tiempo real y desarrollar aplicaciones.
  • MyScale: MyScale es una base de datos vectorial SQL que utilizamos para almacenar y procesar tanto datos estructurados como no estructurados de manera optimizada.
  • OpenAI: Utilizaremos el modelo text-embedding-3-small de OpenAI para obtener los embeddings del texto y luego guardar esos embeddings en MyScale para el análisis de datos y la búsqueda semántica.

Cómo Configurar MyScale y Apify

Para comenzar a configurar MyScale y Apify, necesitarás crear un nuevo directorio y un archivo Python. Puedes hacer esto abriendo tu terminal o línea de comandos y escribiendo los siguientes comandos:

Shell

 

mkdir MyScale
cd MyScale
touch main.ipynb

Instalemos los paquetes. Copia el comando a continuación y pégalo en tu terminal. Estos paquetes proporcionarán las herramientas y bibliotecas que necesitamos para desarrollar nuestra aplicación.

Shell

 

pip install openai apify-client clickhouse-connect pandas numpy

Esto debería instalar todas las dependencias en tu sistema. Para confirmar que todo está instalado correctamente, puedes ingresar el siguiente comando en tu terminal.

Shell

 

pip freeze | egrep '(openai|apify-client|clickhouse-connect|pandas|numpy)'

Esto debería incluir todas las dependencias instaladas con sus versiones. Si detectas alguna dependencia faltante, es posible que debas volver a ejecutar el comando de instalación para ese paquete específico. Ahora, estamos listos para escribir nuestro código después de las instalaciones.

Nota: Estaremos trabajando en una libreta de Python. Considera cada bloque de código como una celda de la libreta.

Cómo Recopilar Datos con Apify

Ahora, utilizaremos la API de Apify para recopilar datos de eventos de la ciudad de Nueva York utilizando raspador de Eventos de Facebook

Python

 

     import pandas as pd
from apify_client import ApifyClient
# Inicializar el ApifyClient con tu token de API
client = ApifyClient("Enter_your_apify_key_here")

# Preparar la entrada del Actor
run_input = {
    "searchQueries": ["Sport New York"],
    "startUrls": [],
    "maxEvents": 50,
}

# Ejecutar el Actor y esperar a que finalice
run = client.actor("UZBnerCFBo5FgGouO").call(run_input=run_input)

df_columns = ['Name', 'Datetime', 'Description', 'Users_Going', 'Users_Interested', 'Users_Responded', 'City', 'Organized_By', 'Street_Address']
dataframe1 = pd.DataFrame(columns=df_columns)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    # Usar una comprensión de diccionario para reemplazar valores None con una cadena vacía
    row = {
        'Name': item.get('name', ''),
        'Datetime': item.get('dateTimeSentence', ''),
        'Description': item.get('description', ''),
        'Users_Going': item.get('usersGoing', ''),
        'Users_Interested': item.get('usersInterested', ''),
        'Users_Responded': item.get('usersResponded', ''),
        'City': item.get('location', {}).get('city', '') if item.get('location') else '',
        'Organized_By': item.get('organizedBy', ''),
        'Street_Address': item.get('location', {}).get('streetAddress', '') if item.get('location') else ''
    }
    # Asegurar que todos los valores None sean reemplazados por una cadena vacía
    row = {k: (v if v is not None else '') for k, v in row.items()}
    dataframe1 = dataframe1._append(row, ignore_index=True)

# Limpiar los datos
dataframe1['Description'] = dataframe1['Description'].replace('\\n', '', regex=True)

Este script nos proporciona los detalles de los próximos eventos en forma de DataFrame de pandas.

Nota: No olvides agregar tu clave de API de Apify en el script anterior. Puedes encontrar tu token de API en la página de Integraciones en la Consola de Apify.

Preprocesamiento de Datos

Cuando recopilamos datos en bruto, estos vienen en varios formatos. En este script, llevaremos las fechas de los eventos a un formato único para que nuestro filtrado de datos pueda realizarse de manera más eficiente.

Python

 

     # Importar bibliotecas necesarias para manipulación de datos y análisis de fechas
import pandas as pd
import numpy as np
from datetime import datetime
from dateutil import parser

# Función para analizar cadenas de fecha que pueden representar un rango o una sola fecha
def parse_dates(date_str):
    # Verificar si la cadena de fecha contiene un guión, indicando un rango
    if '-' in date_str:
        parts = date_str.split('-')
        # Si la cadena se divide en dos partes, es un rango válido
        if len(parts) == 2:
            try:
                # Analizar las fechas de inicio y fin, formateándolas en un formato legible
                start_date = parser.parse(parts[0], fuzzy=True).strftime('%a, %b %d')
                end_date = parser.parse(parts[1], fuzzy=True).strftime('%a, %b %d')
                return start_date, end_date
            except ValueError:
                # En caso de error de análisis, no hacer nada (se manejará más abajo)
                pass  
    # Si no es un rango o si el análisis del rango falló, intentar analizar como una sola fecha
    try:
        parsed_date = parser.parse(date_str, fuzzy=True)
        # Formatear la fecha única para start_date y formatear de manera diferente para end_date
        start_date = parsed_date.strftime('%a, %b %d AT %I:%M %p EDT')
        end_date = parsed_date.strftime('%a, %b %d')  # Omitting time for end_date
        return start_date, end_date
    except ValueError:
        # Devolver NaN para ambas fechas si el análisis falla
        return np.nan, np.nan  

# Función para extraer fecha detallada, hora y día de una cadena de fecha
def extract_date_time_day(date_str):
    try:
        # Analizar la cadena de fecha, permitiendo cierta flexibilidad en el formato de entrada
        parsed_date = parser.parse(date_str, fuzzy=True)
        # Extraer y formatear las partes de fecha, hora y día
        date = parsed_date.strftime('%Y-%m-%d')
        day = parsed_date.strftime('%a')
        # Determinar si la cadena original incluía un componente de hora
        time_component = parsed_date.strftime('%I:%M %p') not in date_str
        time = parsed_date.strftime('%H:%M:%S') if not time_component else np.nan
    except ValueError:
        # Si el análisis falla, establecer fecha, hora y día como NaN
        date, time, day = np.nan, np.nan, np.nan
    
    return date, time, day

# Aplicar la función parse_dates a través del dataframe, creando nuevas columnas para las fechas de inicio y fin
dataframe1[['Start_Date', 'End_Date']] = dataframe1.apply(lambda row: pd.Series(parse_dates(row['Datetime'])), axis=1)

# Eliminar filas donde Start_Date es NaN, indicando que el análisis no tuvo éxito
dataframe = dataframe1.dropna(subset=['Start_Date'])

# Aplicar extract_date_time_day para dividir las fechas de inicio y fin en columnas separadas para fecha, hora y día
dataframe['Start_Date'], dataframe['Start_Time'], dataframe['Start_Day'] = zip(*dataframe['Start_Date'].apply(extract_date_time_day))
dataframe['End_Date'], _, dataframe['End_Day'] = zip(*dataframe['End_Date'].apply(extract_date_time_day))

# Eliminar la columna original 'Datetime' ya que ya no se necesita
dataframe=dataframe.drop(['Datetime'], axis=1)

# Convertir 'Start_Date' y 'End_Date' al formato datetime, extrayendo solo la parte de la fecha
dataframe['Start_Date'] = pd.to_datetime(dataframe['Start_Date']).dt.date
dataframe['End_Date'] = pd.to_datetime(dataframe['End_Date']).dt.date

# Convertir 'Start_Time' al formato datetime, conservando la información de la hora
dataframe['Start_Time'] = pd.to_datetime(dataframe['Start_Time'])

Este fragmento de código utiliza pandas junto con los paquetes datetime y dateutil de Python para formatear los datos.

Generación de Inserciones

Para comprender y buscar eventos de manera profunda, generaremos inserciones a partir de sus descripciones utilizando el text-embedding-3-small. Estas inserciones capturan la esencia semántica de cada evento, ayudando a que la aplicación devuelva mejores resultados.

Python

 

     # Importar la biblioteca OpenAI para acceso a la API.
from openai import OpenAI 
# Inicializar el cliente de OpenAI con una clave de API.
openai_client = OpenAI(api_key="your_openai_api_key_here")
# Función para obtener inserciones de texto 
def get_embedding(text, model="text-embedding-3-small"):
    return openai_client.embeddings.create(input=text, model=model).data
embeddings = get_embedding(dataframe["Description"].tolist())
# Extraer vectores de inserción del objeto de inserciones
vectors = [embedding.embedding for embedding in embeddings]
array = np.array(vectors)
embeddings_series = pd.Series(list(array))
# Agregar inserciones como una nueva columna en el DataFrame.
dataframe['Description_Embeddings'] = embeddings_series

Ahora, insertaremos el nuevo DataFrame con inserciones en MyScale.

Conexión con MyScale

Como se discutió al inicio, utilizaremos MyScale como base de datos vectorial para almacenar y gestionar datos. Aquí, nos conectaremos a MyScale en preparación para el almacenamiento de datos.

Python

 

     import clickhouse_connect
client = clickhouse_connect.get_client(
    host='host_name_here',
    port=443,
    username='username_here',
    password='passwd_here'
)

Esta configuración de conexión garantiza que nuestra aplicación pueda comunicarse con MyScale y utilizar el poder de SQL para la manipulación y análisis de datos.

Nota: Vea Detalles de Conexión para obtener más información sobre cómo conectarse al clúster de MyScale.

Crear Tablas e Índices Utilizando MyScale

Ahora crearemos una tabla de acuerdo con nuestro DataFrame. Todos los datos se almacenarán en esta tabla, incluidas las inserciones.

Python

 

     client.command("""
    CREATE TABLE default.Events (
    Name String,
    Description String,
    Users_Going Int64,
    Users_Interested Int64,
    Users_Responded Int64,
    City String,
    Organized_By String,
    Street_Address String,
    Start_Date Date32,
    End_Date Nullable(Date32),
    Start_Time Nullable(DateTime64),
    Start_Day String,
    End_Day String,
    Description_Embeddings Array(Float32),
    CONSTRAINT check_data_length CHECK length(Description_Embeddings) = 1536
    ) ENGINE = MergeTree()
    ORDER BY (Name);
    """)

Las declaraciones SQL anteriores crean una tabla llamada Events en el clúster. La CONSTRAINT garantiza que todos los vectores de incrustación tengan la misma longitud 1536.

Almacenamiento de los Datos y Creación de un Índice en MyScale

En este paso, insertamos los datos procesados en MyScale. Esto implica la inserción por lotes de los datos para garantizar un almacenamiento y recuperación eficientes.

Python

 

     batch_size = 10  # Adjust based on your needs

num_batches = len(dataframe) // batch_size

for i in range(num_batches):
    start_idx = i * batch_size
    end_idx = start_idx + batch_size
    batch_data = dataframe[start_idx:end_idx]
    # print(batch_data["Description_Embeddings"])
    client.insert("default.Events", batch_data.to_records(index=False).tolist(), column_names=batch_data.columns.tolist())
    print(f"Batch {i+1}/{num_batches} inserted.")

client.command("""
ALTER TABLE default.Events
    ADD VECTOR INDEX vector_index Description_Embeddings
    TYPE MSTG
""")

Usando pandas, el código anterior transfiere eficientemente nuestro conjunto de datos preparado a la base de datos de MyScale.

Análisis de Datos con MyScale

Finalmente, utilizamos las capacidades analíticas de MyScale para realizar análisis y habilitar la búsqueda semántica. Ejecutando consultas SQL, podemos analizar eventos basándonos en temas, ubicaciones y fechas. Entonces, intentemos escribir algunas consultas.

Consulta SQL simple

Intentemos primero obtener los 10 primeros resultados de la tabla.

Python

 

     results=client.query("""
        SELECT Name,Description FROM default.Events LIMIT 10
    """)
for row in results.named_results():
        print(row["Name"])
        print(row['Description'])

Esta consulta simplemente devolverá los 10 primeros resultados de la tabla events.

Descubrir Eventos por Relevancia Semántica

Intentemos encontrar los 10 próximos eventos con una vibra similar a un evento de referencia, como este: “Uno de los Shows Más Largos en el País – Operando desde 1974 …AHORA nuestro 50º AÑO !!! Nuestro Schenectady”. Esto se logra comparando las incrustaciones semánticas de las descripciones de eventos, asegurando un ajuste en temas y emociones.

Python

 

embeddings=get_embedding(["One of the Longest Running Shows in the Country - Operating since 1974 ...NOW our 50th YEAR !!!Our Schenectady"])
embedding=embeddings[0].embedding
results = client.query(f"""
        SELECT Name, Description,
        distance(Description_Embeddings, {embedding}) as dist FROM default.Events ORDER BY dist LIMIT 10
    """)
for row in results.named_results():
        print("Title of the event  ", row["Name"])
        print("Description of the event  ", row['Description'])
        print("Distance : ", row["dist"])

Eventos de Tendencia por Popularidad

Esta consulta clasifica los 10 eventos principales por el número de asistentes e interesados, resaltando eventos populares de festivales en grandes ciudades a conferencias importantes. Es ideal para aquellos que buscan unirse a grandes y energéticos eventos colectivos.

Python

 

     results = client.query(f"""
        SELECT Name, City, Users_Going, Users_Interested, Users_Responded
        FROM default.Events
        ORDER BY Users_Going DESC, Users_Interested DESC
        LIMIT 10
    """)
for row in results.named_results():
        print("Event Name  ", row["Name"])
        print("City ", row["City"])
        print("Users Going ", row["Users_Going"])
        print("Interested Users ", row["Users_Interested"])

Eventos Locales Populares en Nueva York

Al combinar relevancia y popularidad, esta consulta identifica eventos similares en la Ciudad de Nueva York relacionados con un evento específico y los clasifica por asistencia, ofreciendo una lista cuidadosamente seleccionada de eventos que reflejan la vibrante cultura de la ciudad y atraen el interés local.

Python

 

     embeddings=get_embedding(["One of the Longest Running Shows in the Country - Operating since 1974 ...NOW our 50th YEAR !!!Our Schenectady"])
embeddi=embeddings[0].embedding
results = client.query(f"""
        SELECT Name,City, Description, Users_Going,distance(Description_Embeddings, {embeddi}) as dist
        FROM default.Events
        WHERE City LIKE '%New York%' and dist < 1.5
        ORDER BY Users_Going DESC,dist
        LIMIT 10
    """)
for row in results.named_results():
        print("Event Name  ", row["Name"])
        print("Description ", row["Description"])
        print("Users Going ", row["Users_Going"])

Organizadores de Eventos Líderes

Esta consulta clasifica los 10 principales organizadores de eventos por el número total de asistentes e interesados, resaltando a aquellos que sobresalen en la creación de eventos convincentes y en la atracción de grandes audiencias. Proporciona información para planificadores de eventos y asistentes interesados en eventos de primer nivel.

Python

 

     # ¿Qué cliente ha atraído el mayor número de usuarios 
results = client.query(f"""
       SELECT Organized_By, SUM(Users_Going + Users_Interested) AS Total_Users
        FROM default.Events
        GROUP BY Organized_By
        ORDER BY Total_Users DESC
        Limit 10
    """)
for row in results.named_results():
        print("Event Name  ", row["Organized_By"])
        print("Total_Users ", row["Total_Users"])

Implementar RAG

Previamente, hemos explorado MyScale para el análisis de datos, resaltando sus capacidades para mejorar nuestros flujos de trabajo de datos. Avanzando, daremos un paso adelante implementando Retrieval-Augmented Generation (RAG), un marco innovador que combina una base de conocimientos externa con LLMs. Este paso te ayudará a comprender mejor tus datos y encontrar insights más detallados. A continuación, verás cómo usar RAG con MyScale, lo que hará que trabajar con datos sea más interesante y productivo.

Python

 

     from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate

query="Can you please suggest me some events related to basketball"
# Utiliza el método get_embedding definido anteriormente, acepta una lista de oraciones
embeddings=get_embedding([query])
embeddings=embeddings[0].embedding
results = client.query(f"""
        SELECT Name, City, Users_Going, Description, distance(Description_Embeddings, {embeddings}) as dist
        FROM default.Events
        ORDER BY Users_Going DESC,dist
        LIMIT 5
    """)
PROMPT_TEMPLATE = """
Your objective is to formulate a response to a question using only the information provided below:
{context}
---
Your task is to carefully analyze the provided context and provide an answer to the following question based solely on the information given:
{question}
"""
# Combina las descripciones de los resultados principales. 
descriptions = [row["Description"] for row in results.named_results()]
context_text = "\n\n---\n\n".join(descriptions)
prompt_template = ChatPromptTemplate.from_template(PROMPT_TEMPLATE)
prompt = prompt_template.format(context=context_text, question=query)
model = ChatOpenAI(openai_api_key="your_api_key_here")
response_text = model.predict(prompt)
formatted_response = f"Response: {response_text}\n"
print(formatted_response)

A lo largo de este blog, hemos observado que MyScale es mucho más que una base de datos vectorial que se puede utilizar para desarrollar todo tipo de aplicaciones. Podemos usarlo como una base de datos SQL simple o para aplicaciones de inteligencia artificial avanzada, cubriendo la mayor parte del dominio del desarrollo. Te animamos a que lo pruebes y explores las características avanzadas inscribiéndote en la capa gratuita y obteniendo 5 millones de almacenamiento vectorial gratuito.

Conclusión

Hemos explorado las habilidades y funcionalidades de MyScale con Apify Scraper a través del proceso de desarrollo de una aplicación de análisis de eventos. MyScale ha demostrado sus excepcionales capacidades en búsqueda de vectores de alto rendimiento, manteniendo todas las funcionalidades de las bases de datos SQL, lo que ayuda a los desarrolladores a realizar búsquedas semánticas utilizando la sintaxis SQL familiar con mucha mejor velocidad y precisión.

Las capacidades de MyScale no se limitan a esta aplicación: puedes adoptarla para desarrollar cualquier aplicación de inteligencia artificial utilizando el método RAG

Si tienes algún comentario o sugerencia, por favor contáctanos.

Source:
https://dzone.com/articles/performing-advanced-facebook-event-data-analysis-w