Obtén estadísticas a partir de datos estructurados y no estructurados con el paquete BigQuery DataFrames compatible con IA

1. Descripción general

En este lab, usarás BigQuery DataFrames desde un notebook de Python en BigQuery Studio para obtener estadísticas a partir de datos con Python. Usa la IA generativa de Google para analizar y visualizar datos de texto no estructurado.

Crearás un notebook de Python para categorizar y resumir una base de datos pública de quejas de clientes. Esto se puede adaptar para funcionar en cualquier dato de texto no estructurado.

Objetivos

En este lab, aprenderás a realizar las siguientes tareas:

  • Activa y usa notebooks de Python en BigQuery Studio
  • Conéctate a BigQuery con el paquete BigQuery DataFrames
  • Crea incorporaciones a partir de datos de texto no estructurados con BigQuery ML y la conexión a un extremo de incorporación de texto en Vertex AI
  • Cómo usar las incorporaciones de clústeres con BigQuery ML
  • Resume clústeres con un LLM a través de BigQuery ML

2. Requisitos

  • Un navegador, como Chrome o Firefox.
  • Un proyecto de Google Cloud con la facturación habilitada.

Antes de comenzar

Para seguir las instrucciones de este codelab, necesitarás un proyecto de Google Cloud con BigQuery Studio habilitado y una cuenta de facturación conectada.

  1. En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud.
  2. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud. Obtén información para verificar si la facturación está habilitada en un proyecto.
  3. Sigue las instrucciones para habilitar BigQuery Studio para la administración de recursos.

Prepara BigQuery Studio

Crea un notebook vacío y conéctalo a un entorno de ejecución.

  1. Ve a BigQuery Studio en la consola de Google Cloud.
  2. Haz clic en el junto al botón +.
  3. Selecciona Notebook de Python.
  4. Cierra el selector de plantillas.
  5. Selecciona + Código para crear una celda de código nueva.
  6. Instala la versión más reciente del paquete BigQuery DataFrames desde la celda de código.Escribe el siguiente comando.
    %pip install --upgrade bigframes --quiet
    
    Haz clic en el botón 🞂 o presiona Mayúsculas + Intro para ejecutar la celda de código.

3. Lee un conjunto de datos públicos

Para inicializar el paquete BigQuery DataFrames, ejecuta lo siguiente en una celda de código nueva:

import bigframes.pandas as bpd

bpd.options.bigquery.ordering_mode = "partial"

Nota: En este instructivo, usamos el "modo de ordenamiento parcial" experimental, que permite realizar consultas más eficientes cuando se usa con un filtrado similar al de pandas. Es posible que algunas funciones de pandas que requieren un orden o un índice estrictos no funcionen.

Base de datos de reclamos de consumidores

La base de datos de quejas de consumidores se proporciona en BigQuery a través del programa de conjuntos de datos públicos de Google Cloud. Esta es una recopilación de quejas sobre productos y servicios financieros para consumidores, y los datos los recopila la Oficina de Protección Financiera del Consumidor de Estados Unidos.

En BigQuery, consulta la tabla bigquery-public-data.cfbp_complaints.complaint_database para analizar la base de datos de quejas de consumidores. Usa el método bigframes.pandas.read_gbq() para crear un DataFrame a partir de una cadena de consulta o un ID de tabla.

Ejecuta lo siguiente en una celda de código nueva para crear un DataFrame llamado “comentarios”:

feedback = bpd.read_gbq(
    "bigquery-public-data.cfpb_complaints.complaint_database"
)

Descubre información básica sobre un DataFrame

Usa el método DataFrame.peek() para descargar una pequeña muestra de los datos.

Ejecuta esta celda:

feedback.peek()

Resultado esperado:

  date_received                  product ... timely_response  consumer_disputed complaint_id  
0    2014-03-05  Bank account or service ...            True              False       743665   
1    2014-01-21  Bank account or service ...            True              False       678608   
2    2020-12-31          Debt collection ...            True               <NA>      4041190   
3    2014-02-12          Debt collection ...            True              False       714350   
4    2015-02-23          Debt collection ...            True              False      1251358   

