1. 概要
このラボでは、BigQuery Studio の Python ノートブックから BigQuery DataFrames を使用して、Python でデータから分析情報を取得します。Google の生成 AI を使用して、非構造化テキストデータを分析して可視化します。
Python ノートブックを作成して、一般公開されている顧客の苦情データベースを分類し、要約します。これは、任意の非構造化テキストデータで動作するように調整できます。
目標
このラボでは、次のタスクの実行方法について学びます。
- BigQuery Studio で Python ノートブックを有効にして使用する
- BigQuery DataFrames パッケージを使用して BigQuery に接続する
- BigQuery ML と Vertex AI のテキスト エンベディング エンドポイントへの接続を使用して、非構造化テキストデータからエンベディングを作成する
- BigQuery ML を使用したクラスタ エンベディング
- BigQuery ML を介して LLM でクラスタを要約する
2. 必要なもの
始める前に
この Codelab の手順を行うには、BigQuery Studio が有効になっている Google Cloud プロジェクトと、接続された請求先アカウントが必要です。
- Google Cloud コンソールのプロジェクト選択ページで、Google Cloud プロジェクトを選択または作成します。
- Google Cloud プロジェクトに対して課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。
- 手順に沿って、アセット管理に関する BigQuery Studio を有効にする。
BigQuery Studio を準備する
空のノートブックを作成してランタイムに接続します。
- Google Cloud コンソールで BigQuery Studio に移動します。
- [+] ボタンの横にある [▼] をクリックします。
- [Python ノートブック] を選択します。
- テンプレート セレクタを閉じます。
- [+ コード] を選択して、新しいコードセルを作成します。
- コードセルから BigQuery DataFrames パッケージの最新バージョンをインストールします。次のコマンドを入力します。
[🞂?] ボタンをクリックするか、Shift + Enter キーを押してコードセルを実行します。%pip install --upgrade bigframes --quiet
3. 一般公開データセットを読み取る
新しいコードセルで次のコードを実行して、BigQuery DataFrames パッケージを初期化します。
import bigframes.pandas as bpd
bpd.options.bigquery.ordering_mode = "partial"
注: このチュートリアルでは、試験運用版の「部分並べ替えモード」を使用します。このモードでは、pandas のようなフィルタリングと組み合わせることで、より効率的なクエリを実行できます。厳密な順序付けやインデックスが必要な pandas の機能は動作しない場合があります。
消費者苦情データベース
消費者苦情データベースは、Google Cloud の一般公開データセット プログラムを通じて BigQuery で提供されています。これは、消費者向け金融商品およびサービスに関する苦情を収集したもので、データは米国の消費者金融保護局によって収集されています。
BigQuery で bigquery-public-data.cfbp_complaints.complaint_database テーブルをクエリして、消費者苦情データベースを分析します。bigframes.pandas.read_gbq()
メソッドを使用して、クエリ文字列またはテーブル ID から DataFrame を作成します。
新しいコードセルで次のコードを実行して、「feedback」という名前の DataFrame を作成します。
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. データを探索する
実際の苦情を確認する前に、DataFrame で pandas のようなメソッドを使用してデータを可視化します。
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.to_pandas()
メソッドを使用して、これを pandas DataFrame に変換します。
complaints_pd = complaints_by_state.head(10).to_pandas()
このダウンロードした DataFrame で pandas の可視化メソッドを使用します。
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")
)
人口と苦情の数を比較すると、いくつかの州が外れ値のように見えます。これらのポイントを特定するには、ポイントラベルをプロットして確認してください。同様に、その理由に関する仮説(ユーザー属性の違い、金融サービス会社の数など)を立ててテストします。
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 月 1 日に提出された申し立ては約 1,000 件で、データベース全体の行数は約 350 万件です(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
pandas の drop_duplicates
メソッドは、一致する最初の行または最後の行を選択し、それに関連付けられたインデックスを保持しようとするため、行の完全な順序付けが必要です。
代わりに、groupby
メソッドを呼び出して集計し、重複する行を削除します。
feedback = (
feedback.groupby("consumer_complaint_narrative", as_index=False)
.size()
)[["consumer_complaint_narrative"]]
feedback.shape
エンベディングを生成する
BigQuery DataFrames は、TextEmbeddingGenerator クラスを使用してエンベディング ベクトルを生成します。これは、BigQuery ML の ML.GENERATE_EMBEDDING
メソッドに基づいています。このメソッドは、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 平均法を使用してエンベディングをクラスタリングします。このデモでは、任意の数のグループ(セントロイド)を使用します。本番環境向けのソリューションでは、シルエット法などの手法を使用して重心の数を調整する必要があります。
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 DataFrame を使用して、構造化データと非構造化データを分析しました。ここまで、Google Cloud の一般公開データセット、BigQuery Studio の Python ノートブック、BigQuery ML、Vertex AI、BigQuery Studio の自然言語から Python への機能について学習しました。お疲れさまでした。
次のステップ
- ノートブックで Python コードを生成する方法を試してみてください。BigQuery Studio の Python ノートブックは Colab Enterprise をベースにしています。ヒント: テストデータの生成をサポートしてもらうことは非常に有用です。
- GitHub で BigQuery DataFrames のサンプル ノートブックを確認する。
- BigQuery Studio でノートブックを実行するスケジュールを作成します。
- BigQuery DataFrames でリモート関数をデプロイして、サードパーティの Python パッケージを BigQuery と統合します。