รับข้อมูลเชิงลึกจากข้อมูลที่จัดโครงสร้างและไม่จัดโครงสร้างโดยใช้แพ็กเกจ DataFrame ของ BigQuery ที่ทำงานร่วมกับ AI ได้

1. ภาพรวม

ใน Lab นี้ คุณจะได้ใช้ DataFrame ของ BigQuery จาก Notebook ของ Python ใน BigQuery Studio เพื่อรับข้อมูลเชิงลึกจากข้อมูลโดยใช้ Python ใช้ Generative AI ของ Google เพื่อวิเคราะห์และแสดงภาพข้อมูลข้อความที่ไม่มีโครงสร้าง

คุณจะสร้าง Notebook ของ Python เพื่อจัดหมวดหมู่และสรุปฐานข้อมูลการร้องเรียนของลูกค้าแบบสาธารณะ ซึ่งสามารถปรับให้ทำงานกับข้อมูลข้อความที่ไม่มีโครงสร้างได้

วัตถุประสงค์

ในแล็บนี้ คุณจะได้เรียนรู้วิธีทำงานต่อไปนี้

  • เปิดใช้งานและใช้ Notebook ของ Python ใน BigQuery Studio
  • เชื่อมต่อกับ BigQuery โดยใช้แพ็กเกจ BigQuery DataFrames
  • สร้างการฝังจากข้อมูลข้อความที่ไม่มีโครงสร้างโดยใช้ 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

สร้าง Notebook ว่างเปล่าและเชื่อมต่อกับรันไทม์

  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 เพื่อวิเคราะห์ฐานข้อมูลการร้องเรียนของผู้บริโภค ใช้วิธี 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")
)

การสำรวจชุมชนอเมริกันระบุรัฐตาม GEOID รวมกับตารางรัฐเพื่อรับประชากรตามรหัสรัฐ 2 ตัวอักษร

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

แผนภูมิกระจายที่เปรียบเทียบประชากรกับการร้องเรียน

เมื่อเปรียบเทียบประชากรกับจำนวนการร้องเรียนแล้ว ดูเหมือนว่ารัฐ 2 รัฐจะเป็นค่าผิดปกติ ผู้อ่านสามารถลองใช้ป้ายกำกับจุดเพื่อระบุจุดเหล่านี้ ในทำนองเดียวกัน ให้ตั้งสมมติฐานว่าเหตุใดจึงเป็นเช่นนี้ (เช่น ประชากรศาสตร์ที่แตกต่างกัน จำนวนบริษัทที่ให้บริการทางการเงินที่แตกต่างกัน ฯลฯ) และทดสอบสมมติฐานเหล่านั้น

5. คำนวณการฝัง

บ่อยครั้งที่ข้อมูลสำคัญซ่อนอยู่ในข้อมูลที่ไม่มีโครงสร้าง เช่น ข้อความ เสียง หรือรูปภาพ ในตัวอย่างนี้ ข้อมูลที่เป็นประโยชน์ส่วนใหญ่ในฐานข้อมูลการร้องเรียนจะอยู่ในเนื้อหาข้อความของการร้องเรียน

AI และเทคนิคแบบดั้งเดิม เช่น การวิเคราะห์ความรู้สึก "Bag of Words" และ 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,000 รายการที่ส่งเมื่อวันที่ 01-12-2022 เทียบกับแถวเกือบ 3.5 ล้านแถวในฐานข้อมูลทั้งหมด (ตรวจสอบกับ feedback.shape)

เลือกเฉพาะข้อมูลสำหรับวันที่ 01-12-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 ต้องมีการจัดลําดับแถวทั้งหมดเนื่องจากพยายามเลือกแถวแรกหรือแถวสุดท้ายที่ตรงกัน และเก็บดัชนีที่เชื่อมโยงไว้

แต่ให้รวบรวมด้วยการเรียกใช้เมธอด groupby เพื่อนำแถวที่ซ้ำกันออก

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

feedback.shape

สร้างการฝัง

BigQuery DataFrame จะสร้างเวกเตอร์การฝังผ่านคลาส 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, Notebook ของ Python ใน BigQuery Studio, BigQuery ML, Vertex AI และฟีเจอร์ภาษาธรรมชาติเป็น Python ของ BigQuery Studio ยอดเยี่ยมมาก

ขั้นตอนถัดไป