Ottieni insight da dati strutturati e non strutturati utilizzando il pacchetto BigQuery DataFrames compatibile con l'IA

1. Panoramica

In questo lab utilizzerai BigQuery DataFrames da un blocco note Python in BigQuery Studio per ottenere approfondimenti dai dati utilizzando Python. Utilizza l'AI generativa di Google per analizzare e visualizzare i dati di testo non strutturati.

Creerai un notebook Python per classificare e riepilogare un database pubblico di reclami dei clienti. Può essere adattato per funzionare su qualsiasi dato di testo non strutturato.

Obiettivi

In questo lab imparerai a:

  • Attivare e utilizzare i notebook Python in BigQuery Studio
  • Connettiti a BigQuery utilizzando il pacchetto BigQuery DataFrames
  • Crea embedding da dati di testo non strutturati utilizzando BigQuery ML e la connessione a un endpoint di embedding di testo in Vertex AI
  • Raggruppa gli incorporamenti utilizzando BigQuery ML
  • Riepilogare i cluster con un LLM tramite BigQuery ML

2. Requisiti

  • Un browser, ad esempio Chrome o Firefox
  • Un progetto Google Cloud con la fatturazione abilitata

Prima di iniziare

Per seguire le istruzioni di questo codelab, avrai bisogno di un progetto Google Cloud con BigQuery Studio abilitato e un account di fatturazione collegato.

  1. Nella console Google Cloud, nella pagina di selezione del progetto, seleziona o crea un progetto Google Cloud.
  2. Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud. Scopri come verificare se la fatturazione è abilitata per un progetto.
  3. Segui le istruzioni per attivare BigQuery Studio per la gestione degli asset.

Prepara BigQuery Studio

Crea un notebook vuoto e connettilo a un runtime.

  1. Vai a BigQuery Studio nella console Google Cloud.
  2. Fai clic su accanto al pulsante +.
  3. Seleziona Notebook Python.
  4. Chiudi il selettore dei modelli.
  5. Seleziona + Codice per creare una nuova cella di codice.
  6. Installa l'ultima versione del pacchetto BigQuery DataFrames dalla cella di codice.Digita il seguente comando.
    %pip install --upgrade bigframes --quiet
    
    Fai clic sul pulsante 🞂 o premi Maiusc + Invio per eseguire la cella di codice.

3. Leggere un set di dati pubblico

Inizializza il pacchetto BigQuery DataFrames eseguendo il seguente comando in una nuova cella di codice:

import bigframes.pandas as bpd

bpd.options.bigquery.ordering_mode = "partial"

Nota: in questo tutorial utilizziamo la "modalità di ordinamento parziale" sperimentale, che consente query più efficienti se utilizzata con filtri simili a quelli di pandas. Alcune funzionalità di pandas che richiedono un ordinamento o un indice rigoroso potrebbero non funzionare.

Database dei reclami dei consumatori

Il database dei reclami dei consumatori viene fornito su BigQuery tramite il programma per i set di dati pubblici di Google Cloud. Si tratta di una raccolta di reclami relativi a prodotti e servizi finanziari per i consumatori e i dati vengono raccolti dal Consumer Financial Protection Bureau degli Stati Uniti.

In BigQuery, esegui una query sulla tabella bigquery-public-data.cfbp_complaints.complaint_database per analizzare il database dei reclami dei consumatori. Utilizza il metodo bigframes.pandas.read_gbq() per creare un DataFrame da una stringa di query o da un ID tabella.

Esegui il seguente codice in una nuova cella di codice per creare un DataFrame denominato "feedback":

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

Scopri le informazioni di base su un DataFrame

Utilizza il metodo DataFrame.peek() per scaricare un piccolo campione dei dati.

Esegui questa cella:

feedback.peek()

Output previsto:

  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() richiede l'ordinamento ed è generalmente meno efficiente di peek() se vuoi visualizzare un campione di dati.

Come con pandas, utilizza la proprietà DataFrame.dtypes per visualizzare tutte le colonne disponibili e i relativi tipi di dati. Questi vengono esposti in modo compatibile con pandas.

Esegui questa cella:

feedback.dtypes

Output previsto:

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

Il metodo DataFrame.describe() esegue query su alcune statistiche di base del DataFrame. Poiché questo DataFrame non contiene colonne numeriche, mostra un riepilogo del conteggio dei valori non nulli e del numero di valori distinti.

Esegui questa cella:

# 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()

Output previsto:

         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. Esplorare i dati

Prima di esaminare i reclami effettivi, utilizza i metodi simili a Pandas sul DataFrame per visualizzare i dati.

Visualizzare il DataFrame

Esistono diversi metodi di visualizzazione integrati, ad esempio DataFrame.plot.hist(). Poiché questo DataFrame contiene principalmente dati di tipo stringa e booleano, possiamo prima eseguire un'aggregazione per scoprire di più sulle varie colonne.

Conta il numero di reclami ricevuti da ogni stato.

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

Converti questo in un DataFrame Pandas utilizzando il metodo DataFrame.to_pandas().

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

