1. Обзор
В этой лабораторной работе вы будете использовать DataFrames из блокнота Python в BigQuery Studio для получения аналитических данных с помощью Python. Воспользуйтесь генеративным искусственным интеллектом Google для анализа и визуализации неструктурированных текстовых данных.
Вам предстоит создать блокнот на Python для классификации и обобщения общедоступной базы данных жалоб клиентов. Его можно адаптировать для работы с любыми неструктурированными текстовыми данными.
Цели
В этой лабораторной работе вы научитесь выполнять следующие задачи:
- Активируйте и используйте блокноты Python в BigQuery Studio.
- Подключитесь к BigQuery, используя пакет BigQuery DataFrames.
- Создавайте векторные представления из неструктурированных текстовых данных с помощью BigQuery ML и подключения к конечной точке для создания векторных представлений текста в Vertex AI.
- Встраивание кластеров с использованием BigQuery ML
- Обобщение кластеров с помощью LLM через BigQuery ML
2. Требования
Прежде чем начать
Для выполнения инструкций в этом практическом задании вам потребуется проект Google Cloud с включенной функцией BigQuery Studio и подключенный платежный аккаунт.
- В консоли Google Cloud на странице выбора проекта выберите или создайте проект Google Cloud.
- Убедитесь, что для вашего проекта Google Cloud включена функция выставления счетов. Узнайте, как проверить, включена ли функция выставления счетов для проекта.
- Следуйте инструкциям, чтобы включить BigQuery Studio для управления ресурсами .
Подготовка BigQuery Studio
Создайте пустой блокнот и подключите его к среде выполнения.
- Перейдите в BigQuery Studio в консоли Google Cloud.
- Нажмите на значок ▼ рядом с кнопкой + .
- Выберите блокнот 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, требующие строгого упорядочивания или индекса, могут не работать.
База данных жалоб потребителей
База данных жалоб потребителей предоставляется в 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 не содержит числовых столбцов, он отображает сводку количества ненулевых значений и числа уникальных значений.
Запустите эту ячейку:
# 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. Вычислите векторные представления.
Often, important information is hidden in unstructured data, such as text, audio, or images. In this example, much of the useful information in the complaints database is contained in the text content of the complaint.
Искусственный интеллект и традиционные методы, такие как анализ настроений, «мешок слов» и 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 года было подано около 1000 жалоб, тогда как в общей базе данных содержится почти 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 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-средних. Для этой демонстрации используйте произвольное количество групп (или центроидов). В решении, соответствующем производственным стандартам, количество центроидов следует настраивать с помощью таких методов, как метод силуэта .
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. Поздравляем!
Вы проанализировали структурированные и неструктурированные данные с помощью DataFrames BigQuery. В процессе работы вы изучили общедоступные наборы данных Google Cloud, блокноты Python в BigQuery Studio, BigQuery ML, Vertex AI и возможности преобразования естественного языка в Python в BigQuery Studio. Отличная работа!
Следующие шаги
- Попробуйте сгенерировать код Python в своем блокноте . Блокноты Python в BigQuery Studio работают на базе Colab Enterprise. Подсказка: я считаю, что обращение за помощью в генерации тестовых данных очень полезно.
- Ознакомьтесь с примерами блокнотов для работы с DataFrames BigQuery на GitHub.
- Создайте расписание для запуска блокнота в BigQuery Studio .
- Разверните удаленную функцию с использованием DataFrames BigQuery для интеграции сторонних пакетов Python с BigQuery.