1. Présentation
Dans cet atelier, vous allez utiliser BigQuery DataFrames à partir d'un notebook Python dans BigQuery Studio pour obtenir des insights à partir de données à l'aide de Python. Utilisez l'IA générative de Google pour analyser et visualiser des données textuelles non structurées.
Vous allez créer un notebook Python pour catégoriser et résumer une base de données publique de réclamations de clients. Cette méthode peut être adaptée pour fonctionner sur n'importe quelles données textuelles non structurées.
Objectifs
Dans cet atelier, vous allez apprendre à effectuer les tâches suivantes :
- Activer et utiliser des notebooks Python dans BigQuery Studio
- Se connecter à BigQuery à l'aide du package BigQuery DataFrames
- Créer des embeddings à partir de données textuelles non structurées à l'aide de BigQuery ML et d'une connexion à un point de terminaison d'embedding de texte dans Vertex AI
- Regrouper des embeddings à l'aide de BigQuery ML
- Résumer des clusters avec un LLM via BigQuery ML
2. Conditions requises
Avant de commencer
Pour suivre les instructions de cet atelier de programmation, vous aurez besoin d'un projet Google Cloud avec BigQuery Studio activé et un compte de facturation associé.
- Dans la console Google Cloud, sur la page de sélection du projet, sélectionnez ou créez un projet Google Cloud.
- Assurez-vous que la facturation est activée pour votre projet Google Cloud. Découvrez comment vérifier si la facturation est activée sur un projet.
- Suivez les instructions pour activer BigQuery Studio pour la gestion des éléments.
Préparer BigQuery Studio
Créez un notebook vide et connectez-le à un environnement d'exécution.
- Accédez à BigQuery Studio dans la console Google Cloud.
- Cliquez sur ▼ à côté du bouton +.
- Sélectionnez Notebook Python.
- Fermez le sélecteur de modèle.
- Sélectionnez + Code pour créer une cellule de code.
- Installez la dernière version du package BigQuery DataFrames à partir de la cellule de code.Saisissez la commande suivante.
Cliquez sur le bouton 🞂 ou appuyez sur Maj+Entrée pour exécuter la cellule de code.%pip install --upgrade bigframes --quiet
3. Lire un ensemble de données public
Initialisez le package BigQuery DataFrames en exécutant la commande suivante dans une nouvelle cellule de code :
import bigframes.pandas as bpd
bpd.options.bigquery.ordering_mode = "partial"
Remarque : Dans ce tutoriel, nous utilisons le "mode de tri partiel" expérimental, qui permet d'effectuer des requêtes plus efficaces lorsqu'il est utilisé avec un filtrage de type pandas. Il est possible que certaines fonctionnalités pandas nécessitant un ordre ou un index stricts ne fonctionnent pas.
Base de données des réclamations des consommateurs
La base de données des réclamations des consommateurs est disponible sur BigQuery via le programme d'ensembles de données publics de Google Cloud. Il s'agit d'une collection de réclamations concernant des produits et services financiers destinés aux consommateurs. Les données sont collectées par le Consumer Financial Protection Bureau des États-Unis.
Dans BigQuery, interrogez la table bigquery-public-data.cfbp_complaints.complaint_database pour analyser la base de données des réclamations des consommateurs. Utilisez la méthode bigframes.pandas.read_gbq() pour créer un DataFrame à partir d'une chaîne de requête ou d'un ID de table.
Exécutez le code suivant dans une nouvelle cellule de code pour créer un DataFrame nommé "feedback" :
feedback = bpd.read_gbq(
"bigquery-public-data.cfpb_complaints.complaint_database"
)
Découvrir des informations de base sur un DataFrame
Utilisez la méthode DataFrame.peek() pour télécharger un petit échantillon des données.
Exécutez cette cellule :
feedback.peek()
Résultat attendu :
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
Remarque : head() nécessite un tri et est généralement moins efficace que peek() si vous souhaitez visualiser un échantillon de données.
Comme avec pandas, utilisez la propriété DataFrame.dtypes pour afficher toutes les colonnes disponibles et leurs types de données correspondants. Elles sont exposées de manière compatible avec pandas.
Exécutez cette cellule :
feedback.dtypes
Résultat attendu :
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
La méthode DataFrame.describe() interroge des statistiques de base à partir du DataFrame. Comme ce DataFrame ne contient aucune colonne numérique, il affiche un récapitulatif du nombre de valeurs non nulles et du nombre de valeurs distinctes.
Exécutez cette cellule :
# 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()
Résultat attendu :
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. Explorer les données
Avant d'examiner les réclamations proprement dites, utilisez les méthodes pandas-like sur le DataFrame pour visualiser les données.
Visualiser le DataFrame
Il existe plusieurs méthodes de visualisation intégrées, comme DataFrame.plot.hist(). Étant donné que ce DataFrame contient principalement des données de type chaîne et booléen, nous pouvons d'abord effectuer une agrégation pour en savoir plus sur les différentes colonnes.
Comptez le nombre de réclamations reçues de chaque État.
complaints_by_state = (
feedback.groupby(
"state", as_index=False,
).size()
.rename(columns={"size": "total_complaints"})
.sort_values(by="total_complaints", ascending=False)
)
Convertissez-le en DataFrame pandas à l'aide de la méthode DataFrame.to_pandas().
complaints_pd = complaints_by_state.head(10).to_pandas()
Utilisez les méthodes de visualisation pandas sur ce DataFrame téléchargé.
complaints_pd.plot.bar(x="state", y="total_complaints")

