איך מפיקים תובנות מנתונים מובְנים ולא מובְנים באמצעות חבילת BigQuery DataFrames עם יכולות AI

1. סקירה כללית

בשיעור Lab הזה תלמדו איך להשתמש ב-BigQuery DataFrames מ-notebook של Python ב-BigQuery Studio כדי להפיק תובנות מהנתונים באמצעות Python. שימוש ב-AI גנרטיבי מבית Google כדי לנתח נתוני טקסט לא מובנה ולהציג אותם כגרפיקה.

תלמדו ליצור מסמך Python כדי לסווג ולסכם מסד נתונים ציבורי של תלונות של לקוחות. אפשר להתאים את הפתרון הזה לכל נתוני טקסט לא מובְנים.

מטרות

בשיעור ה-Lab הזה תלמדו איך לבצע את המשימות הבאות:

  • הפעלה של מחברות Python ושימוש בהן ב-BigQuery Studio
  • התחברות ל-BigQuery באמצעות החבילה BigQuery DataFrames
  • יצירת הטמעות (embeddings) מנתוני טקסט לא מובנים באמצעות BigQuery ML וחיבור לנקודת קצה להטמעת טקסט ב-Vertex AI
  • הטמעת מודלים של אשכולות באמצעות BigQuery ML
  • סיכום אשכולות באמצעות LLM דרך BigQuery ML

2. דרישות

  • דפדפן, כמו Chrome או Firefox
  • פרויקט ב-Google Cloud שבו החיוב מופעל

לפני שמתחילים

כדי לפעול לפי ההוראות במדריך הזה, תצטרכו פרויקט ב-Google Cloud שבו מופעל BigQuery Studio וחשבון חיוב מחובר.

  1. במסוף Google Cloud, בדף לבחירת הפרויקט, בוחרים או יוצרים פרויקט ב-Google Cloud.
  2. מוודאים שהחיוב מופעל בפרויקט שלכם ב-Google Cloud. כך בודקים אם החיוב מופעל בפרויקט
  3. פועלים לפי ההוראות להפעלת BigQuery Studio לניהול נכסים.

הכנת BigQuery Studio

יוצרים מחברת ריקה ומחברים אותה לסביבת זמן ריצה.

  1. עוברים אל BigQuery Studio במסוף Google Cloud.
  2. לוחצים על לצד הלחצן +.
  3. בוחרים באפשרות Python notebook.
  4. סוגרים את בורר התבניות.
  5. בוחרים באפשרות + קוד כדי ליצור תא קוד חדש.
  6. מתקינים את הגרסה האחרונה של חבילת BigQuery DataFrames מתא הבקרה של הקוד.מקלידים את הפקודה הבאה.
    %pip install --upgrade bigframes --quiet
    
    לוחצים על הלחצן 🞂 או על Shift + Enter כדי להריץ את תא הקוד.

3. קריאה של מערך נתונים ציבורי

כדי לאתחל את החבילה BigQuery DataFrames, מריצים את הפקודה הבאה בתא קוד חדש:

import bigframes.pandas as bpd

bpd.options.bigquery.ordering_mode = "partial"

הערה: במדריך הזה אנחנו משתמשים ב'מצב סדר חלקי' הניסיוני, שמאפשר לבצע שאילתות יעילות יותר כשמשתמשים בו עם סינון מסוג pandas. יכול להיות שחלק מהתכונות של pandas שדורשות סדר או אינדקס קפדניים לא יפעלו.

מסד נתונים של תלונות צרכנים

מסד הנתונים של תלונות הצרכנים זמין ב-BigQuery דרך תוכנית מערכי הנתונים הציבוריים של Google Cloud. מדובר באוסף של תלונות על מוצרים ושירותים פיננסיים לצרכן. הנתונים נאספים על ידי הלשכה להגנה על זכויות צרכן בארצות הברית.

ב-BigQuery, מריצים שאילתה על הטבלה bigquery-public-data.cfbp_complaints.complaint_database כדי לנתח את מסד הנתונים של תלונות הצרכנים. משתמשים ב-method‏ bigframes.pandas.read_gbq() כדי ליצור DataFrame ממחרוזת שאילתה או ממזהה טבלה.

