Uzyskiwanie statystyk z uporządkowanych i nieuporządkowanych danych za pomocą pakietu BigQuery DataFrames z obsługą AI

1. Omówienie

W tym praktycznym ćwiczeniu użyjesz obiektów DataFrame z BigQuery w notatniku Pythona w BigQuery Studio, aby uzyskać statystyki na podstawie danych za pomocą Pythona. Korzystaj z generatywnej AI od Google do analizowania i wizualizacji nieuporządkowanych danych tekstowych.

Utworzysz notebook Pythona, aby skategoryzować i podsumować publiczną bazę danych skarg klientów. Można go dostosować do pracy z dowolnymi danymi tekstowymi nieuporządkowanymi.

Cele

Z tego modułu nauczysz się, jak:

  • Aktywowanie i używanie notatników Pythona w BigQuery Studio
  • Łączenie z BigQuery za pomocą pakietu BigQuery DataFrames
  • tworzenie wektorów dystrybucyjnych na podstawie nieuporządkowanych danych tekstowych za pomocą BigQuery ML i połączenia z punktem końcowym wektorów dystrybucyjnych tekstu w Vertex AI.
  • Umieszczanie w klastrach za pomocą BigQuery ML
  • Podsumowywanie klastrów za pomocą modelu LLM w BigQuery ML

2. Wymagania

  • przeglądarka, np. Chrome lub Firefox;
  • projekt Google Cloud z włączonymi płatnościami;

Zanim zaczniesz

Aby wykonać instrukcje w tym laboratorium kodu, musisz mieć projekt Google Cloud z włączonym BigQuery Studio i połączone konto rozliczeniowe.

  1. W konsoli Google Cloud na stronie selektora projektu wybierz lub utwórz projekt Google Cloud.
  2. Sprawdź, czy w projekcie Google Cloud włączone są płatności. Dowiedz się, jak sprawdzić, czy w projekcie są włączone płatności.
  3. Postępuj zgodnie z instrukcjami, aby włączyć BigQuery Studio do zarządzania zasobami.

Przygotowanie BigQuery Studio

Utwórz pusty notatnik i połącz go ze środowiskiem wykonawczym.

  1. Otwórz BigQuery Studio w konsoli Google Cloud.
  2. Kliknij  obok przycisku +.
  3. Wybierz Notatnik w Pythonie.
  4. Zamknij selektor szablonów.
  5. Aby utworzyć nową komórkę kodu, kliknij + Kod.
  6. Zainstaluj najnowszą wersję pakietu BigQuery DataFrames z komórki kodu.Wpisz następujące polecenie.
    %pip install --upgrade bigframes --quiet
    
    Aby uruchomić komórkę kodu, kliknij przycisk 🞂 lub naciśnij Shift + Enter.

3. Czytanie publicznego zbioru danych

Zainicjuj pakiet BigQuery DataFrames, wykonując ten kod w nowej komórce kodu:

import bigframes.pandas as bpd

bpd.options.bigquery.ordering_mode = "partial"

Uwaga: w tym samouczku używamy eksperymentalnego „trybu częściowego sortowania”, który umożliwia tworzenie bardziej wydajnych zapytań w połączeniu z filtracją w stylu pandas. Niektóre funkcje pakietu pandas, które wymagają ścisłej kolejności lub indeksu, mogą nie działać.

Baza danych o skargach konsumentów

Baza danych Consumer Complaint Database jest udostępniana w BigQuery w ramach programu Google Cloud dotyczącym publicznych zbiorów danych. Jest to zbiór skarg dotyczących produktów i usług finansowych dla konsumentów. Dane są zbierane przez Biuro Ochrony Finansowej Konsumentów w Stanach Zjednoczonych.

Aby przeanalizować bazę danych skarg konsumentów, w BigQuery wyślij zapytanie do tabeli bigquery-public-data.cfbp_complaints.complaint_database. Użyj metody bigframes.pandas.read_gbq(), aby utworzyć DataFrame z ciągu zapytania lub identyfikatora tabeli.

Aby utworzyć DataFrame o nazwie „feedback”, uruchom w nowej komórce kodu ten kod:

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

Poznawanie podstawowych informacji o ramce danych

Aby pobrać małą próbkę danych, użyj metody DataFrame.peek().

Uruchom tę komórkę:

feedback.peek()

Oczekiwane dane wyjściowe:

  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   

Uwaga: funkcja head() wymaga uporządkowania danych i jest zazwyczaj mniej wydajna niż funkcja peek(), jeśli chcesz wizualizować próbkę danych.

Podobnie jak w przypadku pakietu pandas, aby wyświetlić wszystkie dostępne kolumny i odpowiadające im typy danych, użyj właściwości DataFrame.dtypes. Są one udostępniane w sposób zgodny z biblioteką pandas.

Uruchom tę komórkę:

feedback.dtypes

Oczekiwane dane wyjściowe:

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

Metoda DataFrame.describe() wysyła zapytanie o podstawowe statystyki z ramy danych. Ponieważ ten DataFrame nie zawiera kolumn liczbowych, zawiera podsumowanie liczby wartości niepustych i liczby unikalnych wartości.

Uruchom tę komórkę:

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

Oczekiwane dane wyjściowe:

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

Zanim zaczniesz analizować konkretne skargi, użyj metod podobnych do tych z pandas, aby zwizualizować dane w ramach DataFrame.

Wizualizacja DataFrame

Dostępnych jest kilka wbudowanych metod wizualizacji, np. DataFrame.plot.hist(). Ponieważ ten obiekt DataFrame zawiera głównie dane typu string i boolean, możemy najpierw wykonać pewne agregacje, aby dowiedzieć się więcej o różnych kolumnach.