Effectuer une jointure avec d'autres ensembles de données
Auparavant, vous avez examiné les réclamations par État, mais cela perd un contexte important. Certains États ont une population plus importante que d'autres. Associez-le à un ensemble de données sur la population, comme l'American Community Survey du Bureau du recensement des États-Unis et la table 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")
)
L'American Community Survey identifie les États par GEOID. Joignez-la à la table "states" pour obtenir la population par code d'État à deux lettres.
pops = us_states.set_index("geo_id")[["state"]].join(
us_survey.set_index("geo_id")[["total_pop"]]
)
Joignez maintenant cette table à la base de données des réclamations pour comparer la population au nombre de réclamations.
complaints_and_pops = complaints_by_state.set_index("state").join(
pops.set_index("state")
)
Créez un graphique en nuage de points pour comparer la population des États au nombre de réclamations.
(
complaints_and_pops
.to_pandas()
.plot.scatter(x="total_pop", y="total_complaints")
)

Il semble que certains États soient des valeurs aberrantes lorsque l'on compare la population au nombre de réclamations. Le lecteur est invité à tracer les points avec des libellés pour les identifier. De même, élaborez des hypothèses pour expliquer ce phénomène (par exemple, des différences démographiques, un nombre différent d'entreprises de services financiers, etc.) et testez-les.
5. Calculer des embeddings
Souvent, des informations importantes sont cachées dans des données non structurées, comme du texte, de l'audio ou des images. Dans cet exemple, la plupart des informations utiles de la base de données des réclamations se trouvent dans le contenu textuel de la réclamation.
L'IA et les techniques traditionnelles, telles que l'analyse des sentiments, le "sac de mots" et word2vec, peuvent extraire des informations quantitatives à partir de données non structurées. Plus récemment, les modèles d'embedding vectoriel, qui sont étroitement liés aux LLM, peuvent créer une séquence de nombres à virgule flottante représentant les informations sémantiques du texte.
Sélectionner un sous-ensemble de la base de données
L'exécution d'un modèle d'embedding vectoriel utilise plus de ressources que les autres opérations. Pour réduire les coûts et les problèmes de quota, sélectionnez un sous-ensemble de données pour le reste de ce tutoriel.
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
Environ 1 000 réclamations ont été envoyées le 1er décembre 2022, contre près de 3,5 millions de lignes dans la base de données totale (vérifiez auprès de feedback.shape).
Sélectionnez uniquement les données du 01/12/2022 et la colonne 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
La méthode drop_duplicates de pandas nécessite un ordre total des lignes, car elle tente de sélectionner la première ou la dernière ligne correspondante et de conserver l'index qui y est associé.
Au lieu de cela, agrégez les données en appelant la méthode groupby pour supprimer les lignes en double.
feedback = (
feedback.groupby("consumer_complaint_narrative", as_index=False)
.size()
)[["consumer_complaint_narrative"]]
feedback.shape
Générer des embeddings
BigQuery DataFrames génère des vecteurs d'embedding via la classe TextEmbeddingGenerator. Cette opération est basée sur la méthode ML.GENERATE_EMBEDDING dans BigQuery ML, qui appelle les modèles d'embedding de texte fournis par Vertex AI.
from bigframes.ml.llm import TextEmbeddingGenerator
embedding_model = TextEmbeddingGenerator(
model_name="text-embedding-004"
)
feedback_embeddings = embedding_model.predict(feedback)
Découvrez à quoi ressemblent les embeddings. Ces vecteurs représentent la signification sémantique du texte telle qu'elle est comprise par le modèle d'embedding de texte.
feedback_embeddings.peek()
Résultat attendu :
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-...
Ces vecteurs comportent de nombreuses dimensions. Examinons un seul vecteur d'embedding :
feedback_embeddings["ml_generate_embedding_result"].peek().iloc[0]
La génération d'embeddings fonctionne selon un contrat de "succès partiel". Cela signifie que certaines lignes peuvent comporter des erreurs et ne pas générer d'embedding. Les messages d'erreur sont indiqués dans la colonne 'ml_generate_embedding_status'. Une liste vide signifie qu'il n'y a aucune erreur.
Filtrez les embeddings pour n'inclure que les lignes où aucune erreur ne s'est produite.
mask = feedback_embeddings["ml_generate_embedding_status"] == ""
valid_embeddings = feedback_embeddings[mask]
valid_embeddings.shape
6. Regrouper des données à l'aide d'embeddings de texte
Regroupez maintenant les embeddings à l'aide de k-means. Pour cette démonstration, utilisez un nombre arbitraire de groupes (ou centroïdes). Une solution de qualité de production doit ajuster le nombre de centroïdes à l'aide d'une technique telle que la méthode 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()
Supprimez les échecs d'intégration.
mask = clusters["ml_generate_embedding_status"] == ""
clusters = clusters[mask]
Jetez un coup d'œil à la distribution des commentaires par centroïde.
clusters.groupby("CENTROID_ID").size()
7. Résumer les clusters
Fournissez quelques commentaires associés à chaque centroïde et demandez à Gemini de résumer les réclamations. L'ingénierie des requêtes est un domaine émergent, mais il existe de bons exemples sur Internet, comme 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()
Utiliser Gemini pour rédiger un rapport à partir des résumés
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. Effectuer un nettoyage
Si vous avez créé un projet Google Cloud pour ce tutoriel, vous pouvez le supprimer pour éviter des frais supplémentaires pour les tables ou autres ressources créées.
9. Félicitations !
Vous avez analysé des données structurées et non structurées à l'aide de BigQuery DataFrames. Vous avez exploré les ensembles de données publics de Google Cloud, les notebooks Python dans BigQuery Studio, BigQuery ML, Vertex AI et les fonctionnalités de langage naturel vers Python de BigQuery Studio. Bravo !
Étapes suivantes
- Essayez de générer du code Python dans votre notebook. Les notebooks Python dans BigQuery Studio sont fournis par Colab Enterprise. Conseil : Je trouve très utile de demander de l'aide pour générer des données de test.
- Explorez les exemples de notebooks pour BigQuery DataFrames sur GitHub.
- Créez une programmation pour exécuter un notebook dans BigQuery Studio.
- Déployez une fonction distante avec BigQuery DataFrames pour intégrer des packages Python tiers à BigQuery.