מריצים את הקוד הבא בתא קוד חדש כדי ליצור DataFrame בשם feedback:

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

מידע בסיסי על DataFrame

משתמשים בשיטה DataFrame.peek() כדי להוריד דגימה קטנה של הנתונים.

מריצים את התא הזה:

feedback.peek()

הפלט הצפוי:

  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   

הערה: כדי להציג גרפית דגימת נתונים, צריך להשתמש ב-head(), אבל בדרך כלל האפשרות הזו פחות יעילה מ-peek().

בדומה ל-pandas, משתמשים במאפיין DataFrame.dtypes כדי לראות את כל העמודות הזמינות ואת סוגי הנתונים התואמים שלהן. הם נחשפים באופן תואם ל-pandas.

מריצים את התא הזה:

feedback.dtypes

הפלט הצפוי:

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

השיטה DataFrame.describe() שולחת שאילתות על נתונים סטטיסטיים בסיסיים מ-DataFrame. מאחר ש-DataFrame הזה לא מכיל עמודות מספריות, מוצג בו סיכום של מספר הערכים שאינם null ומספר הערכים הייחודיים.

מריצים את התא הזה:

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

הפלט הצפוי:

         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. ניתוח הנתונים

לפני שמתעמקים בבדיקה של התלונות בפועל, משתמשים בשיטות שדומות ל-pandas ב-DataFrame כדי להציג את הנתונים באופן חזותי.

הצגה חזותית של DataFrame

יש כמה שיטות מובנות להצגה חזותית, כמו DataFrame.plot.hist(). מכיוון ש-DataFrame הזה מכיל בעיקר מחרוזות ונתונים בוליאניים, אפשר קודם לבצע צבירת נתונים כדי לקבל מידע נוסף על עמודות שונות.

ספירת מספר התלונות שמתקבלות מכל מדינה.

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

ממירים את זה ל-DataFrame של pandas באמצעות השיטה DataFrame.to_pandas().

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

משתמשים בשיטות להמחשה חזותית של pandas ב-DataFrame שהורדתם.

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

תרשים עמודות שבו מוצגת קליפורניה כמדינה עם מספר התלונות הגבוה ביותר

איחוד עם מערכי נתונים אחרים

בעבר, בדקתם את התלונות לפי מדינה, אבל כך אתם מפספסים הקשר חשוב. בחלק מהמדינות יש אוכלוסייה גדולה יותר מאשר במדינות אחרות. יצירת צירוף עם מערך נתונים של אוכלוסייה, כמו הסקר האמריקאי של הקהילות של מפקד האוכלוסין בארה"ב והטבלה 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, המדינות מזוהות לפי GEOID. משלבים עם טבלת המדינות כדי לקבל את האוכלוסייה לפי קוד המדינה בן שתי האותיות.

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

עכשיו משלבים את הטבלה הזו עם מסד הנתונים של התלונות כדי להשוות בין האוכלוסייה למספר התלונות.

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

יוצרים תרשים פיזור כדי להשוות בין אוכלוסיית המדינה למספר התלונות.

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

תרשים פיזור להשוואה בין אוכלוסייה לבין תלונות