Nota: head() requiere orden y, por lo general, es menos eficiente que peek() si deseas visualizar una muestra de datos.

Al igual que con pandas, usa la propiedad DataFrame.dtypes para ver todas las columnas disponibles y sus tipos de datos correspondientes. Se exponen de una manera compatible con pandas.

Ejecuta esta celda:

feedback.dtypes

Resultado esperado:

date_received                   date32[day][pyarrow]
product                              string[pyarrow]
subproduct                           string[pyarrow]
issue                                string[pyarrow]
subissue                             string[pyarrow]
consumer_complaint_narrative         string[pyarrow]
company_public_response              string[pyarrow]
company_name                         string[pyarrow]
state                                string[pyarrow]
zip_code                             string[pyarrow]
tags                                 string[pyarrow]
consumer_consent_provided            string[pyarrow]
submitted_via                        string[pyarrow]
date_sent_to_company            date32[day][pyarrow]
company_response_to_consumer         string[pyarrow]
timely_response                              boolean
consumer_disputed                            boolean
complaint_id                         string[pyarrow]
dtype: object

El método DataFrame.describe() consulta algunas estadísticas básicas del DataFrame. Como este DataFrame no contiene columnas numéricas, muestra un resumen del recuento de valores no nulos y la cantidad de valores distintos.

Ejecuta esta celda:

# Exclude some of the larger columns to make the query more efficient.
feedback.drop(columns=[
  "consumer_complaint_narrative",
  "company_public_response",
  "company_response_to_consumer",
]).describe()

Resultado esperado:

         product  subproduct    issue  subissue  company_name    state ... timely_response  consumer_disputed  complaint_id
count    3458906     3223615  3458906   2759004       3458906  3417792 ...         3458906             768399       3458906
nunique       18          76      165       221          6694       63 ...               2                  2       3458906

4. Cómo explorar los datos

Antes de analizar las quejas reales, usa los métodos similares a Pandas en el DataFrame para visualizar los datos.

Visualiza el DataFrame

Existen varios métodos de visualización integrados, como DataFrame.plot.hist(). Dado que este DataFrame contiene principalmente datos de cadenas y booleanos, primero podemos realizar una agregación para obtener más información sobre varias columnas.

Cuenta cuántas quejas se reciben de cada estado.

complaints_by_state = (
  feedback.groupby(
    "state", as_index=False,
  ).size()
  .rename(columns={"size": "total_complaints"})
  .sort_values(by="total_complaints", ascending=False)
)

Convierte esto en un DataFrame de Pandas con el método DataFrame.to_pandas().

complaints_pd = complaints_by_state.head(10).to_pandas()

Usa los métodos de visualización de Pandas en este DataFrame descargado.

complaints_pd.plot.bar(x="state", y="total_complaints")

gráfico de barras que muestra California como el estado con más reclamos

Cómo unir con otros conjuntos de datos

Anteriormente, analizaste las quejas por estado, pero esto pierde contexto importante. Algunos estados tienen poblaciones más grandes que otros. Únete a un conjunto de datos de población, como la Encuesta sobre la comunidad estadounidense de la Oficina de Censos de EE.UU. y la tabla bigquery-public-data.geo_us_boundaries.states.

us_states = bpd.read_gbq("bigquery-public-data.geo_us_boundaries.states")
us_survey = bpd.read_gbq("bigquery-public-data.census_bureau_acs.state_2020_5yr")

# Ensure there are leading 0s on GEOIDs for consistency across tables.
us_states = us_states.assign(
    geo_id=us_states["geo_id"].str.pad(2, fillchar="0")
)

us_survey = us_survey.assign(
    geo_id=us_survey["geo_id"].str.pad(2, fillchar="0")
)

La Encuesta sobre la comunidad estadounidense identifica los estados por GEOID. Únete a la tabla de estados para obtener la población por código de estado de dos letras.

pops = us_states.set_index("geo_id")[["state"]].join(
  us_survey.set_index("geo_id")[["total_pop"]]
)

Ahora, únete a la base de datos de reclamos para comparar la población con la cantidad de reclamos.