Policz, ile skarg otrzymano z każdego stanu.

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

Za pomocą metody DataFrame.to_pandas() przekształc to w DataFrame w pandas.

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

Zastosuj do pobranego DataFrame metody wizualizacji z pandas.

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

wykres słupkowy pokazujący, że Kalifornia jest stanem, w którym zgłoszono najwięcej skarg

Złączanie z innymi zbiorami danych

Wcześniej analizowano skargi według stanu, ale w ten sposób traci się istotny kontekst. W niektórych stanach mieszka więcej osób niż w innych. Wykonaj złączanie z danymi o populacji, np. z amerykańskim badaniem społeczności przeprowadzonym przez US Census Bureau i z tabelą 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")
)

Badanie American Community Survey określa stany za pomocą identyfikatorów GEOID. Złącz z tabelą states, aby uzyskać liczbę ludności według dwuliterowego kodu stanu.

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

Teraz złącz to z bazą danych skarg, aby porównać liczbę ludności z liczbą skarg.

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

Utwórz wykres punktowy, aby porównać liczbę skarg z liczebnością ludności w poszczególnych stanach.

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

wykres punktowy porównujący liczbę ludności z liczbą skarg

Przy porównaniu liczby ludności z liczbą skarg kilka stanów wydaje się być odstępstwem od normy. Pozostawiamy czytelnikowi zadanie narysowania punktów z oznacznikami. Podobnie sformułuj kilka hipotez na temat tego, dlaczego tak się dzieje (np. różne dane demograficzne, różna liczba firm świadczących usługi finansowe itp.), i sprawdź je.

5. Obliczanie wektorów

Często ważne informacje są ukryte w nieuporządkowanych danych, takich jak tekst, dźwięk lub obrazy. W tym przykładzie większość przydatnych informacji w bazie danych skarg znajduje się w treści skargi.

AI i tradycyjne techniki, takie jak analiza sentymentu, „torba słów” i word2vec, mogą wyodrębnić niektóre dane ilościowe z danych nieuporządkowanych. Niedawno modele „wektorów dystrybucyjnych”, które są blisko związane z modelami LLM, mogą tworzyć sekwencję liczb zmiennoprzecinkowych reprezentujących informacje semantyczne tekstu.

Wybierz podzbiór bazy danych.

Uruchamianie modelu wektorów dystrybucyjnych zużywa więcej zasobów niż inne operacje. Aby zmniejszyć koszty i uniknąć problemów z kwotą, w dalszej części samouczka użyj podzbioru danych.

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

1 stycznia 2022 r.wpłynęło około 1000 skarg, a w całości w bazie danych jest prawie 3,5 mln wierszy (sprawdź w feedback.shape).

Wybierz tylko dane z 1.12.2022 r. i tylko kolumnę 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

Metoda drop_duplicates z biblioteki pandas wymaga całkowitego uporządkowania wierszy, ponieważ próbuje wybrać pierwszy lub ostatni pasujący wiersz i zachować powiązany z nim indeks.

Zamiast tego zamiast tego zastosuj agregację za pomocą wywołania metody groupby, aby usunąć duplikaty wierszy.

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

feedback.shape

Generowanie wektorów

BigQuery DataFrames generuje wektory embeddingu za pomocą klasy TextEmbeddingGenerator. Jest to oparte na metodzie ML.GENERATE_EMBEDDING w BigQuery ML, która wywołuje modele tekstowych zanurzeń udostępnione przez Vertex AI.

from bigframes.ml.llm import TextEmbeddingGenerator

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

Zobacz, jak wyglądają embeddingi. Wektory te reprezentują znaczenie semantyczne tekstu zrozumiane przez model reprezentacji tekstu.

feedback_embeddings.peek()

Oczekiwane dane wyjściowe:

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

Wektory te mają wiele wymiarów. Przyjrzyjmy się jednemu wektorowi dystrybucyjnemu:

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

Generowanie wstawień działa na podstawie umowy „częściowy sukces”. Oznacza to, że niektóre wiersze mogą zawierać błędy i nie generować reprezentacji. Komunikaty o błędach są widoczne w kolumnie 'ml_generate_embedding_status'. Pusty oznacza brak błędów.

Przefiltruj wektory, aby uwzględnić tylko wiersze, w których nie wystąpił błąd.

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

6. Grupowanie za pomocą wektorów tekstowych

Teraz zgrupuj elementy za pomocą metody k-średnich. W tym pokazie użyj dowolnej liczby grup (czyli centroidów). Rozwiązanie o jakości produkcyjnej powinno dostosować liczbę centroidów za pomocą techniki takiej jak metoda 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()

Usuń wszystkie błędy w osadzeniu.

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

Sprawdź rozkład komentarzy według centroidów.

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

7. Podsumowanie klastrów

Dodaj komentarze powiązane z każdym centroidem i poproś Gemini o podsumowanie skarg. Inżynieria promptów to rozwijająca się dziedzina, ale w internecie można znaleźć dobre przykłady, np. 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()

Użyj Gemini do utworzenia raportu na podstawie podsumowań.

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

Jeśli na potrzeby tego samouczka został przez Ciebie utworzony nowy projekt Google Cloud, możesz go usunąć, aby uniknąć dodatkowych opłat za utworzone tabele lub inne zasoby.

9. Gratulacje!

Analizujesz dane uporządkowane i nieuporządkowane za pomocą obiektów DataFrames w BigQuery. W trakcie tego szkolenia poznasz publiczne zbiory danych Google Cloud, notatniki Pythona w BigQuery Studio, BigQuery ML, Vertex AI oraz funkcje BigQuery Studio umożliwiające przekształcanie języka naturalnego w Pythona. Świetna robota!

Dalsze kroki