Utilizza i metodi di visualizzazione di Pandas su questo DataFrame scaricato.

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

Grafico a barre che mostra la California come stato con il maggior numero di reclami

Unire ad altri set di dati

In precedenza, esaminavi i reclami per stato, ma in questo modo si perde un contesto importante. Alcuni stati hanno una popolazione più numerosa di altri. Unisciti a un set di dati sulla popolazione come l'American Community Survey del Census Bureau degli Stati Uniti e la tabella 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 identifica gli stati in base al GEOID. Esegui il join con la tabella degli stati per ottenere la popolazione in base al codice stato di due lettere.

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

Ora unisci questo database a quello dei reclami per confrontare la popolazione con il numero di reclami.

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

Crea un grafico a dispersione per confrontare la popolazione degli stati con il numero di reclami.

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

un grafico a dispersione che confronta la popolazione con i reclami

Un paio di stati sembrano essere valori anomali se si confronta la popolazione con il numero di reclami. Il lettore può esercitarsi a tracciare i grafici con le etichette dei punti per identificarli. Allo stesso modo, formula alcune ipotesi sul perché potrebbe essere così (ad es. dati demografici diversi, numero diverso di società di servizi finanziari e così via) e testale.

5. Calcolare gli incorporamenti

Spesso, informazioni importanti sono nascoste in dati non strutturati, come testo, audio o immagini. In questo esempio, gran parte delle informazioni utili nel database dei reclami è contenuta nel testo del reclamo.

L'AI e le tecniche tradizionali, come l'analisi del sentiment, il "bag of words" e word2vec, possono estrarre alcune informazioni quantitative dai dati non strutturati. Più di recente, i modelli di "vector embedding", strettamente correlati agli LLM, possono creare una sequenza di numeri in virgola mobile che rappresentano le informazioni semantiche del testo.

Seleziona un sottoinsieme del database

L'esecuzione di un modello di incorporamento vettoriale utilizza più risorse rispetto ad altre operazioni. Per ridurre i costi e i problemi relativi alla quota, seleziona un sottoinsieme dei dati per il resto di questo tutorial.

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

Il 1° dicembre 2022 sono stati inviati circa 1000 reclami rispetto a quasi 3,5 milioni di righe nel database totale (verifica con feedback.shape).

Seleziona solo i dati per il giorno 01/12/2022 e solo la colonna 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

Il metodo drop_duplicates di pandas richiede un ordinamento totale delle righe perché tenta di selezionare la prima o l'ultima riga corrispondente e di conservare l'indice associato.

Esegui invece l'aggregazione con una chiamata al metodo groupby per rimuovere i duplicati delle righe.

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

feedback.shape

Genera embedding

BigQuery DataFrames genera vettori di incorporamento tramite la classe TextEmbeddingGenerator. Si basa sul metodo ML.GENERATE_EMBEDDING in BigQuery ML, che chiama i modelli di incorporamento di testo forniti da Vertex AI.

from bigframes.ml.llm import TextEmbeddingGenerator

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

Dai un'occhiata a come appaiono gli incorporamenti. Questi vettori rappresentano il significato semantico del testo così come viene compreso dal modello di embedding del testo.

feedback_embeddings.peek()

Output previsto:

                        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-...   

Questi vettori hanno molte dimensioni. Dai un'occhiata a un singolo vettore di embedding:

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

La generazione di incorporamenti opera in base a un contratto di "successo parziale". Ciò significa che alcune righe potrebbero contenere errori e non generare un embedding. I messaggi di errore vengono visualizzati nella colonna 'ml_generate_embedding_status'. Un valore vuoto indica che non sono presenti errori.

Filtra gli incorporamenti in modo da includere solo le righe in cui non si è verificato alcun errore.

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

6. Clusterizzazione utilizzando gli incorporamenti di testo

Ora raggruppa gli incorporamenti utilizzando k-means. Per questa demo, utilizza un numero arbitrario di gruppi (ovvero centroidi). Una soluzione di qualità di produzione deve ottimizzare il numero di centroidi utilizzando una tecnica come il metodo della 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()

Rimuovi eventuali errori di incorporamento.

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

Dai un'occhiata e scopri la distribuzione dei commenti per centroide.

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

7. Riassumere i cluster

Fornisci alcuni commenti associati a ogni centroide e chiedi a Gemini di riassumere i reclami. Il prompt engineering è un campo emergente, ma su internet esistono buoni esempi, come 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()

Utilizzare Gemini per scrivere un report a partire dai riepiloghi.

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. Esegui la pulizia

Se hai creato un nuovo progetto Google Cloud per questo tutorial, puoi eliminarlo per evitare addebiti aggiuntivi per tabelle o altre risorse create.

9. Complimenti!

Hai analizzato dati strutturati e non strutturati utilizzando BigQuery DataFrames. Durante il percorso, hai esplorato i set di dati pubblici di Google Cloud, i notebook Python in BigQuery Studio, BigQuery ML, Vertex AI e le funzionalità di conversione dal linguaggio naturale a Python di BigQuery Studio. Ottimo lavoro.

Passaggi successivi