complaints_and_pops = complaints_by_state.set_index("state").join(
    pops.set_index("state")
)

Crea un diagrama de dispersión para comparar las poblaciones estatales con la cantidad de reclamos.

(
  complaints_and_pops
  .to_pandas()
  .plot.scatter(x="total_pop", y="total_complaints")
)

un diagrama de dispersión que compara la población con las quejas

Algunos estados parecen ser valores atípicos cuando se compara la población con la cantidad de reclamos. Se deja como ejercicio para que el lector los grafique con etiquetas de punto para identificarlos. Del mismo modo, plantea algunas hipótesis sobre por qué podría ser así (p.ej., diferentes datos demográficos, diferente cantidad de empresas de servicios financieros, etc.) y pruébalas.

5. Cómo calcular las incorporaciones

A menudo, la información importante se oculta en datos no estructurados, como texto, audio o imágenes. En este ejemplo, gran parte de la información útil de la base de datos de reclamos se encuentra en el contenido de texto de la queja.

La IA y las técnicas tradicionales, como el análisis de sentimientos, el "bag of words" y word2vec, pueden extraer algunos datos cuantitativos de información no estructurados. Más recientemente, los modelos de "incorporación vectorial", que están estrechamente relacionados con los LLM, pueden crear una secuencia de números de punto flotante que representan la información semántica del texto.

Selecciona un subconjunto de la base de datos

Ejecutar un modelo de incorporación de vectores usa más recursos que otras operaciones. Para reducir los costos y los problemas de cuota, selecciona un subconjunto de los datos para el resto de este instructivo.

import bigframes.pandas as bpd

bpd.options.bigquery.ordering_mode = "partial"

feedback = bpd.read_gbq(
    "bigquery-public-data.cfpb_complaints.complaint_database"
)

# Note: if not using ordering_mode = "partial", you must specify these in read_gbq
# for these to affect query efficiency.
# feedback = bpd.read_gbq(
#    "bigquery-public-data.cfpb_complaints.complaint_database",
#     columns=["consumer_complaint_narrative"],
#     filters= [
#         ("consumer_complaint_narrative", "!=", ""),
#         ("date_received", "==", "2022-12-01")])

feedback.shape

Hay alrededor de 1,000 reclamos enviados el 01/12/2022 en comparación con casi 3.5 millones de filas en la base de datos total (consulta con feedback.shape).

Selecciona solo los datos del 1 de diciembre de 2022 y solo la columna consumer_complaint_narrative.

import datetime

feedback = feedback[
    # Filter rows by passing in a boolean Series.
    (feedback["date_received"] == datetime.date(2022, 12, 1))
    & ~(feedback["date_received"].isnull())
    & ~(feedback["consumer_complaint_narrative"].isnull())
    & (feedback["consumer_complaint_narrative"] != "")
    & (feedback["state"] == "CA")

    # Uncomment the following if using free credits for a workshop.
    # Billing accounts with free credits have limited Vertex AI quota.
    # & (feedback["product"] == "Mortgage")
][
    # Filter columns by passing in a list of strings.
    ["consumer_complaint_narrative"]
]

feedback.shape

El método drop_duplicates de pandas requiere un ordenamiento total de las filas porque intenta seleccionar la primera o la última fila coincidente y preservar el índice asociado con ella.

En su lugar, realiza una llamada al método groupby para anular las filas duplicadas.

feedback = (
  feedback.groupby("consumer_complaint_narrative", as_index=False)
  .size()
)[["consumer_complaint_narrative"]]

feedback.shape

Genera embeddings

BigQuery DataFrames genera vectores de incorporación a través de la clase TextEmbeddingGenerator. Esto se basa en el método ML.GENERATE_EMBEDDING, en BigQuery ML, que llama a los modelos de incorporación de texto que proporciona Vertex AI.

from bigframes.ml.llm import TextEmbeddingGenerator

embedding_model = TextEmbeddingGenerator(
    model_name="text-embedding-004"
)
feedback_embeddings = embedding_model.predict(feedback)

Observa cómo se ven las incorporaciones. Estos vectores representan el significado semántico del texto tal como lo entiende el modelo de incorporación de texto.