יש כמה מדינות שנראות כחריגות בהשוואה בין האוכלוסייה למספר התלונות. הקוראים יכולים לתרגל את הנושא הזה על ידי הצגת הנקודות עם תוויות כדי לזהות אותן. כמו כן, כדאי לנסח כמה השערות לגבי הסיבות לכך (למשל, מאפיינים דמוגרפיים שונים, מספר שונה של חברות שירותים פיננסיים וכו') ולבדוק אותן.

5. חישוב הטמעות

לעיתים קרובות, מידע חשוב מוסתר בנתונים לא מובְנים, כמו טקסט, אודיו או תמונות. בדוגמה הזו, רוב המידע השימושי במסד הנתונים של התלונות נכלל בתוכן הטקסט של התלונה.

טכניקות קיימות ו-AI, כמו ניתוח סנטימנטים, 'תיקיית מילים' ו-word2vec, יכולים לחלץ מידע כמותי מסוים מנתונים לא מובְנים. לאחרונה, מודלים של 'הטמעת וקטורים', שקשורים מאוד ל-LLM, יכולים ליצור רצף של מספרים בנקודה צפה שמייצגים את המידע הסמנטי של הטקסט.

בחירת קבוצת משנה של מסד הנתונים

הפעלת מודל הטמעת וקטורים צורכת יותר משאבים מפעולות אחרות. כדי לצמצם את העלויות ואת הבעיות שקשורות למכסות, כדאי לבחור קבוצת משנה של הנתונים לצורך המשך המדריך.

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 בדצמבר 2022 נשלחו כ-1,000 תלונות, לעומת כ-3.5 מיליון שורות בסך הכול במסד הנתונים (לבדוק עם feedback.shape).

בוחרים רק את הנתונים של 01 בדצמבר 2022 ורק את העמודה 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

כדי להשתמש בשיטה drop_duplicates מ-pandas, צריך לסדר את השורות באופן מלא כי היא מנסה לבחור את השורה התואמת הראשונה או האחרונה ולשמור את המדד שמשויך אליה.

במקום זאת, מבצעים צבירה באמצעות קריאה ל-method‏ groupby כדי לבטל כפילויות בשורות.

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

feedback.shape

יצירת הטמעות (embeddings)

BigQuery DataFrames יוצר וקטורים של הטמעה באמצעות הקלאס TextEmbeddingGenerator. הבדיקה מבוססת על השיטה ML.GENERATE_EMBEDDING ב-BigQuery ML, שמפעילה את המודלים להטמעת טקסט ש-Vertex AI מספק.

from bigframes.ml.llm import TextEmbeddingGenerator

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

איך נראים הטמעות (embeddings) הווקטורים האלה מייצגים את המשמעות הסמנטית של הטקסט כפי שהיא מובנת למודל הטמעת הטקסט.

feedback_embeddings.peek()

הפלט הצפוי:

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

לווקטורים האלה יש הרבה מאפיינים. נבחן וקטור הטמעה יחיד:

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

היצירה של הטמעות פועלת בכפוף לחוזה מסוג 'הצלחה חלקית'. כלומר, יכול להיות שבחלק מהשורות יהיו שגיאות והן לא ייצרו הטמעה. הודעות השגיאה מוצגות בעמודה 'ml_generate_embedding_status'. אם השדה ריק, סימן שאין שגיאות.

מסננים את הטמעות הקוד כך שיכללו רק שורות שבהן לא התרחשה שגיאה.

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

6. קיבוץ באמצעות הטמעות טקסט

עכשיו, מקצים את ה-embeddings לאשכולות באמצעות k-means. בדגמה הזו, נשתמש במספר שרירותי של קבוצות (נקראות גם מרכזי מסה). בפתרון באיכות ייצור, צריך לשנות את מספר מרכזי הכובד באמצעות שיטה כמו שיטת 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()

מסירים את כל הכשלים בהטמעה.

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

הצצה לחלוקת התגובות לפי מרכז כובד.

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

7. סיכום של האשכולות

מזינים כמה הערות שמשויכות לכל מרכז כובד ומבקשים מ-Gemini לסכם את התלונות. הנדסת הנחיות היא תחום חדש יחסית, אבל יש דוגמאות טובות באינטרנט, כמו 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()

משתמשים ב-Gemini כדי לכתוב דוח מהסיכומים.

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. הסרת המשאבים

אם יצרתם פרויקט חדש ב-Google Cloud לצורך המדריך הזה, תוכלו למחוק אותו כדי למנוע חיובים נוספים על טבלאות או משאבים אחרים שיצרתם.

9. מעולה!

ניתחתם נתונים מובְנים ולא מובְנים באמצעות BigQuery DataFrames. לאורך הדרך, הכרתם את מערכי הנתונים הציבוריים של Google Cloud, את ספרי הקוד של Python ב-BigQuery Studio, את BigQuery ML, את Vertex AI ואת התכונות של BigQuery Studio להמרת שפה טבעית ל-Python. עבודה נהדרת!

השלבים הבאים