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

1. Przegląd

W tym module użyjesz BigQuery DataFrames z notatnika Pythona w BigQuery Studio, aby uzyskać wgląd w dane za pomocą Pythona. Korzystaj z generatywnej AI od Google, aby analizować i wizualizować nieustrukturyzowane dane tekstowe.

Utworzysz notatnik w Pythonie, aby kategoryzować i podsumowywać publiczną bazę danych skarg klientów. Można go dostosować do pracy z dowolnymi nieustrukturyzowanymi danymi tekstowymi.

Cele

Z tego modułu nauczysz się, jak:

  • Aktywowanie i używanie notatników w Pythonie w BigQuery Studio
  • Łączenie z BigQuery za pomocą pakietu BigQuery DataFrames
  • Tworzenie wektorów dystrybucyjnych tekstu z nieustrukturyzowanych danych tekstowych za pomocą BigQuery ML i połączenia z punktem końcowym wektora dystrybucyjnego tekstu w Vertex AI
  • Grupowanie wektorów za pomocą BigQuery ML
  • Podsumowywanie klastrów za pomocą 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 podane w tym samouczku, musisz mieć projekt Google Cloud z włączoną usługą BigQuery Studio i połączonym kontem rozliczeniowym.

  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 włączone są płatności
  3. Postępuj zgodnie z instrukcjami, aby włączyć BigQuery Studio do zarządzania zasobami.

Przygotowywanie BigQuery Studio

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

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

3. Odczytywanie publicznego zbioru danych

Zainicjuj pakiet BigQuery DataFrames, uruchamiając w nowej komórce kodu to polecenie:

import bigframes.pandas as bpd

bpd.options.bigquery.ordering_mode = "partial"

Uwaga: w tym samouczku używamy eksperymentalnego „trybu częściowego porządkowania”, który w połączeniu z filtrowaniem podobnym do tego w bibliotece pandas umożliwia wykonywanie bardziej wydajnych zapytań. Niektóre funkcje biblioteki pandas, które wymagają ścisłego uporządkowania lub indeksowania, mogą nie działać.

Baza skarg konsumentów

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

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

Aby utworzyć ramkę danych o nazwie „feedback”, uruchom w nowej komórce kodu to polecenie:

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

Poznaj podstawowe informacje o obiekcie DataFrame

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: head() wymaga uporządkowania i jest zwykle mniej wydajne niż peek(), jeśli chcesz wizualizować próbkę danych.

Podobnie jak w przypadku biblioteki pandas, użyj właściwości DataFrame.dtypes, aby wyświetlić wszystkie dostępne kolumny i odpowiadające im typy danych. 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 obiektu DataFrame. Ten obiekt DataFrame nie zawiera kolumn numerycznych, więc wyświetla podsumowanie liczby wartości niezerowych 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. Analizowanie danych

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

Wizualizacja obiektu DataFrame

Istnieje kilka wbudowanych metod wizualizacji, takich jak DataFrame.plot.hist(). Ponieważ ten obiekt DataFrame zawiera głównie dane tekstowe i wartości logiczne, możemy najpierw przeprowadzić agregację, aby dowiedzieć się więcej o różnych kolumnach.

Policz, ile skarg wpłynęło 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)
)

Przekształć go w obiekt pandas DataFrame za pomocą metody DataFrame.to_pandas().

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

Użyj metod wizualizacji biblioteki pandas w pobranym obiekcie DataFrame.

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

wykres słupkowy pokazujący Kalifornię jako stan z największą liczbą skarg;

Złączanie z innymi zbiorami danych

Wcześniej analizowaliśmy skargi w poszczególnych stanach, ale w ten sposób traciliśmy ważny kontekst. Niektóre stany mają większą populację niż inne. Połącz z zbiorem danych o populacji, takim jak American Community Survey amerykańskiego Biura Spisu Ludnościtabela 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")
)

American Community Survey identyfikuje stany za pomocą GEOID. Połącz z tabelą stanów, aby uzyskać populację według dwuliterowego kodu stanu.

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