feedback_embeddings.peek()

Resultado esperado:

                        ml_generate_embedding_result  \
0  [ 7.36380890e-02  2.11779331e-03  2.54309829e-...   
1  [-1.10935252e-02 -5.53950183e-02  2.01338865e-...   
2  [-7.85628427e-03 -5.39347418e-02  4.51385677e-...   
3  [ 0.02013054 -0.0224789  -0.00164843  0.011354...   
4  [-1.51684484e-03 -5.02693094e-03  1.72322839e-...   

Estos vectores tienen muchas dimensiones. Observa un solo vector de embedding:

feedback_embeddings["ml_generate_embedding_result"].peek().iloc[0]

La generación de incorporaciones funciona bajo un contrato de "éxito parcial". Esto significa que algunas filas pueden tener errores y no generar una incorporación. La columna 'ml_generate_embedding_status' expone los mensajes de error. Si está vacío, significa que no hay errores.

Filtra las incorporaciones para incluir solo las filas en las que no se produjo ningún error.

mask = feedback_embeddings["ml_generate_embedding_status"] == ""
valid_embeddings = feedback_embeddings[mask]
valid_embeddings.shape

6. Cómo crear clústeres con incorporaciones de texto

Ahora, agrupa las incorporaciones con k-means. Para esta demostración, usa una cantidad arbitraria de grupos (también conocidos como centroides). Una solución de calidad de producción debe ajustar la cantidad de centroides con una técnica como el método Silhouette.

from bigframes.ml.cluster import KMeans

num_clusters = 5
cluster_model = KMeans(n_clusters=num_clusters)
cluster_model.fit(valid_embeddings["ml_generate_embedding_result"])
clusters = cluster_model.predict(valid_embeddings)
clusters.peek()

Quita los errores de incorporación.

mask = clusters["ml_generate_embedding_status"] == ""
clusters = clusters[mask]

Consulta la distribución de los comentarios por centroide.

clusters.groupby("CENTROID_ID").size()

7. Resume los clústeres

Agrega algunos comentarios asociados con cada centroide y pídele a Gemini que resuma las quejas. La ingeniería de instrucciones es un área emergente, pero hay buenos ejemplos en Internet, como https://www.promptingguide.ai/.

from bigframes.ml.llm import GeminiTextGenerator

preamble = "What is the main concern in this list of user complaints:"
suffix = "Write the main issue using a formal tone."

# Now let's sample the raw comments and get the LLM to summarize them.
prompts = []
for centroid_id in range(1, num_clusters + 1):
  cluster = clusters[clusters["CENTROID_ID"] == centroid_id]
  comments = "\n".join(["- {0}".format(x) for x in cluster.content.peek(40)])
  prompts.append("{}:\n{}\n{}".format(preamble, comments, suffix))

prompt_df = bpd.DataFrame(prompts)
gemini = GeminiTextGenerator(model_name="gemini-1.5-flash-001")
issues = gemini.predict(X=prompt_df, temperature=0.0)
issues.peek()

Usa Gemini para escribir un informe a partir de los resúmenes.

from IPython.display import display, Markdown

prompt = "Turn this list of issues into a short, concise report:"
for value in issues["ml_generate_text_llm_result"]:
  prompt += "- {}".format(value)
prompt += "Using a formal tone, write a markdown text format report."

summary_df = bpd.DataFrame(([prompt]))
summary = gemini.predict(X=summary_df, temperature=0.0)

report = (summary["ml_generate_text_llm_result"].values[0])
display(Markdown(report))

8. Limpia

Si creaste un proyecto de Google Cloud nuevo para este instructivo, puedes borrarlo para evitar cargos adicionales por las tablas o los demás recursos que creaste.

9. ¡Felicitaciones!

Analizaste datos estructurados y no estructurados con BigQuery DataFrames. A lo largo del camino, exploraste los conjuntos de datos públicos de Google Cloud, los notebooks de Python en BigQuery Studio, BigQuery ML, Vertex AI y las funciones de lenguaje natural a Python de BigQuery Studio. ¡Gran trabajo!

Próximos pasos