Получение информации из структурированных и неструктурированных данных с помощью пакета BigQuery DataFrames с поддержкой ИИ

1. Обзор

В этой практической работе вы будете использовать BigQuery DataFrames из блокнота Python в BigQuery Studio, чтобы получать информацию из данных с помощью Python. Используйте генеративный искусственный интеллект от Google, чтобы анализировать и визуализировать неструктурированные текстовые данные.

Вы создадите блокнот Python, чтобы категоризировать и обобщить общедоступную базу данных жалоб клиентов. Его можно адаптировать для работы с любыми неструктурированными текстовыми данными.

Цели

На этом практическом занятии вы научитесь выполнять следующие задачи:

  • Как активировать и использовать блокноты Python в BigQuery Studio
  • Как подключиться к BigQuery с помощью пакета BigQuery DataFrames
  • Как создавать встраиваемые объекты из неструктурированных текстовых данных с помощью BigQuery ML и подключения к конечной точке встраивания текста в Vertex AI
  • Кластеризация встраиваний с помощью BigQuery ML
  • Как обобщать кластеры с помощью большой языковой модели через 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.
  4. Закройте окно выбора шаблона.
  5. Нажмите + Код, чтобы создать новую ячейку с кодом.
  6. Установите последнюю версию пакета BigQuery DataFrames из ячейки кода. Введите следующую команду:
    %pip install --upgrade bigframes --quiet
    
    Нажмите кнопку 🞂 или сочетание клавиш Shift + Ввод, чтобы выполнить код в ячейке.

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 на основе строки запроса или идентификатора таблицы.

Чтобы создать фрейм данных с названием feedback, выполните в новой ячейке кода следующие действия:

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

Как получить основную информацию о фрейме данных

Используйте метод 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. Поскольку в этом фрейме данных нет числовых столбцов, в нем приводится сводка количества ненулевых значений и количества уникальных значений.

Выполните эту ячейку:

# 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.plot.hist(). Поскольку этот фрейм данных в основном содержит строковые и логические данные, мы можем сначала выполнить агрегирование, чтобы узнать больше о различных столбцах.

Подсчитывать количество жалоб, полученных из каждого штата.

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 для скачанного фрейма данных.

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

Линейчатая диаграмма, на которой показано, что в Калифорнии больше всего жалоб

Объединение с другими наборами данных

Раньше вы смотрели жалобы по штатам, но это не давало важного контекста. В некоторых штатах проживает больше людей, чем в других. Объедините с набором данных о населении, например American Community Survey от Бюро переписи населения США и таблицей 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. Рассчитывать представления

Часто важная информация скрыта в неструктурированных данных, таких как текст, аудио или изображения. В этом примере большая часть полезной информации в базе данных жалоб содержится в текстовом контенте жалобы.

ИИ и традиционные методы, такие как анализ тональности, "мешок слов" и word2vec, могут извлекать некоторую количественную информацию из неструктурированных данных. В последнее время появились модели векторных встраиваний, тесно связанные с большими языковыми моделями. Они могут создавать последовательности чисел с плавающей запятой, представляющие семантическую информацию текста.

Как выбрать подмножество базы данных

Для работы модели векторных встраиваний требуется больше ресурсов, чем для других операций. Чтобы снизить расходы и избежать проблем с квотами, выберите подмножество данных для остальной части этого руководства.

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. Поздравляем!

Вы проанализировали структурированные и неструктурированные данные с помощью BigQuery DataFrames. В процессе работы вы познакомились с общедоступными наборами данных Google Cloud, блокнотами Python в BigQuery Studio, BigQuery ML, Vertex AI и функциями преобразования естественного языка в код Python в BigQuery Studio. Продолжайте в том же духе!

Дальнейшие действия