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

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

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

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

מטרות

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

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

2. דרישות

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

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

כדי לפעול לפי ההוראות ב-codelab הזה, תצטרכו פרויקט ב-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. לוחצים על + Code (קוד) כדי ליצור תא קוד חדש.
  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)
)

ממירים את זה ל-pandas DataFrame באמצעות השיטה 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

ב-2022-12-01 הוגשו כ-1,000 תלונות, לעומת כמעט 3.5 מיליון שורות במסד הנתונים הכולל (כדאי לבדוק את הנתון הזה מול feedback.shape).

בוחרים רק את הנתונים של התאריך 2022-12-01 ואת העמודה 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 מחייבת סדר מלא של השורות, כי היא מנסה לבחור את השורה הראשונה או האחרונה שתואמת ולשמור את האינדקס שמשויך אליה.

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

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

feedback.shape

יצירת הטמעות

‫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)

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

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. קיבוץ לאשכולות באמצעות הטמעות טקסט

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

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 ובתכונות של שפה טבעית ל-Python ב-BigQuery Studio. עבודה נהדרת!

השלבים הבאים