Teraz połącz te dane z bazą danych skarg, aby porównać liczbę mieszkańców 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ę mieszkańców poszczególnych stanów z liczbą skarg.

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

wykres punktowy porównujący liczbę mieszkańców z liczbą skarg,

W przypadku kilku stanów widać odchylenia od normy, gdy porównamy liczbę mieszkańców z liczbą skarg. Pozostawiamy to jako ćwiczenie dla czytelnika, aby narysować wykres z etykietami punktów i zidentyfikować te wartości. Podobnie opracuj hipotezy dotyczące tego, dlaczego tak może być (np. różne dane demograficzne, różna liczba firm świadczących usługi finansowe itp.) i je przetestuj.

5. Obliczanie wektorów dystrybucyjnych

Ważne informacje są często ukryte w nieustrukturyzowanych danych, takich jak tekst, dźwięk czy obrazy. W tym przykładzie większość przydatnych informacji w bazie danych skarg znajduje się w tekście skargi.

AI i tradycyjne techniki, takie jak analiza nastawienia, „bag of words” i word2vec, mogą wyodrębniać z danych nieustrukturyzowanych informacje ilościowe. Ostatnio modele „osadzania wektorowego”, które są ściśle powiązane z LLM, mogą tworzyć sekwencję liczb zmiennoprzecinkowych reprezentujących informacje semantyczne tekstu.

Wybieranie podzbioru bazy danych

Uruchomienie modelu wektorów dystrybucyjnych zużywa więcej zasobów niż inne operacje. Aby zmniejszyć koszty i uniknąć problemów z limitami, wybierz podzbiór danych na potrzeby pozostałej części tego samouczka.

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

W dniu 1 grudnia 2022 r.przesłano około 1000 skarg, a w całej bazie danych jest prawie 3,5 miliona wierszy (sprawdź w feedback.shape).

Wybierz tylko dane z 1 grudnia 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 użyj agregacji z wywołaniem metody groupby, aby usunąć zduplikowane wiersze.

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

feedback.shape

Generowanie wektorów dystrybucyjnych

BigQuery DataFrames generuje wektory osadzania za pomocą klasy TextEmbeddingGenerator. Jest to oparte na ML.GENERATE_EMBEDDINGmetodzie w BigQuery ML, która wywołuje modele wektorów dystrybucyjnych tekstu udostępniane 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ą wektory. Wektory te reprezentują znaczenie semantyczne tekstu w sposób, w jaki rozumie je model wektora dystrybucyjnego 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. Przyjrzyj się pojedynczemu wektorowi dystrybucyjnemu:

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

Generowanie embeddingów działa na podstawie umowy „częściowe powodzenie”. Oznacza to, że niektóre wiersze mogą zawierać błędy i nie generować reprezentacji właściwościowych. Komunikaty o błędach są widoczne w kolumnie 'ml_generate_embedding_status'. Puste pole oznacza brak błędów.

Przefiltruj wektory, aby uwzględniały 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. Klastrowanie za pomocą wektorów dystrybucyjnych tekstu

Teraz pogrupuj wektory za pomocą algorytmu k-średnich. W tym przykładzie użyj dowolnej liczby grup (czyli centroidów). Rozwiązanie o jakości produkcyjnej powinno dostosowywać liczbę centroidów za pomocą techniki takiej jak metoda sylwetki.

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ń wszelkie błędy związane z osadzaniem.

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

Sprawdź rozkład komentarzy w poszczególnych centroidach.

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

7. Podsumuj klastry

Przekaż Gemini kilka komentarzy powiązanych z każdym centroidem i poproś Gemini o podsumowanie skarg. Inżynieria promptów to nowa dziedzina, ale w internecie można znaleźć dobre przykłady, np. na stronie 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 napisania 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 w chmurze Google, 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ą BigQuery DataFrames. Po drodze poznasz publiczne zbiory danych Google Cloud, notatniki w Pythonie w BigQuery Studio, BigQuery ML, Vertex AI i funkcje języka naturalnego w Pythonie w BigQuery Studio. Świetna robota!

Dalsze kroki