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 notebook Python in BigQuery Studio per ottenere informazioni dai dati utilizzando Python. Utilizza l'IA generativa di Google per analizzare e visualizzare i dati di testo non strutturato.

Creerai un notebook Python per classificare e riepilogare un database pubblico dei reclami dei clienti. Questo approccio 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
  • Creare embedding da dati di testo non strutturati utilizzando BigQuery ML e la connessione a un endpoint di embedding di testo in Vertex AI
  • Embedding di cluster 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, devi disporre di un progetto Google Cloud con BigQuery Studio abilitato e di un account di fatturazione collegato.

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

Prepara BigQuery Studio

Crea un blocco note vuoto e connettilo a un runtime.

  1. Vai a BigQuery Studio nella console Google Cloud.
  2. Fai clic sul pulsante accanto al pulsante +.
  3. Seleziona Blocco note Python.
  4. Chiudi il selettore dei modelli.
  5. Seleziona + Codice per creare una nuova cella di codice.
  6. Installa la versione più recente 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 codice 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 il filtro simile a pandas. Alcune funzionalità di pandas che richiedono un ordinamento o un indice rigoroso potrebbero non funzionare.

Consumer Complaint Database

Il database dei reclami dei consumatori è 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 dall'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 informazioni di base su un DataFrame

Utilizza il metodo DataFrame.peek() per scaricare un piccolo campione di 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 è in genere meno efficiente di peek() se vuoi visualizzare un campione di dati.

Come per pandas, utilizza la proprietà DataFrame.dtypes per visualizzare tutte le colonne disponibili e i relativi tipi di dati corrispondenti. Questi sono 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 null 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. Esplorazione dei dati

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

Visualizza il DataFrame

Esistono diversi metodi di visualizzazione integrati, come DataFrame.plot.hist(). Poiché questo DataFrame contiene principalmente dati di stringa e booleani, possiamo prima eseguire alcune aggregazioni per saperne 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)
)

Convertilo 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

Eseguire l'unione con altri set di dati

In precedenza, esaminavi i reclami per stato, ma questo approccio non tiene conto di un contesto importante. Alcuni stati hanno una popolazione più grande di altri. Esegui l'unione con un set di dati sulla popolazione, ad esempio 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 tramite GEOID. Esegui l'unione con la tabella degli stati per ottenere la popolazione in base al codice di stato di due lettere.

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

Ora unisci questa tabella al database 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. Lasciamo al lettore il compito di tracciare i punti con le etichette 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. Calcola gli incorporamenti

Spesso le informazioni importanti sono nascoste in dati non strutturati, come testo, audio o immagini. In questo esempio, molte delle informazioni utili nel database dei reclami sono contenute 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 "embedding vettoriale", 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 di quota, seleziona un sottoinsieme di 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 ai quasi 3,5 milioni di righe nel database totale (controlla con feedback.shape).

Seleziona solo i dati relativi al 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 l'aggregazione con una chiamata al metodo groupby per deduplicare le righe.

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

feedback.shape

Genera embedding

I DataFrame di BigQuery generano vettori di embedding tramite la classe TextEmbeddingGenerator. Si basa sul metodo ML.GENERATE_EMBEDDING in BigQuery ML, che chiama i modelli di embedding del 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 sono fatti gli embedding. Questi vettori rappresentano il significato semantico del testo così come è 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 incorporamento:

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

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

Filtra le istanze incorporate 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. Cluster utilizzando gli incorporamenti di testo

Ora raggruppa le rappresentazioni distribuite utilizzando k-means. Per questa demo, utilizza un numero arbitrario di gruppi (noti anche come centroidi). Una soluzione di qualità di produzione deve ottimizzare il numero di centroidi utilizzando una tecnica come il metodo 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. Riepiloga i cluster

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

Utilizza Gemini per scrivere un report 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 le tabelle o altre risorse create.

9. Complimenti!

Hai analizzato dati strutturati e non strutturati utilizzando BigQuery DataFrames. Lungo 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 BigQuery Studio per il passaggio dal linguaggio naturale a Python. Ottimo lavoro.

Passaggi successivi