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 los datos con Python. Aprovecha la IA generativa de Google para analizar y visualizar datos de texto no estructurados.
Crearás un notebook de Python para categorizar y resumir una base de datos pública de reclamos de clientes. Se puede adaptar para que funcione con 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 de BigQuery DataFrames
- Crea incorporaciones a partir de datos de texto no estructurados con BigQuery ML y una conexión a un extremo de incorporación de texto en Vertex AI
- Agrupa clústeres de incorporaciones con BigQuery ML
- Resume clústeres con un LLM a través de BigQuery ML
2. Requisitos
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.
- En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud.
- 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.
- 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.
- Ve a BigQuery Studio en la consola de Google Cloud.
- Haz clic en ▼ junto al botón +.
- Selecciona Notebook de Python.
- Cierra el selector de plantillas.
- Selecciona + Código para crear una celda de código nueva.
- Instala la versión más reciente del paquete de BigQuery DataFrames desde la celda de código.Escribe el siguiente comando.
Haz clic en el botón 🞂 o presiona Mayúsculas + Intro para ejecutar la celda de código.%pip install --upgrade bigframes --quiet
3. Cómo leer un conjunto de datos públicos
Inicializa el paquete de BigQuery DataFrames ejecutando 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 filtros similares a los de pandas. Es posible que no funcionen algunas funciones de pandas que requieren un orden o un índice estrictos.
Base de datos de reclamos de consumidores
La Consumer Complaint Database se proporciona en BigQuery a través del programa de conjuntos de datos públicos de Google Cloud. Esta es una recopilación de reclamos sobre productos y servicios financieros para el consumidor, y los datos son recopilados por 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 reclamos 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 "feedback":
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 ordenamiento 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. Dado que 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 los reclamos reales, usa los métodos similares a los de 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 cadena y booleanos, primero podemos realizar alguna agregación para obtener más información sobre varias columnas.
Contamos cuántas reclamos 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")

Unir con otros conjuntos de datos
Anteriormente, analizaste los reclamos por estado, pero esto pierde contexto importante. Algunos estados tienen más población que otros. Une los datos con un conjunto de datos de población, como la Encuesta sobre la comunidad estadounidense de la Oficina del Censo 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. Une 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, une esta tabla 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 la población de los estados con la cantidad de reclamos.
(
complaints_and_pops
.to_pandas()
.plot.scatter(x="total_pop", y="total_complaints")
)

Al comparar la población con la cantidad de reclamos, parece que algunos estados son valores atípicos. Se deja como ejercicio para el lector que genere un gráfico con etiquetas de puntos para identificarlos. Del mismo modo, formula 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 ponlas a prueba.
5. Cómo calcular embeddings
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 del reclamo.
La IA y las técnicas tradicionales, como el análisis de opiniones, la "bolsa de palabras" y word2vec, pueden extraer información cuantitativa de los datos no estructurados. Más recientemente, los modelos de "incorporación de vectores", 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
El 2022-12-01, se enviaron alrededor de 1,000 reclamos, en comparación con los casi 3.5 millones de filas de la base de datos total (consulta con feedback.shape).
Selecciona solo los datos del 2022-12-01 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 orden total de las filas porque intenta seleccionar la primera o la última fila coincidente y conservar el índice asociado a ella.
En su lugar, agrega los datos con una llamada al método groupby para quitar 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 proporcionados por 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 los embeddings. Estos vectores representan el significado semántico del texto tal como lo entiende el modelo de embedding 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 embeddings funciona según 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. Agrupa en clústeres con incorporaciones de texto
Ahora, agrupa los embeddings en clústeres con k-means. Para esta demostración, usa una cantidad arbitraria de grupos (también conocidos como centroides). Una solución de calidad para la producción debe ajustar la cantidad de centroides con una técnica como el método de la silueta.
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]
Echa un vistazo y observa la distribución de los comentarios por centroide.
clusters.groupby("CENTROID_ID").size()
7. Resume los clústeres
Proporciona algunos comentarios asociados a cada centroide y pídele a Gemini que resuma los reclamos. 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()
Usar 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 nuevo de Google Cloud para este instructivo, puedes borrarlo para evitar cargos adicionales por las tablas o los demás recursos creados.
9. ¡Felicitaciones!
Analizaste datos estructurados y no estructurados con BigQuery DataFrames. En el 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
- Intenta generar código de Python en tu notebook. Los notebooks de Python en BigQuery Studio cuentan con la tecnología de Colab Enterprise. Sugerencia: Me resulta muy útil pedir ayuda para generar datos de prueba.
- Explora los notebooks de muestra para BigQuery DataFrames en GitHub.
- Crea una programación para ejecutar un notebook en BigQuery Studio.
- Implementa una función remota con BigQuery DataFrames para integrar paquetes de Python de terceros en BigQuery.