TowardsDataScience 2023 博客中文翻译(三百五十三)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

使用枚举和 functools 升级你的 Pandas 数据管道

原文:towardsdatascience.com/using-enums-and-functools-to-upgrade-your-pandas-data-pipelines-d51ca1418fe2

编程

通过两个逐步示例,看看如何更高效地编程以处理你的数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Byron Dolon

·发布于Towards Data Science ·12 分钟阅读·2023 年 6 月 9 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片使用了我才华横溢的姐姐ohmintyartz的许可。

你可能在创建数据管道以处理原始数据时曾使用过 Pandas。编写代码来过滤、分组和执行数据计算只是构建数据管道和 ETL 过程的第一步。

在大规模数据处理时,除了这些,我们还应该编写功能性易于阅读和维护的代码。

有许多方法可以改进你现有的数据管道,比如添加高效的日志记录、包括数据验证,甚至使用除 Pandas 之外的新库,如 PySpark 和 Polars。

此外,你还可以不同地结构化你用于处理数据的实际代码。这意味着不是为了提高管道的性能,而是专注于编写易于修改和迭代的代码。

在这篇文章中,我们将通过两个简单的例子来看看如何做到这一点,特别是通过使用枚举functools

随意在你选择的笔记本或 IDE 中跟随操作!你可以从 Kaggle这里下载数据集,CC0 1.0 通用(CC0 1.0)公共领域献身许可下免费使用。然后导入并运行以下内容,我们可以开始了!

import pandas as pd
from pandas import DataFrame
import numpy as np

from functools import reduce
from enum import Enum

FILE_PATH = "/Updated_sales.csv"
CHUNK_SIZE = 1000

def read_raw_data(file_path: str, chunk_size: int=1000) -> DataFrame:
    csv_reader = pd.read_csv(file_path, chunksize=chunk_size)
    processed_chunks = []

    # append the processed chunk to the list
    for chunk in csv_reader:
        chunk = chunk.loc[chunk["Order ID"] != "Order ID"].dropna()
        processed_chunks.append(chunk)

    # concatenate the processed chunks into a single DataFrame
    return pd.concat(processed_chunks, axis=0)

df = read_raw_data(file_path=FILE_PATH)

使用枚举更好地结构化你的数据管道

对枚举的快速介绍

你可能首先会想“什么是枚举”?

枚举,简称“enum”,是“一组与唯一值绑定的符号名称(成员)” (Python docs, 2023)。实际来说,这意味着你可以在一个主要的“类”下定义和使用一组相关的变量。

一个简单的例子是有一个枚举类“Color”,其中包含“Red”,“Green”和“Blue”等名称,每当你想引用特定颜色时都可以使用它们。

接下来,你可能会想,如果你可以直接在数据处理管道中调用所需的名称,定义一些变量在单独的枚举类中还有什么意义呢?

枚举有一些关键的好处:

  • 定义枚举可以让你将相关的常量组织在一个(或多个)类中,这些类可以作为你在管道中调用的维度、度量和其他常量的真实来源;

  • 使用枚举将帮助你避免在数据管道中传递无效值,前提是你正确地定义和维护了枚举类;

  • 枚举允许用户使用标准化的数据点和常量集,这在多人基于一个主要数据源进行聚合或创建模型时非常有用(有助于避免在原始数据源中对同一列有多个定义或别名)。

听起来有点抽象,所以让我们看看在标准预处理管道中如何实际应用枚举的例子。

在你的数据处理管道中使用枚举

我们已经有了初始的 DataFrame,所以让我们开始创建一个函数,通过拆分购买地址来向数据中添加更多列。

def split_purchase_address(df_to_process: DataFrame) -> DataFrame:
    df_address_split = df_to_process["Purchase Address"].str.split(",", n=3, expand=True)
    df_address_split.columns = ["Street Name", "City", "State and Postal Code"]

    df_state_postal_split = (
        df_address_split["State and Postal Code"]
        .str.strip()
        .str.split(" ", n=2, expand=True)
    )
    df_state_postal_split.columns = ["State Code", "Postal Code"]

    return pd.concat([df_to_process, df_address_split, df_state_postal_split], axis=1)

接下来,我们可以通过使用 Pandas 的原生pipe方法将其应用于现有的表,例如,我们在 DataFrame 上调用 pipe 并将函数名作为参数传递。

processed_df = df.pipe(split_purchase_address)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来,你会看到我们拥有的数据仍然处于非常详细的层次,订单 ID 是表的主键。当我们想要对数据进行聚合以进行进一步分析时,可以使用 Pandas 中的groupby方法来实现。

在 Pandas 中,你可能会看到一些代码用于在一组列上对数据进行分组,然后对其中一个维度(在这个例子中我们将使用订单 ID)进行聚合计数,看起来可能是这样的:

# groupby normally
grouped_df = (
    processed_df
    .groupby(
        ["Product", "Quantity Ordered", "Street Name", "City", "State Code", "Postal Code"]
    )
    ["Order ID"]
    .count()
    .reset_index()
    .sort_values("Order ID", ascending=False)
    .rename({"Order ID": "Count of Order IDs"}, axis=1)
)

结果是一个新的 DataFrame,像这样:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这个简单的例子中,按六列进行分组并不太困难,我们可以将这些列的列表直接传递给groupby方法。然而,这有一些缺点:

  • 如果我们处理的是一个更大的数据集,并且希望按 20 列进行分组怎么办?

  • 如果最终用户提出了新的需求,我们需要调整具体的列进行分组怎么办?

  • 如果底层表发生变化,列的名称或别名发生变化怎么办?

我们可以通过在枚举类中定义列来部分解决这些问题。特别是对于这种情况,我们可以在一个新的类SalesGroupByColumns中定义这些与销售表相关的分组列,如下所示:

class SalesGroupByColumns(Enum):
    PRODUCT = "Product"
    QUANTITY_ORDERED = "Quantity Ordered"
    STREET_NAME = "Street Name"
    CITY = "City"
    STATE_CODE = "State Code"
    POSTAL_CODE = "Postal Code"

我们在这里做的最终只是将列定义为新的 Enum 类中的常量(这是从from enum import Enum的导入中获得的)。

现在我们已经定义了这些新的枚举值,我们可以像这样访问枚举的各个成员:

SalesGroupByColumns.PRODUCT

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

SalesGroupByColumns.PRODUCT.value

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

只需调用枚举名称将返回枚举成员,并且在目标枚举上调用value让我们直接访问枚举成员的字符串值。现在,要将所有枚举成员放入我们可以传递给groupby的列表中,我们可以像这样使用列表推导式:

[column.value for column in SalesGroupByColumns]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在将它们放入列表后,我们可以将这个输出分配给一个变量,然后将这个变量传递给我们的groupby方法,而不是直接传递原始的字符串列表:

# groupby adjusted
groupby_columns = [column.value for column in SalesGroupByColumns]

grouped_df = (
    processed_df
    .groupby(groupby_columns)
    ["Order ID"]
    .count()
    .reset_index()
    .sort_values("Order ID", ascending=False)
    .rename({"Order ID": "Count of Order IDs"}, axis=1)
)

grouped_df.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们得到了与之前相同的表格,但代码看起来稍微更干净。对于长期维护来说,这种做法的好处可以在你处理管道时体现出来。

例如,你可能会发现你想添加几个新的列,比如说如果你还想进行更多的特征工程,创建一个房屋号码和产品类别列,然后添加到分组中。你可以这样更新你的枚举类:

# what's the benefit? adding new columns!

class SalesGroupByColumns(Enum):
    PRODUCT = "Product"
    QUANTITY_ORDERED = "Quantity Ordered"
    STREET_NAME = "Street Name"
    CITY = "City"
    STATE_CODE = "State Code"
    POSTAL_CODE = "Postal Code"
    HOUSE_NUMBER = "House Number"
    PRODUCT_CATEGORY = "Prouct Category"

# then you run the code same as before and it would still work

这样,你就不需要修改现有的处理代码,因为列表推导式会自动获取SalesGroupByColumns类中的所有值,并将其应用于你的聚合逻辑。

一个好的提示是,所有这些仅在你确切知道你在枚举类中定义了什么并仅按预期使用它们时才会有效。如果你在这里进行更改,并且你在几个不同的表中抓取所有这些列进行分组,重要的是要确保那是你打算做的。

否则,你可以在单独的类中定义你需要用于特定表的枚举集,或者如果有意义的话,在单独的列列表中(这样你仍然避免将原始字符串列表传递给groupby方法)。

在 Pandas 中使用枚举进行数据聚合

另一个例子是,假设我们有一个不同的情况,我们通过更改一些列的数据类型和创建一个新的总成本列来对数据进行一些额外的转换。我们可以像这样将其添加到之前的管道中:

def convert_numerical_column_types(df_to_process: DataFrame) -> DataFrame:
    df_to_process["Quantity Ordered"] = df_to_process["Quantity Ordered"].astype(int)
    df_to_process["Price Each"] = df_to_process["Price Each"].astype(float)
    df_to_process["Order ID"] = df_to_process["Order ID"].astype(int)

    return df_to_process

def calculate_total_order_cost(df_to_process: DataFrame) -> DataFrame:
    df_to_process["Total Cost"] = df_to_process["Quantity Ordered"] * df_to_process["Price Each"]
    return df_to_process

processed_df = (
    df
    .pipe(split_purchase_address)
    .pipe(convert_numerical_column_types)
    .pipe(calculate_total_order_cost)
)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们的 DataFrame 在订单 ID 级别上已经转换过来,接下来我们在一组新列上进行另一个分组,但这次对几个不同的度量进行聚合:

# let's say we have a file now "SalesColumns.py"
# we can add to it

import numpy as np

class AddressColumns(Enum):
    STREET_NAME = "Street Name"
    CITY = "City"
    STATE_CODE = "State Code"
    POSTAL_CODE = "Postal Code"

class SalesMeasureColumns(Enum):
    TOTAL_COST = "Total Cost"
    QUANTITY_ORDERED = "Quantity Ordered"    

# then separately we can do the groupby
groupby_columns = [column.value for column in AddressColumns]

grouped_df = (
    processed_df
    .groupby(groupby_columns)
    .agg(
        Total_Cost=(SalesMeasureColumns.TOTAL_COST.value, np.sum),
        Total_Quantity_Ordered=(SalesMeasureColumns.QUANTITY_ORDERED.value, np.sum)
    )
    .reset_index()
    .sort_values("Total_Cost", ascending=False)
)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里有几个关键点需要注意:

  • 我们定义了一组新的枚举类:AddressColumnsSalesMeasureColumns。现在,对于一个不同的表格,如果我们想要专门按地址字段进行分组,我们可以定义 groupby_columns 列表来包括这些列,然后将其传递给转换后的 DataFrame 的 groupby 方法。

  • SalesMeasureColumns 类包括我们希望进行聚合的度量。将原始表格中的列名放入该类中意味着如果其他人也希望汇总成本和订购数量,他们会调用正确的列。

我们可以进一步在之前的管道中添加之前定义的链式管道和函数,并将此代码放入新函数中以收集列列表并聚合表格。这样,最终代码变得更容易阅读,并且随着时间的推移,可能更容易调试和记录。

对于聚合,总成本和订购数量在不同的表格、团队和最终用户中可能会有所不同。在 SalesMeasuresColumns 的枚举中定义它,意味着对于 Sales 表格和度量,所有用户都可以使用相同的定义对这些列进行聚合。

利用 functools 的 reduce 方法来简化你的数据过滤

现在,让我们来看看如何使用 functools 的 reduce 方法来改进数据过滤。

在 Pandas 中,过滤原始数据的常见方法是使用 loc 方法。例如,让我们写一些代码来过滤包含“North”的街道数据。

grouped_df.loc[grouped_df["Street Name"].str.contains("North")]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们的输出 DataFrame 现在只包括根据过滤器筛选的列。一般来说,在对特定问题进行分析或调整数据集以适应机器学习模型时,你可能希望对 DataFrame 应用多个过滤器。你可以这样使用 loc 方法应用多个过滤器:

grouped_df.loc[
    (grouped_df["Street Name"].str.contains("North")) &
    (grouped_df["Postal Code"].str.contains("940")) &
    (grouped_df["Total_Cost"] < 1000)
]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来,就像之前优化代码时使用枚举一样,如果我们想要添加、编辑或删除一些过滤器会怎么样?来自最终用户的需求变化或从一些探索性数据分析中获得的新见解可能意味着你需要随着时间的推移调整过滤数据的方式。

与其继续在 loc 方法中添加更多的代码行,我们可以在一个变量中定义过滤器列表,然后稍后将其传递给 loc

filter_conditions = [
    grouped_df["Street Name"].str.contains("North"),
    grouped_df["Postal Code"].str.contains("940"),
    grouped_df["Total_Cost"] < 1000
]

然而,我们不能直接将这个列表传递给 locloc 中的多个条件接受的格式是由 DataFrame 的布尔掩码组成,通过 & 运算符分隔。

# doesn't work -> you can't just pass a list into loc
df.loc[FILTER_CONDITIONS]

# format should look like this
df.loc[condition_1 & condition_2 & condition_3]

这就是 functools.reduce 方法发挥作用的地方。如何实现正确的格式可以在这里的示例中看到:

# functools reduce
reduce(lambda x, y: f"{x} & {y}", ["condition_1", "condition_2", "condition_3"])

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这个简单的示例中,我们只是将一堆字符串组合在一起,以输出稍后在 loc 方法中需要写的内容。

functools 中的reduce方法允许你将函数和可迭代对象作为参数传递。reduce方法然后将函数应用于可迭代对象中的元素,逐步执行。这意味着它会对可迭代对象中的元素集合进行顺序操作。

在我们的例子中,我们有一个匿名lambda函数,它接受两个参数xy,并使用 f-string 将它们结合起来,用&操作符分隔。这意味着首先函数会输出condition_1 & condition_2,然后将condition_3添加到第一个累计值中,结果就是condition_1 & condition_2 & condition_3

现在,我们可以将这个 reduce 方法与函数和过滤条件传递给loc方法,而不是逐个将所有原始过滤条件传递给loc

grouped_df.loc[reduce(lambda x, y: x & y, filter_conditions)]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

应用所有过滤器后的最终 DataFrame 如下所示。如果你想要添加另一个过滤器,只需将其添加到现有的filter_conditions变量中,其他代码保持不变。

这篇文章的重点是展示几种不同的代码结构方式,以提高代码的可读性和可维护性。虽然这些改变不一定会加快你的管道速度或改善内存使用,但考虑代码的易用性是很重要的。

这有两个好处:

  1. 如果多人同时处理相同的原始数据,将列名和过滤器定义在一个集中位置意味着每个人都可以参考一个唯一的真实来源,避免出现不同的名称和逻辑却最终指代同一事物的情况;

  2. 当处理包含变化需求的数据时,你只需在一个地方修复列名和逻辑即可加快开发时间。

希望你觉得这些改善数据管道的技巧有帮助。尝试一下这种数据处理结构,看看它是否适合你!

如果你喜欢我的内容,可以考虑关注我并通过下面的链接注册成为 Medium 会员。每月只需 5 美元,你将获得对 Medium 上所有内容的无限制访问。通过我的链接注册可以让我赚取少量佣金。如果你已经注册关注我,感谢你的支持!

[## 通过我的推荐链接加入 Medium — Byron Dolon

作为 Medium 会员,你的一部分会员费用会支付给你阅读的作者,而你可以完全访问每个故事……

byrondolon.medium.com](https://byrondolon.medium.com/membership?source=post_page-----d51ca1418fe2--------------------------------)

更多内容: - 3 种高效的方式通过子字符串过滤 Pandas DataFrame 列

- 5 条实用建议给有志于数据分析的新人 - 使用 Python 中的堆叠条形图改进数据可视化 - C**onditional Selection and Assignment With .loc in Pandas - 5(以及半个)行代码用以理解 Pandas 中的数据

使用从 BERT 嵌入中衍生的向量表示的傅里叶变换进行语义相似度评估

原文:towardsdatascience.com/using-fourier-transform-of-vector-representations-derived-from-bert-embeddings-for-semantic-9d91a7d4839c?source=collection_archive---------1-----------------------#2023-01-14

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Igor Shabalin 提供,已获许可

探索通过评估 BERT 嵌入的不同表示来了解句子中词语的相互影响

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Yuli Vasiliev

·

关注 发布于 Towards Data Science ·5 min read·2023 年 1 月 14 日

BERT 嵌入在程序化提取文本意义方面提供了极大的机会。似乎我们(以及机器)理解文本所需的一切都隐藏在这些数字中。关键在于如何正确地操作这些数字。我在我最近的帖子中讨论了这一概念 发现 BERT 嵌入在不同层次中的趋势,用于语义上下文确定任务。本文继续讨论这一主题,探讨通过对 BERT 嵌入应用傅里叶变换得到的向量表示是否在 NLP 任务中的意义提取方面也有用。

假设

正如你可能从物理学中知道的那样,傅里叶变换使我们能够理解信号中的频率。表示单词嵌入的向量是否看起来像信号?也就是说,从傅里叶变换得出的频域知识在处理 BERT 嵌入以发现语义接近性时是否有用?简单来说,傅里叶变换在分析 BERT 嵌入时是否有意义?让我们来检查一下。

实验

本文剩余部分讨论的例子假设你已经按照 之前的帖子 中的示例定义了模型。我们还需要从该 之前的帖子 中讨论的样本句子中获得的表示。请注意,本文使用了一组与上述帖子中使用的样本稍有不同的样本。因此,在创建表示之前,你需要定义以下样本:

sents = []
sents.append(‘I had a very good apple.)
sents.append(‘I had a very good orange.)
sents.append(‘I had a very good adventure.)

正如你所看到的,所有句子都有相同的直接宾语修饰词集合,而直接宾语在每个句子中都是不同的。我们实验的目的是检查直接宾语的语义接近性如何影响修饰词的接近程度。

之前的帖子中已经介绍了对样本句子进行分词和生成隐藏状态的过程。因此我们在这里不会重复这个过程。

让我们专注于每个句子中直接宾语(“apple/orange/adventure”)的修饰词(“a/very/good”)。为了在获取其嵌入时使用正确的索引,我们首先检查一下句子中的词元:

for i in range(len(sents)):
 print(tokenizer.convert_ids_to_tokens(tokenized_text[i]))
[[CLS], ‘i’, ‘had’, ‘a’, ‘very’, ‘good’, ‘apple’,.,[SEP]]
[[CLS], ‘i’, ‘had’, ‘a’, ‘very’, ‘good’, ‘orange’,.,[SEP]]
[[CLS], ‘i’, ‘had’, ‘a’, ‘very’, ‘good’, ‘adventure’,.,[SEP]]

由于我们对直接宾语的修饰词(在这个具体的例子中,我们有三个修饰词:a, very, good)感兴趣,我们需要索引为 3,4,5 的词元。因此,我们需要将索引偏移 3。以下,我们将为每个修饰词在每个句子中获取上下文嵌入。我们将把修饰词嵌入保存在为每个句子定义的列表中:

l12_1 = []
l12_2 = []
l12_3 = []
for i in range(3):
 l12_1.append(hidden_states[0][12][0][i+3][:10].numpy())
 l12_2.append(hidden_states[1][12][0][i+3][:10].numpy())
 l12_3.append(hidden_states[2][12][0][i+3][:10].numpy())

现在让我们来探讨不同句子中直接宾语的语义相似性如何影响各自修饰语的相似性。

from scipy import spatial
for i in range(3):
 print(1 — spatial.distance.cosine(l12_1[i], l12_2[i]))
0.9003266096115112
0.9178041219711304
0.8865049481391907

在上述输出中,我们可以看到“Apple”和“Orange”修饰语的上下文嵌入显示了高度的相似性。这是可以理解的,因为直接宾语“Apple”和“Orange”本身非常接近。

虽然从以下结果来看,“Apple”和“Adventure”修饰语的表示并不太接近:

for i in range(3):
 print(1 — spatial.distance.cosine(l12_1[i], l12_3[i]))
0.49141737818717957
0.7987119555473328
0.6404531598091125

“Orange”和“Adventure”修饰语也不应该太接近:

for i in range(3):
 print(1 — spatial.distance.cosine(l12_2[i], l12_3[i]))
0.7402883768081665
0.8417230844497681
0.7215733528137207

现在让我们从 BERT 提供的嵌入中推导出更复杂的表示。首先,让我们获取每个句子中修饰语的初始嵌入:

l0_1 = []
l0_2 = []
l0_3 = []
for i in range(3):
 l0_1.append(hidden_states[0][0][0][i+3][:10].numpy())
 l0_2.append(hidden_states[1][0][0][i+3][:10].numpy())
 l0_3.append(hidden_states[2][0][0][i+3][:10].numpy())

现在,我们可以,例如,通过将上下文嵌入(在第 12 层编码器中生成)除以相应的初始嵌入(如前面帖子中讨论的),得到一些新的嵌入表示,用于进一步分析。

import numpy as np
l0_12_1 = []
l0_12_2 = []
l0_12_3 = []
for i in range(3):
 l0_12_1.append(np.log(l12_1[i]/l0_1[i]))
 l0_12_2.append(np.log(l12_2[i]/l0_2[i]))
 l0_12_3.append(np.log(l12_3[i]/l0_3[i]))
for i in range(3):
 l0_12_1[i] = np.where(np.isnan(l0_12_1[i]), 0, l0_12_1[i])
 l0_12_2[i] = np.where(np.isnan(l0_12_2[i]), 0, l0_12_2[i])
 l0_12_3[i] = np.where(np.isnan(l0_12_3[i]), 0, l0_12_3[i])

为了分析目的,你可能还想创建另一组表示,计算上下文嵌入与非上下文(初始)嵌入之间的逐元素差异。

_l0_12_1 = []
_l0_12_2 = []
_l0_12_3 = []
for i in range(3):
 _l0_12_1.append(l12_1[i]-l0_1[i])
 _l0_12_2.append(l12_2[i]-l0_2[i])
 _l0_12_3.append(l12_3[i]-l0_3[i])

在继续评估我们刚创建的表示之前,让我们使用傅里叶变换创建另一组表示,以便随后可以比较不同方法获得的所有表示。

fourierTransform_1=[]
fourierTransform_2=[]
fourierTransform_3=[]
for i in range(3):
 fourierTransform_1.append(np.fft.fft(l0_12_1[i])/len(l0_12_1[i]))
 fourierTransform_2.append(np.fft.fft(l0_12_2[i])/len(l0_12_2[i]))
 fourierTransform_3.append(np.fft.fft(l0_12_3[i])/len(l0_12_3[i]))

现在我们可以比较每个修饰语的每对句子的获得表示。

print (sents[0])
print (sents[1])
print()
for i in range(3):
 print(tokenizer.convert_ids_to_tokens(tokenized_text[0][i+3]))
 print(‘diff’, 1 — spatial.distance.cosine(_l0_12_1[i], _l0_12_2[i]))
 print(‘log_quotient’, 1 — spatial.distance.cosine(l0_12_1[i], l0_12_2[i]))
 print(‘fourier’, 1 — spatial.distance.cosine(abs(fourierTransform_1[i]), abs(fourierTransform_2[i])))
 print()

生成的输出应如下所示:

I had a very good apple.
I had a very good orange.
a
diff 0.8866338729858398
log_quotient 0.43184104561805725
fourier 0.9438706822278501
very
diff 0.9572229385375977
log_quotient 0.9539480209350586
fourier 0.9754009221726183
good
diff 0.8211167454719543
log_quotient 0.5680340528488159
fourier 0.7838190546462953

在上述实验中,我们期望看到前两个句子中的相同修饰语之间具有高度的相似性。实际上,我们可以看到差异和傅里叶变换方法在任务中表现良好。

以下实验的目的是确定那些被修饰的名词不太接近的修饰语的相似性。

print (sents[0])
print (sents[2])
print()
for i in range(3):
 print(tokenizer.convert_ids_to_tokens(tokenized_text[0][i+3]))
 print(‘diff’, 1 — spatial.distance.cosine(_l0_12_1[i], _l0_12_3[i]))
 print(‘log_quotient’, 1 — spatial.distance.cosine(l0_12_1[i], l0_12_3[i]))
 print(‘fourier’, 1 — spatial.distance.cosine(abs(fourierTransform_1[i]), abs(fourierTransform_3[i])))
 print()

这是输出结果:

I had a very good apple.
I had a very good adventure.
a
diff 0.5641788840293884
log_quotient 0.5351020097732544
fourier 0.8501702469740261
very
diff 0.8958494067192078
log_quotient 0.5876994729042053
fourier 0.8582797441535993
good
diff 0.6836684346199036
log_quotient 0.18607155978679657
fourier 0.8857107252606878

上述输出显示,当评估那些相关名词不是非常接近的修饰语的相似性时,差异和对数商的效果最好。

print (sents[1])
print (sents[2])
print()
for i in range(3):
 print(tokenizer.convert_ids_to_tokens(tokenized_text[0][i+3]))
 print(‘diff’, 1 — spatial.distance.cosine(_l0_12_2[i], _l0_12_3[i]))
 print(‘log_quotient’, 1 — spatial.distance.cosine(l0_12_2[i], l0_12_3[i]))
 print(‘fourier’, 1 — spatial.distance.cosine(abs(fourierTransform_2[i]), abs(fourierTransform_3[i])))
 print()

输出结果如下:

I had a very good orange.
I had a very good adventure.
a
diff 0.8232558369636536
log_quotient 0.7186723351478577
fourier 0.8378725099204362
very
diff 0.9369465708732605
log_quotient 0.6996179223060608
fourier 0.9164374584436726
good
diff 0.8077239990234375
log_quotient 0.5284199714660645
fourier 0.9069805698881434

我们再次看到,当评估那些相关名词不是非常接近的修饰语的相似性时,差异和对数商的效果最好。

结论

在分析 BERT 嵌入时,傅里叶变换是否有意义?根据本文所做的实验,我们可以得出结论,这种方法可以有效地与其他方法结合使用。

使用 GPT-3.5-Turbo 和 GPT-4 进行人道主义数据类别预测

原文:towardsdatascience.com/using-gpt-3-5-turbo-and-gpt-4-to-apply-text-defined-data-quality-checks-on-humanitarian-datasets-6f02219c693c?source=collection_archive---------5-----------------------#2023-03-29

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Matthew Harris

·

关注 发表在数据科学之道 · 23 分钟阅读 · 2023 年 3 月 29 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图像由稳定扩散创建,提示词为“预测猫”。

总结

在本文中,我探讨了使用 GPT-3.5-Turbo 和 GPT-4 对数据集进行分类,而不需要标记数据或模型训练,通过向模型提供数据摘录和类别定义。使用从令人惊叹的人道主义数据交换(HDX)找到的一小部分已分类的“数据网格”数据集,GPT-4 的零-shot 提示在预测类别时达到了 96%的准确率,而在预测类别和子类别时达到了 89%的准确率。GPT-4 在相同提示下的表现优于 GPT-3.5-Turbo,类别准确率为 96%对 66%。尤其有用的是,模型能够提供其预测的推理,这有助于识别改进过程。这只是由于成本限制而涉及少量记录的快速分析,但它显示了使用大型语言模型进行数据质量检查和总结的一些前景。由于提示中允许的最大令牌数量影响数据摘录中可以包含的数据量,以及性能和成本挑战——特别是如果你是一个小型非营利组织!——在商业生成 AI 的早期阶段存在局限性。

人道主义数据交换(HDX)平台有一个很棒的功能叫做HDX 数据网格,它提供了按国家划分的六个关键危机类别的高质量数据覆盖概述,查看这里了解乍得的例子。进入网格的数据集会经过 HDX 团队一系列严格的测试以确定覆盖范围和质量,其中第一个测试是确定数据集是否在批准的类别中。

我在想,也许大型语言模型(LLMs)可能是一个有效的方法来应用数据质量和分类规则,在那些可能没有标记训练数据的情况下。这也很方便,以人类可读的文本形式提供规则,非技术团队可以轻松维护,并直接使用这些规则以消除对特征工程和模型管理的需求。

哦,我最近也获得了 GPT-4 的早期访问权限,想要试一试!🙂……所以决定也进行一些分析,比较 GPT-3.5-Turbo 的表现。

数据集是否在已批准的类别中?

查看《2023 年人道主义数据现状 附录 B》,其中概述了在评估数据是否具有足够质量和覆盖范围时使用的标准和类别……

确定数据集是否应包含在数据网格中的第一步是检查数据集是否符合附录 A 中定义的主题要求。不相关的数据集将被自动排除。

附录 A 中的类别是……

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

HDX 数据网格数据集的接受数据类别(见 HDX 年度报告,附录 A [1])

我们可以编写分类器将这些类别分配给我们的数据集,但我们只知道已批准的 HDX 数据网格数据集的子集的类别。如果仅通过提示就能对我们的数据进行分类而不需要手动标记,那将是太棒了。这是一个零-shot 任务[2],这是大语言模型的一个惊人特性,即可以在没有专门为任务训练或提供示例的情况下进行分类。

为单个表预测数据集类别

让我们读取类别数据,并使用它生成定义每一类的提示文本……

hdx_data_categories_file = './data/Data Completeness Definitions  - version_1.csv'
dg_categories = pd.read_csv(hdx_data_categories_file)
dg_categories = dg_categories[
    ["Category", "Subcategory", "Definition", "Datagrid recipe category"]
]
dg_categories["prompt_text"] = dg_categories.apply(
    lambda x: f"- Category '{x['Category']} : {x['Subcategory']}' is defined as: {x['Definition']}",
    axis=1,
)

category_prompt_text = dg_categories["prompt_text"].to_string(index=False, header=False)
display(category_prompt_text)

这给出……

- Category \'Affected People : Internally Displaced Persons\' is defined as: Tabular data of the number of displaced people by location. Locations can be administrative divisions or other locations (such as camps) if an additional dataset defining those locations is also available.\n                                              
- Category \'Affected People : Refugees and Persons of Concern\' is defined as: Tabular data of the number of refugees and persons of concern either in the country or originating from the country disaggregated by their current location. Locations can be administrative divisions or other locations (such as camps) if an additional dataset defining those locations is also available or if the locations\' coordinates are defined in the tabular data.\n                                                                                                                                                                                                                                                                                                                                                                                  
- Category \'Affected People : Returnees\' is defined as: Tabular data of the number of displaced people who have returned.\n                                                                                                                                                                                                                                                                                                                      
- Category \'Affected People : Humanitarian Needs\' is defined as: Tabular data of the number of people in need of humanitarian assistance by location and humanitarian cluster/sector.\n                                                                                                                                                                                                                                                                                       
- Category \'Coordination & Context : 3W - Who is doing what where\' is defined as: List of organisations working on humanitarian issues, by humanitarian cluster/sector and disaggregated by administrative division.\n                                                                                                                                                                                                                                                                                                                                                                                                                         
- Category \'Coordination & Context : 3W - Who is doing what where\' is defined as: \n                                                                                                                                                                                                                                                                        
- Category \'Coordination & Context : 3W - Who is doing what where\' is defined as: Note: An exception for the subnational rule is made for the IATI dataset which, if available, should always be included as an incomplete dataset.\n                                                                                                                                                                                                                                                                                                                                                           
- Category \'Coordination & Context : Funding\' is defined as: Tabular data listing the amount of funding provided by humanitarian cluster/sector.\n                                                                                                                                                                                                                                                                                                                                                                                                                                              
- Category \'Coordination & Context : Funding\' is defined as: \n                                                                                                                                                                                                                                                                                                 
- Category \'Coordination & Context : Funding\' is defined as: Note: An exception for the subnational rule is made for the FTS dataset which, if available, should always be included as a complete dataset.\n                                                                                                                                                                                                                                                                                                                               
- Category \'Coordination & Context : Conflict Events\' is defined as: Vector data or tabular data with coordinates describing the location, date, and type of conflict event.\n                                                                                                                                                                                                                                              
- Category \'Coordination & Context : Humanitarian Access\' is defined as: Tabular or vector data describing the location of natural hazards, permissions, active fighting, or other access constraints that impact the delivery of humanitarian interventions.\n                                                              
- Category \'Coordination & Context : Climate Impact\' is defined as: Tabular or vector data containing current and historical impacts of climate events relating to floods, droughts and storms. The data should specify the location of the event, date of the event, and contain at least one indicator of impact such as spatial extent of event, disruption to affected populations, destroyed infrastructure, and/or affected vegetation.\n                                                                                                                                                                                                                                      
- Category \'Food Security & Nutrition : Food Security\' is defined as: Vector data representing the IPC/CH acute food insecurity phase classification or tabular data representing population or percentage of population by IPC/CH phase and administrative division.\n                                                                                                                                                                                                                                                                                                
- Category \'Food Security & Nutrition : Acute Malnutrition\' is defined as: Tabular data specifying the global acute malnutrition (GAM) or severe acute malnutrition (SAM) rate\xa0 by administrative division.\n                                                                                                                                                                                                                                                                                                                                                                  
- Category \'Food Security & Nutrition : Food Prices\' is defined as: Time series prices for common food commodities at a set of locations.\n- Category \'Geography & Infrastructure : Administrative Divisions\' is defined as: Vector geographic data describing the sub-national administrative divisions of a location, usually a country, including the names and unique identifiers, usually p-codes, of each administrative division. To be considered "complete", and included here, the humanitarian community working in the location has to have endorsed a preferred set of administrative boundaries as the Common Operational Dataset (COD).\n                                                                                                                                                                                                                                                                                                            
- Category \'Geography & Infrastructure : Populated Places\' is defined as: Vector data or tabular data with coordinates representing the location of populated places (cities, towns, villages).\n                                                                                                                                                                           
- Category \'Geography & Infrastructure : Roads\' is defined as: Geographic data describing the location of roads with some indication of the importance of each road segment in the transportation network. The data should exclude or indicate roads that are not usable by typical four-wheel-drive vehicles (footpaths, etc.).\n                                                                                                                                                                                                                                                                              
- Category \'Geography & Infrastructure : Airports\' is defined as: Geographic data representing all operational airports including a name or other unique identifier and an indication of what types of aircraft can use each.\n                                                                                                                                                                                                                                                                                      
- Category \'Health & Education : Health Facilities\' is defined as: Vector data or tabular data with coordinates representing health facilities with some indication of the type of facility (clinic, hospital, etc.).\n                                                                                                                                                                                                                                                                              
- Category \'Health & Education : Education Facilities\' is defined as: Vector data or tabular data with coordinates representing education facilities with some indication of the type of facility (school, university, etc.).\n                                                                                                                                                                                                                                                                                                                                 
- Category \'Population & Socio-economy : Baseline Population\' is defined as: Total population disaggregated age and sex categories, aggregated by administrative division.\n                                                                                                                                                                                                                                                             
- Category \'Population & Socio-economy : Poverty Rate\' is defined as: Population living under a defined poverty threshold, aggregated by administrative division and represented as a percentage of total population or as an absolute number.'

这里有一个与农业相关的测试文件,这是一个不受支持的类别,并且不出现在 HDX 的数据网格中……

filename = "./data/number-of-acreage-under-irrigation.xlsx"
df = pd.read_excel(filename, sheet_name="Sheet1")
df = df.fillna("")
display(df)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个数据集表的摘录,该表不属于 HDX 支持的类别之一

在上述内容中,我故意避免了对表格进行解析以整理内容(有关更多信息,请参见这里)。相反,我们将原始表格扔给 GPT,看看它的表现如何。

作为提示的 CSV 字符串表示,表格如下所示……

csv_as_str = df[0:20].to_csv(index=False)
print(csv_as_str)

Unnamed: 0,Unnamed: 1,Unnamed: 2,Unnamed: 3,Unnamed: 4,Unnamed: 5,Unnamed: 6,Unnamed: 7,Unnamed: 8,Unnamed: 9,Unnamed: 10,Unnamed: 11
Table 3: Number of acreage under irrigation,,,,,,,,,,,
,,OVERALL,,Sub county,,,,,,,
,,,,Chepalungu,,,,Bomet Central,,,
,,,,Male,,Female,,Male,,Female,
,,N,%,N,%,N,%,N,%,N,%
What is the average size of land you own that is currently under irrigation?,0 - 2 acres,22,2.8%,4,2.2%,10,3.8%,3,1.7%,5,2.9%
,2 - 5 acres,6,.8%,2,1.1%,2,.8%,0,0.0%,2,1.2%
,5 - 10 acres,1,.1%,0,0.0%,0,0.0%,0,0.0%,1,.6%
,More than 10 acres,0,0.0%,0,0.0%,0,0.0%,0,0.0%,0,0.0%
,None,760,96.3%,176,96.7%,251,95.4%,170,98.3%,163,95.3%
,Total,789,100.0%,182,100.0%,263,100.0%,173,100.0%,171,100.0%

对于提示,我们将类别定义合并为一个聊天提示,并将一些指令和正在分析的表格合并为第二个……

prompts    = []
prompts.append(f"Here is a list of HDX data categories with their definition: \n\n {category_prompt_text} \n\n")
prompts.append(f"Does the following table from file {filename} fall into one of the categories provided, if not say no. "\
               f"If it does, which category and explain why? \n\n {csv_as_str} \n\n")

所以提示 1……

Here is a list of HDX data categories with their definition:

- Category \'Affected People : Internally Displaced Persons\' is defined as: Tabular data of the number of displaced people by location. Locations can be administrative divisions or other locations (such as camps) if an additional dataset defining those locations is also available.\n                                              
- Category \'Affected People : Refugees and Persons of Concern\' is defined as: Tabular data of the number of refugees and persons of concern either in the country or originating from the country disaggregated by their current location. Locations can be administrative divisions or other locations (such as camps) if an additional dataset defining those locations is also available or if the locations\' coordinates are defined in the tabular data.\n                                                                                                                                                                                                                                                                                                                                                                                  
- Category \'Affected People : Returnees\' is defined as: Tabular data of the number of displaced people who have returned.\n                                                                                                                                                                                                                                                                                                                      
- Category \'Affected People : Humanitarian Needs\' is defined as: Tabular data of the number of people in need of humanitarian assistance by location and humanitarian cluster/sector.\n                                                                                                                                                                                                                                                                                       
- Category \'Coordination & Context : 3W - Who is doing what where\' is defined as: List of organisations working on humanitarian issues, by humanitarian cluster/sector and disaggregated by administrative division.\n                                                                                                                                                                                                                                                                                                                                                                                                                         
- Category \'Coordination & Context : 3W - Who is doing what where\' is defined as: \n                                                                                                                                                                                                                                                                        
- Category \'Coordination & Context : 3W - Who is doing what where\' is defined as: Note: An exception for the subnational rule is made for the IATI dataset which, if available, should always be included as an incomplete dataset.\n                                                                                                                                                                                                                                                                                                                                                           
- Category \'Coordination & Context : Funding\' is defined as: Tabular data listing the amount of funding provided by humanitarian cluster/sector.\n                                                                                                                                                                                                                                                                                                                                                                                                                                              
- Category \'Coordination & Context : Funding\' is defined as: \n                                                                                                                                                                                                                                                                                                 
- Category \'Coordination & Context : Funding\' is defined as: Note: An exception for the subnational rule is made for the FTS dataset which, if available, should always be included as a complete dataset.\n                                                                                                                                                                                                                                                                                                                               
- Category \'Coordination & Context : Conflict Events\' is defined as: Vector data or tabular data with coordinates describing the location, date, and type of conflict event.\n                                                                                                                                                                                                                                              
- Category \'Coordination & Context : Humanitarian Access\' is defined as: Tabular or vector data describing the location of natural hazards, permissions, active fighting, or other access constraints that impact the delivery of humanitarian interventions.\n                                                              
- Category \'Coordination & Context : Climate Impact\' is defined as: Tabular or vector data containing current and historical impacts of climate events relating to floods, droughts and storms. The data should specify the location of the event, date of the event, and contain at least one indicator of impact such as spatial extent of event, disruption to affected populations, destroyed infrastructure, and/or affected vegetation.\n                                                                                                                                                                                                                                      
- Category \'Food Security & Nutrition : Food Security\' is defined as: Vector data representing the IPC/CH acute food insecurity phase classification or tabular data representing population or percentage of population by IPC/CH phase and administrative division.\n                                                                                                                                                                                                                                                                                                
- Category \'Food Security & Nutrition : Acute Malnutrition\' is defined as: Tabular data specifying the global acute malnutrition (GAM) or severe acute malnutrition (SAM) rate\xa0 by administrative division.\n                                                                                                                                                                                                                                                                                                                                                                  
- Category \'Food Security & Nutrition : Food Prices\' is defined as: Time series prices for common food commodities at a set of locations.\n- Category \'Geography & Infrastructure : Administrative Divisions\' is defined as: Vector geographic data describing the sub-national administrative divisions of a location, usually a country, including the names and unique identifiers, usually p-codes, of each administrative division. To be considered "complete", and included here, the humanitarian community working in the location has to have endorsed a preferred set of administrative boundaries as the Common Operational Dataset (COD).\n                                                                                                                                                                                                                                                                                                            
- Category \'Geography & Infrastructure : Populated Places\' is defined as: Vector data or tabular data with coordinates representing the location of populated places (cities, towns, villages).\n                                                                                                                                                                           
- Category \'Geography & Infrastructure : Roads\' is defined as: Geographic data describing the location of roads with some indication of the importance of each road segment in the transportation network. The data should exclude or indicate roads that are not usable by typical four-wheel-drive vehicles (footpaths, etc.).\n                                                                                                                                                                                                                                                                              
- Category \'Geography & Infrastructure : Airports\' is defined as: Geographic data representing all operational airports including a name or other unique identifier and an indication of what types of aircraft can use each.\n                                                                                                                                                                                                                                                                                      
- Category \'Health & Education : Health Facilities\' is defined as: Vector data or tabular data with coordinates representing health facilities with some indication of the type of facility (clinic, hospital, etc.).\n                                                                                                                                                                                                                                                                              
- Category \'Health & Education : Education Facilities\' is defined as: Vector data or tabular data with coordinates representing education facilities with some indication of the type of facility (school, university, etc.).\n                                                                                                                                                                                                                                                                                                                                 
- Category \'Population & Socio-economy : Baseline Population\' is defined as: Total population disaggregated age and sex categories, aggregated by administrative division.\n                                                                                                                                                                                                                                                             
- Category \'Population & Socio-economy : Poverty Rate\' is defined as: Population living under a defined poverty threshold, aggregated by administrative division and represented as a percentage of total population or as an absolute number.'

然后提示 2……

Does the following table from file ./data/number-of-acreage-under-irrigation.xlsx fall into one of the categories provided, if not say no. If it does, which category and explain why? 

Unnamed: 0,Unnamed: 1,Unnamed: 2,Unnamed: 3,Unnamed: 4,Unnamed: 5,Unnamed: 6,Unnamed: 7,Unnamed: 8,Unnamed: 9,Unnamed: 10,Unnamed: 11\nTable 3: Number of acreage under irrigation,,,,,,,,,,,
,,OVERALL,,Sub county,,,,,,,
,,,,Chepalungu,,,,Bomet Central,,,
,,,,Male,,Female,,Male,,Female,
,,N,%,N,%,N,%,N,%,N,%
What is the average size of land you own that is currently under irrigation?,0 - 2 acres,22,2.8%,4,2.2%,10,3.8%,3,1.7%,5,2.9%
,2 - 5 acres,6,.8%,2,1.1%,2,.8%,0,0.0%,2,1.2%
,5 - 10 acres,1,.1%,0,0.0%,0,0.0%,0,0.0%,1,.6%
,More than 10 acres,0,0.0%,0,0.0%,0,0.0%,0,0.0%,0,0.0%
,None,760,96.3%,176,96.7%,251,95.4%,170,98.3%,163,95.3%
,Total,789,100.0%,182,100.0%,263,100.0%,173,100.0%,171,100.0%

让我们尝试使用GPT-3.5-turboGPT-4……

def prompt_model(prompts, temperature=0.0, model="gpt-4"):
    messages = [{"role": "system", "content": "You are a helpful assistant."}]
    for prompt in prompts:
        messages.append({"role": "user", "content": prompt})
        response = ai.ChatCompletion.create(
            model=model, temperature=temperature, messages=messages
        )
    return response["choices"][0]["message"]["content"]

prompts = []
prompts.append(
    f"Here is a list of HDX data categories with their definition: \n\n {category_prompt_text} \n\n"
)
prompts.append(
    f"Does the following table from file {filename} fall into one of the categories provided, if not say no. "
    f"If it does, which category and explain why? \n\n {csv_as_str} \n\n"
)

for model in ["gpt-3.5-turbo", "gpt-4"]:
    response = prompt_model(prompts, temperature=0.0, model=model)
    print(f"\n{model} Model response: \n\n{response}")

我们得到……

gpt-3.5-turbo Model response: 

No, the table does not fall into any of the categories provided. 
The table is about the number and percentage of people who own land of 
different sizes that are currently under irrigation. 
It does not provide any information about the number of affected people, 
coordination and context, food security and nutrition, geography and 
infrastructure, health and education, or population and socio-economy.

gpt-4 Model response: 

The table from the file ./data/number-of-acreage-under-irrigation.xlsx 
does not fall into any of the provided HDX data categories. 
The table provides information about the number of acreage under 
irrigation in different sub-counties and is not related to any of the 
categories mentioned, such as affected people, coordination & context, 
food security & nutrition, geography & infrastructure, health & education, 
or population & socio-economy.

GPT-3.5-turboGPT-4都完美地工作,并识别出我们的表格属于所需类别之一(它与农业相关)。我也喜欢这种推理,至少在这个例子中完全正确。

我们用一个在受支持类别中的表进行尝试,查德的食品价格,如在查德 HDX 数据网格上找到的。这个文件的 CSV 字符串,取前 20 行,如下所示……

date,admin1,admin2,market,latitude,longitude,category,commodity,unit,priceflag,pricetype,currency,price,usdprice
#date,#adm1+name,#adm2+name,#loc+market+name,#geo+lat,#geo+lon,#item+type,#item+name,#item+unit,#item+price+flag,#item+price+type,#currency,#value,#value+usd
2003-10-15,Barh El Gazal,Barh El Gazel Sud,Moussoro,13.640841,16.490069,cereals and tubers,Maize,KG,actual,Retail,XAF,134.0,0.2377
2003-10-15,Barh El Gazal,Barh El Gazel Sud,Moussoro,13.640841,16.490069,cereals and tubers,Millet,KG,actual,Retail,XAF,147.0,0.2608
2003-10-15,Lac,Mamdi,Bol,13.5,14.683333,cereals and tubers,Maize,KG,actual,Retail,XAF,81.0,0.1437
2003-10-15,Lac,Mamdi,Bol,13.5,14.683333,cereals and tubers,Maize (white),KG,actual,Retail,XAF,81.0,0.1437
2003-10-15,Logone Occidental,Lac Wey,Moundou,8.5666667,16.0833333,cereals and tubers,Millet,KG,actual,Retail,XAF,95.0,0.1685
2003-10-15,Logone Occidental,Lac Wey,Moundou,8.5666667,16.0833333,cereals and tubers,Sorghum,KG,actual,Retail,XAF,62.0,0.11
2003-10-15,Logone Occidental,Lac Wey,Moundou,8.5666667,16.0833333,cereals and tubers,Sorghum (red),KG,actual,Retail,XAF,62.0,0.11
2003-10-15,Moyen Chari,Barh-K h,Sarh,9.1429,18.3923,cereals and tubers,Millet,KG,actual,Retail,XAF,100.0,0.1774
2003-10-15,Moyen Chari,Barh-K h,Sarh,9.1429,18.3923,cereals and tubers,Sorghum,KG,actual,Retail,XAF,90.0,0.1597
2003-10-15,Moyen Chari,Barh-K h,Sarh,9.1429,18.3923,cereals and tubers,Sorghum (red),KG,actual,Retail,XAF,90.0,0.1597
2003-10-15,Ndjaména,Ndjamena,Ndjamena,12.11,15.04,cereals and tubers,Maize,KG,actual,Retail,XAF,132.0,0.2342
2003-10-15,Ndjaména,Ndjamena,Ndjamena,12.11,15.04,cereals and tubers,Maize (white),KG,actual,Retail,XAF,132.0,0.2342
2003-10-15,Ndjaména,Ndjamena,Ndjamena,12.11,15.04,cereals and tubers,Millet,KG,actual,Retail,XAF,110.0,0.1952
2003-10-15,Ndjaména,Ndjamena,Ndjamena,12.11,15.04,cereals and tubers,Rice (imported),KG,actual,Retail,XAF,396.0,0.7026
2003-10-15,Ndjaména,Ndjamena,Ndjamena,12.11,15.04,cereals and tubers,Rice (local),KG,actual,Retail,XAF,297.0,0.5269
2003-10-15,Ndjaména,Ndjamena,Ndjamena,12.11,15.04,cereals and tubers,Sorghum,KG,actual,Retail,XAF,100.0,0.1774
2003-10-15,Ndjaména,Ndjamena,Ndjamena,12.11,15.04,cereals and tubers,Sorghum (red),KG,actual,Retail,XAF,100.0,0.1774
2003-10-15,Ouaddai,Ouara,Abeche,13.8166667,20.8166667,cereals and tubers,Millet,KG,actual,Retail,XAF,155.0,0.275
2003-10-15,Ouaddai,Ouara,Abeche,13.8166667,20.8166667,cereals and tubers,Sorghum,KG,actual,Retail,XAF,97.0,0.1721

使用相同格式的提示,我们得到……

gpt-3.5-turbo Model response: 

Yes, the table falls into the category 'Food Security & Nutrition : Food Prices'. 
This is because the table contains time series prices for common food 
commodities at different locations.

gpt-4 Model response: 

Yes, the table falls into the category "Food Security & Nutrition : Food Prices". 
This is because the table contains time series prices for common 
food commodities (such as Maize, Millet, and Sorghum) at various 
locations (markets) with their respective coordinates (latitude and longitude). 
The data also includes information on the date, administrative divisions, 
and currency.

所以再说一次,两种模型都是正确的。该数据集的类别确实是“食品安全与营养:食品价格”。

好的,对于使用单个表进行的一些快速示例,看起来不错。那么,基于多个表的内容来识别类别呢?

使用来自多个表的摘录预测数据集类别

在 HDX 中,一个数据集可以有多个“资源”(文件),而对于 Excel 中的数据,这些文件可能在工作表中包含多个表。因此,只查看数据集中的一个表可能无法完全了解情况,我们需要根据多个表做出决策。这一点很重要,因为在数据集中的所有表中可能会有关于数据集、字段查找等的文档标签,而这些标签本身不足以推断数据集中所有数据的类别。

在 ChatGPT API 推出之前,这会由于令牌限制而变得困难。然而,ChatGPT 允许我们指定多个提示,并且有增加的令牌限制。如我们所见,这仍然是一个限制因素,但比以前的模型有所改进。

本分析的样本数据——在笔记本仓库中提供——是从 HDX 中提取的,由…

  1. 遍历数据集

  2. 对于每个数据集,遍历文件

  3. 对于每个表格文件,下载它

  4. 对于文件中的每个标签,创建一个表格摘录(前 20 行)以 CSV 格式

注意:我没有包含这段代码以避免 HDX 上的流量过多,但如果对这段代码感兴趣,可以在 Medium 上给我留言。

所以每个数据集都有一个这样的字段…

[
    {
       "filename":"<DATASET NAME>/<FILE NAME 1>",
       "format": "EXCEL",
       "sheet": "<SHEET 1>",
       "table_excerpt": "<FIRST 20 ROWS OF TABLE IN CSV FORMAT>"  
    },
    {
       "filename":"<DATASET NAME>/<FILE NAME 1>",
       "format": "EXCEL",
       "sheet": "<SHEET 2>",
       "table_excerpt": "<FIRST 20 ROWS OF TABLE IN CSV FORMAT>"  
    },
    {
       "filename":"<DATASET NAME>/<FILE NAME 2>",
       "format": "CSV",
       "sheet": "",
       "table_excerpt": "<FIRST 20 ROWS OF TABLE IN CSV FORMAT>"  
    },
    {
       "filename":"<DATASET NAME>/<FILE NAME 3>",
       "format": "EXCEL",
       "sheet": "<SHEET 1>",
       "table_excerpt": "<FIRST 20 ROWS OF TABLE IN CSV FORMAT>"  
    },
    ... etc
]

对于每个数据集,这种结构允许我们为每个表生成多个提示…

def predict(data_excerpts, temperature=0.0):
    results = []
    for index, row in data_excerpts.iterrows():
        dataset = row["name"]
        title = row["title"]
        print(
            f"\n========================================= {dataset} =============================================\n"
        )

        prompts = []

        # Start the prompt by defining the categories we want to assign
        prompts.append(
            f"Here is a list of HDX data categories with their definition: \n\n {category_prompt_text} \n\n"
        )
        prompts.append(
            f"Here are excerpts from all the tables in this dataset: {title} ...\n\n"
        )

        # Build multiple prompts for each table excerpt for this dataset
        tables = row["table_excerpts"]
        for table in tables:
            table = json.loads(table)
            csv_as_str = table["table_excerpt"]
            sheet = table["sheet"]
            type = table["type"]
            filename = table["filename"]
            print(f"DATA > {filename} / {sheet}")
            prompts.append(
                f"Type {type} sheet {sheet} from file {filename} Table excerpt: \n\n {csv_as_str} \n\n"
            )

        # Finish up with our request
        prompts.append(
            "Does the dataset fall into exactly one of the categories mentioned above, if not say no. "
            "If it does, add a pipe charatcter '|' before and after the top category and sub-category category and explain why it was chosen step-by-step.\n\n"
            "What is the second most likely category if you had to pick one (adding a ^ character either side)? \n\n"
        )

        actual_category = row["datagrid_category"]
        d = {
            "dataset_name": dataset,
            "filename": filename,
            "prompts": prompts,
            "actual_category": actual_category,
        }

        # Send our prompt array to two models
        for model in ["gpt-3.5-turbo", "gpt-4"]:
            # for model in ['gpt-3.5-turbo']:
            # GPT-4 is in test and can fail sometimes
            try:
                print(f"\nCalling model {model}")
                response = prompt_model(prompts, temperature=temperature, model=model)
                if "|" in response:
                    predicted_category = response.split("|")[1].strip()
                else:
                    predicted_category = response
                print(f"\n{model} Model response: \n\n{response}")
                match = actual_category == predicted_category
                d[f"{model}_response"] = response
                d[f"{model}_predicted_category"] = predicted_category
                d[f"{model}_match"] = match
                print(
                    f"******* RESULT: || {match} || prediced {predicted_category}, actual {actual_category} *******"
                )
            except Exception as e:
                print(e)
        results.append(d)

    results = pd.DataFrame(results)
    return results 

这会生成像这样的提示…

提示 1 — 定义类别

Here is a list of HDX data categories with their definition: 
- Category \'Affected People : Internally Displaced Persons\' is defined as: Tabular data of the number of displaced people by location. Locations can be administrative divisions or other locations (such as camps) if an additional dataset defining those locations is also available.\n                                              
- Category \'Affected People : Refugees and Persons of Concern\' is defined as: Tabular data of the number of refugees and persons of concern either in the country or originating from the country disaggregated by their current location. Locations can be administrative divisions or other locations (such as camps) if an additional dataset defining those locations is also available or if the locations\' coordinates are defined in the tabular data.\n                                                                                                                                                                                                                                                                                                                                                                                  
- Category \'Affected People : Returnees\' is defined as: Tabular data of the number of displaced people who have returned.\n
... etc 

提示 2 — 指定数据集名称并介绍表格摘录

Here are excerpts from all the tables in this colombia-health-facilities-2021: ...

提示 3、4 等 — 提供表格摘录

Type XLSX sheet servicios from file ./data/prompts/colombia-health-facilities-2021/fservicios.xlsx Table excerpt: \
,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
0,depa_nombre,muni_nombre,habi_codigo_habilitacion,codigo_habilitacion,numero_sede,sede_nombre,nivel,grse_codigo,grse_nombre,serv_codigo,serv_nombre,ambulatorio,hospitalario,unidad_movil,domiciliario,otras_extramural,centro_referencia,institucion_remisora,complejidad_baja,complejidad_media,complejidad_alta
1,Amazonas,LETICIA,9100100019,9100100019,01,E.S.E. HOSPITAL SAN RAFAEL,2,7,Apoyo Diagnóstico y Complementación Terapéutica,706,LABORATORIO CLÍNICO,SI,SI,NO,NO,NO,NO,NO,NO,SI,NO
2,Amazonas,LETICIA,9100100019,9100100019,01,E.S.E. HOSPITAL SAN RAFAEL,2,7,Apoyo Diagnóstico y Complementación Terapéutica,712,TOMA DE MUESTRAS DE LABORATORIO CLÍNICO,SI,SI,SI,NO,NO,NO,NO,SI,NO,NO\n3,Amazonas,LETICIA,9100100019,9100100019,01,E.S.E. HOSPITAL SAN RAFAEL,2,7,Apoyo Diagnóstico y Complementación Terapéutica,714,SERVICIO FARMACÉUTICO,SI,SI,NO,NO,NO,NO,NO,SI,NO,NO
... etc

Type XLSX sheet capacidad from file ./data/prompts/colombia-health-facilities-2021/fcapacidad.xlsx Table excerpt: 
,0,1,2,3,4,5,6,7,8,9,10\n0,depa_nombre,muni_nombre,codigo_habilitacion,numero_sede,sede_nombre,nivel,grupo_capacidad,coca_nombre,cantidad,modalidad,modelo
1,Amazonas,EL ENCANTO,9126300019,11,CENTRO DE SALUD SAN RAFAEL - E.S.E HOSPITAL SAN RAFAEL DE LETICIA,2,CAMAS,Pediátrica,1,,0
2,Amazonas,EL ENCANTO,9126300019,11,CENTRO DE SALUD SAN RAFAEL - E.S.E HOSPITAL SAN RAFAEL DE LETICIA,2,CAMAS,Adultos,3,,0
... etc

最终提示 — 我们请求对数据进行分类

Does the dataset fall into exactly one of the categories mentioned above, if not say no. 
If it does, add a pipe charatcter '|' before and after the top category and sub-category category and explain why it was chosen step-by-step.
What is the second most likely category if you had to pick one (adding a ^ character either side)? 

你会注意到在最后的提示中,我们要求有点多:

  • 我们要求模型指明数据符合我们的类别,以便我们捕捉负面情况,模型不会尝试为每个数据集分配一个类别。有些将不符合批准的类别

  • 请求类别“完全匹配”。如果没有这个要求,GPT-3.5-Turbo 可能会随意构造新的类别!

  • 如果模型确实识别出一个类别,将其用‘|’括起来,以便更容易解析

  • 我们要求模型提供其推理过程,因为这已被证明可以改善结果[3]。了解类别决策的原因也有助于突出虚假信息的情况

  • 最后,为了后续讨论,我们还请求第二个最可能的类别

此外,如果你仔细查看预测函数中的代码,我在这项研究中使用了温度为 0.0。温度控制输出的随机程度,由于我们希望结果既准确又具体,而不是描述量子物理的文本,所以我将其设置为尽可能低。

生成我们的预测…

output_folder = "./data/prompts"
data_excerpts = pd.read_pickle(f"{output_folder}/datasets_excerpts.pkl")
data_excerpts = data_excerpts[data_excerpts["is_datagrid"] == True]
data_excerpts = data_excerpts.sample(min(150, data_excerpts.shape[0]), random_state=42)

results = predict(data_excerpts, temperature=0.0)
results.to_excel(f"{output_folder}/results.xlsx")

我们做得怎么样?

def output_prediction_metrics(results, prediction_field="predicted_post_processed", actual_field="actual_category"):
    """
    Prints out model performance report if provided results.

    Parameters
    ----------
    results : list
        Where each element has fields as defined by ...
    prediction_field : str
        Field name of element with prediction
    actual_field : str
        Field name of element with actual value
    """
    y_test = []
    y_pred = []
    for index, r in results.iterrows():
        if actual_field not in r:
            print("Provided results do not contain expected values.")
            sys.exit()
        y_pred.append(r[prediction_field])
        y_test.append(r[actual_field])

    print(f"Results for {prediction_field}, {len(results)} predictions ...\n")
    print(f"Accuracy: {round(accuracy_score(y_test, y_pred),2)}")
    print(
        f"Precision: {round(precision_score(y_test, y_pred, average='weighted', zero_division=0),2)}"
    )
    print(
        f"Recall: {round(recall_score(y_test, y_pred, average='weighted', zero_division=0),2)}"
    )
    print(
        f"F1: {round(f1_score(y_test, y_pred, average='weighted', zero_division=0),2)}"
    )

    return 

results.fillna("", inplace=True)

print("\ngpt-3.5-turbo ...")
output_prediction_metrics(results, prediction_field="gpt-3.5-turbo_predicted_category", actual_field="actual_category")

print("\ngpt-4 ...")
output_prediction_metrics(results, prediction_field="gpt-4_predicted_category", actual_field="actual_category")

注意:虽然我们提供了 150 个数据集进行预测,但 GPT-4 的 API 时常超时,且未重试调用以节省成本。这对于处于早期预览阶段的 GPT-4 是完全可以预期的。有些提示也超出了 GPT-3.5-Turbo 的令牌长度。因此,以下结果适用于 GPT-3.5-turbo 和 GPT-4 做出的 53 个预测。

比如,仅预测类别,如“Coordination & Context”,当完整类别和子类别为“Coordination & Context : Humanitarian Access”时……

Results for **gpt-3.5**-turbo_predicted_category_1, 53 predictions ...

Accuracy: 0.66
Precision: 0.86
Recall: 0.66
F1: 0.68

Results for **gpt-4**_predicted_category_1, 53 predictions ...

Accuracy: 0.96
Precision: 0.97
Recall: 0.96
F1: 0.96

GPT-4 几乎总是能够识别正确的类别(**96%**准确率),在相同提示下表现显著优于 GPT-3.5-turbo(66%准确率)。

对于同时预测整个类别子类别……

Results for **gpt-3.5**-turbo_predicted_category, 53 predictions ...

Accuracy: 0.57
Precision: 0.73
Recall: 0.57
F1: 0.60

Results for **gpt-4**_predicted_category, 53 predictions ...

Accuracy: 0.89
Precision: 0.92
Recall: 0.89
F1: 0.89

再次强调,GPT-4 比 GPT-3.5 表现显著优越。**89%**的准确率实际上相当不错,鉴于……

  • 我们仅仅提供了一组文本规则,没有标记数据、训练分类器或提供任何示例

实际上,如果我们查看那些预测失败的示例……

df = results.loc[results["gpt-4_match"] == False]

for index, row in df.iterrows():
    response = row["gpt-4_response"]
    predicted_second_category = response.split("^")[1].strip()
    print(f"Dataset: {row['dataset_name']}")
    # print(f"Dataset: {row['filename']}")
    print("")
    print(f"Actual: {row['actual_category']}")
    print(f"Predicted category: {row['gpt-4_predicted_category']}")
    print(f"Predicted second category: {predicted_second_category}\n")
    print(
        f"Secondary category matched: {predicted_second_category == row['actual_category']}"
    )
    print("=====================================================")

我们得到……

Dataset: mozambique-attacks-on-aid-operations-education-health-and-protection

Actual: Coordination & Context : Humanitarian Access
Predicted category: Coordination & Context : Conflict Events
Predicted second category: Health & Education : Health Facilities

Secondary category matched: False
=====================================================
Dataset: iraq-violence-against-civilians-and-vital-civilian-facilities

Actual: Coordination & Context : Humanitarian Access
Predicted category: Coordination & Context : Conflict Events
Predicted second category: Affected People : Humanitarian Needs

Secondary category matched: False
=====================================================
Dataset: south-sudan-access-incidents

Actual: Coordination & Context : Conflict Events
Predicted category: Coordination & Context : Humanitarian Access
Predicted second category: Coordination & Context : Conflict Events

Secondary category matched: **True**
=====================================================
Dataset: somalia-displacement-idps-returnees-baseline-assessment-iom-dtm

Actual: Affected People : Returnees
Predicted category: Affected People : Internally Displaced Persons
Predicted second category: Affected People : Returnees

Secondary category matched: **True**
=====================================================
Dataset: ukraine-border-crossings

Actual: Coordination & Context : Humanitarian Access
Predicted category: Geography & Infrastructure : Populated Places
Predicted second category: Coordination & Context : Humanitarian Access

Secondary category matched: **True**
=====================================================
Dataset: northeast-nigeria-displacement-for-borno-adamawa-and-yobe-states-bay-state

Actual: Affected People : Returnees
Predicted category: Affected People : Internally Displaced Persons
Predicted second category: Affected People : Returnees

Secondary category matched: **True**
=====================================================
Dataset: somalia-acute-malnutrition-burden-and-prevalence

Actual: Food Security & Nutrition : Acute Malnutrition
Predicted category: Affected People : Acute Malnutrition
Predicted second category: Food Security & Nutrition : Food Security

Secondary category matched: False
=====================================================
Dataset: colombia-people-in-need-pin-del-cluster-en-seguridad-alimentaria-y-nutricion-san-sp

Actual: Food Security & Nutrition : Food Security
Predicted category: Affected People : Humanitarian Needs
Predicted second category: Coordination & Context : 3W - Who is doing what where

Secondary category matched: False
=====================================================
Dataset: sind-safeguarding-healthcare-monthly-news-briefs-dataset

Actual: Coordination & Context : Humanitarian Access
Predicted category: Coordination & Context : Conflict Events
Predicted second category: Affected People : Humanitarian Needs

Secondary category matched: False
=====================================================

有几件事引起了注意。像‘mozambique-attacks-on-aid-operations-education-health-and-protection’这样的数据集,包含了与医疗保健和攻击相关的数据文件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,假设每个数据集只有一个类别可能不是解决问题的最佳方式,数据集在类别之间被重复使用。

在 GPT-4 错误的约一半的案例中,它预测的第二名类别是正确的。查看这些案例中的一个模型输出,乌克兰边界穿越……

Yes, the dataset falls into exactly one of the categories mentioned above.

|Geography & Infrastructure : Populated Places|

The dataset contains information about border crossings in Ukraine, 
including their names in English and Ukrainian, the country they connect to, 
and their latitude and longitude coordinates. This information is related to 
populated places (border crossings) and their geographic locations, which is why the "Geography & Infrastructure : Populated Places" category is the most appropriate.

^Coordination & Context : Humanitarian Access^

The second most likely category would be "Coordination & Context : Humanitarian Access" 
border crossings can be considered as points of access between countries, and 
understanding their locations could be relevant in the context of humanitarian 
interventions. However, this category is not as fitting as the first one 
since the dataset does not specifically describe access constraints or 
permissions related to humanitarian interventions.

很酷的一点是它解释了为什么没有选择‘Coordination & Context : Humanitarian Access’,因为‘……它并不特别关注访问限制’。这是类别定义……

Coordination & Context : Humanitarian Access:表格或矢量数据,描述自然灾害、许可、激烈战斗或其他影响人道干预交付的访问限制的位置。

因此,GPT-4 似乎严格遵循类别规则。HDX 团队应用的分类有一些更细致的区别,其中跨境数据集与人道主义访问有很合理的关系。因此,也许提高模型在这种情况下预测的一个方法是向类别定义中添加额外的文本,指明边界穿越可能与人道主义访问相关。

这里的关键是 GPT-4 表现非常出色,而少数不正确的预测是由于我对问题的框定不当(数据集可以有多个类别),以及定义类别的文本可能存在的问题。

结论

该技术看起来非常有前途。我们能够获得一些良好的结果,无需设置标签、训练模型或在提示中提供示例。此外,像 GPT-4 这样的模型的数据总结能力确实令人印象深刻,帮助调试模型预测,也可能是提供快速数据概览的不错方法。

然而,存在一些警示:

  • 由于成本和 GPT-4 仍处于早期预览阶段,这项研究所使用的数据量非常有限。未来的研究当然需要使用更多的数据。

  • 目前提示长度是一个限制因素,上述研究只包括了少于 4 个表的数据集,以避免在提示表格摘录时超出 token 限制。HDX 数据集可能包含比这更多的表格,在某些情况下,拥有更大的表格摘录可能会更有价值。像 OpenAI 这样的供应商似乎在逐步增加 token 限制,因此随着时间的推移,这可能会变得不那么成为问题。

  • 由于早期预览的原因,GPT-4 模型的性能非常慢,每个提示完成需要 20 秒。

  • 问题的框架并不理想,例如,假设一个数据集只能有一个类别。虽然足以展示大型语言模型在评估数据质量和总结方面的潜力,但未来稍微不同的方法可能会产生更好的结果。例如,为 HDX 平台上的数据集预测每个国家的顶级数据集候选者。

能够用自然语言指定数据测试和数据问题仍然很酷!

参考文献

[1] OCHA, 2023 年开放人道数据状态

[2] Brown 等人, 语言模型是少样本学习者(2020 年)。

[3] Kojima 等人, 大型语言模型是零样本推理者

Schopf 等人, 评估无监督文本分类:零样本和基于相似性的 approaches

这个分析的代码可以在这个笔记本中找到。

使用 GPT-4 的视觉功能作为艺术评论家

原文:towardsdatascience.com/using-gpt-4-with-vision-as-an-art-critic-ec91080ba334

OpenAI 最新模型如何提供对视觉艺术的见解

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Robert A. Gonsalves

·发表于 Towards Data Science ·14 分钟阅读·2023 年 11 月 2 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AI 艺术评论家的极简主义画作图像由 AI 图像创建程序 Midjourney 创建,并由作者编辑

大约两周前,OpenAI 开始推出其具备视觉功能的 GPT-4 模型(GPT-4V)[1]。作为 ChatGPT Plus 的订阅者,每月费用为 20 美元,我获得了新模型的早期访问权限。系统可在这里获取:chat.openai.com

使用 GPT-4V,我可以提交一个包含最多四张图片的文本提示。系统会分析提示和图片,并作出相应的回应。由于我一直在写有关 AI 和 ML 创意用途的文章,我的第一个直觉是看看 GPT-4V 是否能够有效地作为艺术评论家。

这是我的第一次实验。我让系统评论了一幅我在 2002 年制作的新的英格兰风景丙烯画,这幅画是通过参考图像、一些自定义软件和投影仪完成的。我拍了一张画作的照片,并将其发送给 GPT-4V 进行评论。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ChatGPT 用户界面 (左侧)秋天的沃伦公园 (右侧),截图和画作由作者提供

这是我的提示,随后是 GPT-4V 的评论。

RobG*: 根据这幅画的照片,写一篇带有建设性批评的评论。

秋天的沃伦公园

罗伯特·A·冈萨尔维斯

画布板上的丙烯画

24” x 32”*

GPT-4V: “秋天的沃伦公园”由罗伯特·A·冈萨尔维斯创作,是对大自然美丽的迷人描绘。艺术家选择了充满活力的秋季色彩,捕捉了季节的精髓,使场景充满了炽热的橙色和深邃的棕色。使用的点彩技法赋予了作品梦幻般的、近乎超凡脱俗的质量,让观众感到仿佛被旋转的落叶包围。

建设性批评:

1. 尽管点彩画创造了迷人的质感,但如果点的大小能有更多变化,可能会为秋叶增添更多的深度和现实感。

2. 虽然天空以其冷色调的蓝色呈现得很美,但如果能有更平滑的过渡或渐变,会使其感觉更自然。

3. 签名“Robert Arthur 11/02”虽然重要,但显得有些突出。如果能更微妙地融入画作中,可能会更具美感。

总体而言,这幅作品是对秋天的绝妙表现,吸引了观众的注意力,并将他们带到了沃伦公园的中心。

第一部分相当令人赞赏。我注意到 ChatGPT 通常提供积极的回应。它指出了我画作的一些客观特征,如点彩风格和秋季色彩。我喜欢它说画作给观众带来了“被卷入旋转的落叶风暴中的感觉”时的热情。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

沃伦公园秋季细节,秋叶 (左), 天空 (中), 和签名 (右),作者提供的图像

在我的提示中,我要求一些“建设性批评”,系统确实提供了一些。关于点的大小的评论是公平的,但建议天空使用平滑渐变似乎不太对劲,因为点彩画通常仅由颜色点构成。然而,我对系统能够读取我的签名和日期感到印象深刻,因为我选择了几乎没有对比度的颜色。是的,我的签名在画作中确实不寻常地大。

在本文中,我将提供有关 GPT-4V 模型的一些背景信息,并查看它在审视其他形式的视觉艺术(包括多媒体装置和 AI 生成艺术)时的表现如何。

GPT-4V 模型

2023 年 3 月,OpenAI 推出了 GPT-4,其中非视觉变体提供给了 ChatGPT Plus 用户。以下是作者们对视觉功能的评价。

GPT-4 接受由图像和文本组成的提示,这种设置与纯文本设置类似,让用户指定任何视觉或语言任务。具体来说,模型根据由任意交织的文本和图像组成的输入生成文本输出。在各种领域——包括文本和照片、图表或屏幕截图的文档——GPT-4 展现了与纯文本输入类似的能力。 - OpenAI [1]

模型大小和架构

与 OpenAI 发布之前的模型不同的是,它没有透露有关 GPT-4 模型的大小和架构的很多信息。然而,有泄漏的报告显示 GPT-4 约有 1.8 万亿个参数。它使用了一个专家混合(MoE)系统,在模型中有 16 个专家,每个专家约有 1110 亿个参数。作为参考,早期的 GPT-3 模型使用了 1750 亿个参数 [3]。

训练过程

OpenAI 没有透露他们用于训练 GPT-4 模型的数据详情。在他们的研究网站上,他们表示 GPT-4 基础模型是通过公共和许可数据语料库进行训练的,涵盖了各种推理能力、陈述和意识形态。为了确保模型的响应与用户意图一致,他们通过人类反馈强化学习(RLHF)进行了微调。

实验结果

为了测试这些模型,OpenAI 进行了各种基准测试,包括模拟最初为人类设计的考试。他们没有对这些考试进行特定的训练。模型在训练期间见到了考试中少量的问题;对于每个考试,他们运行了一个去除这些问题的变体,并报告了较低的分数[1]。以下是一些结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GPT 模型的测试结果,数据来自OpenAI,图表由作者提供

你可以看到 GPT-4 模型在大多数测试中显著优于 GPT-3.5 模型。有趣的是,GPT-4V 在一些测试中,如 GRE 定量测试,表现优于标准 GPT-4。从他们的论文中,我了解到 OpenAI 的研究人员尽可能客观地转录了测试中的任何图像和图表,以供视觉模型和非视觉模型使用[1]。然而,他们没有提供为什么具有视觉的 GPT-4 在测试中表现优于标准 GPT-4 模型的任何见解。我猜测 GPT-4V 在回答那些具有图像描述的“文字”问题时表现更好。

模型的局限性

作者描述了 GPT-4 和 GPT-4V 的不足之处。他们报告说,尽管这些模型有所进步,但与其前身一样,仍存在一些弱点:它们并不总是可靠,可能会产生“幻觉”,具有有限的上下文窗口,并且无法从经验中学习。这些局限性,特别是在关键情况下,使用时需要谨慎。模型的能力和限制引入了新的安全问题,强调了由于其潜在的社会影响而需要进一步研究。论文探讨了包括偏见、虚假信息等潜在风险,并概述了为最小化这些风险而采取的措施,如对抗性测试和安全管道[1]。

GPT-4V 的初步发布

起初,视觉版本 GPT-4V 仅通过Be My Eyes这一由丹麦初创公司创建的应用程序提供。该应用程序通过将盲人或视力低下者与志愿者连接,来帮助他们完成诸如产品识别和机场导航等任务。利用 GPT-4V 的功能,该初创公司在应用程序中推出了一个“虚拟志愿者”功能,旨在匹配人类助手的理解水平[2]。

OpenAI 的数据收集政策

OpenAI 修改了其数据收集政策。默认情况下,你的提示和回应可以被 OpenAI 用于训练未来的模型。他们之前使用了一个在线表单,用户可以选择退出数据收集。根据他们的新政策,数据收集现在与聊天记录绑定。如果你关闭聊天记录,他们将不会使用你的提示和回应来训练他们的模型。你可以在这里阅读他们的新政策。

接下来,我将展示更多使用 GPT-4V 作为艺术评论家的实验。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ChatGPT 用户界面,作者截图

GPT-4V 作为艺术评论家

GPT-4V 可以作为艺术评论家吗?我在上面的截图中问了这个问题,它回答说,“绝对可以!”并解释了为什么它可以。让我们看看它在几个例子中的表现。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

安娜·克里斯蒂娜·戈朗松和罗布·贡萨尔维斯的《Swarming》,作者提供的图片

装置艺术

第一个例子是对一个名为“Swarming”的互动装置的评论,这个装置是我和我的朋友及艺术家安娜·克里斯蒂娜·戈朗松共同构建的。该装置展示了毛毡和染色的形状,作为“boids”的家,这些数字生物似乎从这些形状中飞出,通过投影在空中飞翔,最终又回到形状中。boids 可以通过微软 Kinect 设备被观众干扰和移动,该设备正在观察观众。

我将三张图片和一个装置描述发送给 GPT-4V,获取评论。以下是互动的过程。

*RobG: 根据这些照片和互动装置的描述,写一篇带有建设性批评的评论。

[description]*

GPT-4V: 安娜·克里斯蒂娜·戈朗松和罗布·贡萨尔维斯的《Swarming》评论

“Swarming” 是对将触感艺术与现代技术的沉浸式能力相结合的可能性的一次雄心勃勃的证明。由安娜·克里斯蒂娜·戈朗松设计的色彩鲜艳的毛毡雕塑为展览增添了奇幻的质感。这些有机形态与它们的动画对照形成了对日常生活的超现实逃离,展现了一个艺术真的栩栩如生的世界。

四种互动模式——睡眠、侦察、集群和互动——经过深思熟虑地设计,以为访客提供分层的体验。观众的存在本身就可以改变装置的行为,弥合被动观看和主动参与之间的差距。使用微软 Kinect 接口来跟踪访客的动作并触发视觉和听觉反馈,这种方法既创新又引人入胜。这种即时反馈循环使访客能够真正融入艺术作品之中。

然而,还有一些领域可能需要进一步完善:

  1. 环境声音:静默模式,特别是睡眠和侦察,可能利用细微的环境声音。这将增强体验,确保在这些较安静的时刻气氛不显得过于单调或空旷。

  2. 互动清晰度:提供一个简单的指南或指示,说明访客如何将展览从一种模式过渡到另一种模式可能会有所帮助。这可以确保访客能够充分探索“Swarming”提供的互动深度。

  3. 照明:考虑到视频投影仪在这个装置中的重要性,应特别关注展览室的环境光照。适当的照明可以增强投影的可见性,并确保感应雕塑得到适当的照明。

  4. 动画中的多样性:虽然“boids”为展览增添了动态元素,但引入多样的图案或行为可以进一步丰富观众的体验。这可以通过多样化 boids 的颜色或大小来实现。

总之,“Swarming”是传统艺术与前沿技术的引人入胜的融合,提供了一种既创新又怀旧的多感官体验。通过一些调整,这个装置有潜力进一步吸引观众,使每次访问都成为独特的发现之旅。

GPT-4V 对这件作品的评价非常积极。它以“雄心勃勃”、“异想天开”、“创新”和“引人入胜”等词语开始了对装置的高度评价。几乎就像我付钱让它写这篇评论一样。哦,等等。我确实这么做了。🙂

但它确实提出了一些合理的建设性批评。第一点,关于在睡眠和侦察模式中发出声音,并未考虑艺术坐席者的理智。关于为观众提供指示和光照条件的建议是有效的。最后一点,关于在动画中增加更多多样性也是很好的。但建议改变 boids 的大小听起来很像建议在我开头示例中改变点彩画点的大小。嗯,让我们看看这个趋势是否在其他示例中继续。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Dream Studio(右)、DALL-E 3(中)、和 Midjourney(左)的用户界面,作者截图

AI 生成艺术

为了测试系统的比较艺术批评能力,我将相同的提示输入到三个文本生成图像模型中,并请求 GPT-4V 对生成的图像进行比较。我使用的图像生成模型是 Stability AI 最新提供的Dream Studio,OpenAI 的DALL-E 3Midjourney。我为这些服务都拥有付费账户。您可以在上面的截图中看到用户界面。

在这三种图像生成系统中,DALL-E 3 有一个有趣的特点;它使用 ChatGPT 作为界面。当我要求它使用提示“秋季树林的印象派画作”生成画作时,它首先将其扩展为更长的提示:“印象派风格的油画,描绘了秋季的密林。金色的树叶铺满了地面,而树木则装饰着生动的橙色、红色和黄色。斑驳的阳光透过树冠,投射出闪烁的光斑到森林地面上。”这是一个很酷的功能,所以我用了它。如果我输入的是“创建秋季树林的印象派画作。使用这个确切的提示。”它将跳过提示扩展步骤。

以下是生成“秋季树林的印象派画作”的结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

“秋季树林的印象派画作,” 在 Dream Studio 生成 (左), DALL-E 3 (中), 和 Midjourney (右),作者提供图像

这是我发送给 GPT-4V 的提示以及三幅图像。

RobG:分析这些使用提示“秋季树林的印象派画作”创作的三幅图像。提供对比反馈,将图像称为左、中、右。

GPT-4V:当然!让我们深入分析这三幅秋季树林的印象派画作。

左侧图像:左侧图像使用了柔和的色彩调色板,主要展示了柔和的橙色、黄色和冷灰色。树木用细长的树干绘制,质地光滑,使整个场景呈现出一种精致、空灵的感觉。前景有一条明显的小径,覆盖着落叶,引导观众的视线深入树林。画作中有一种宁静和安静的感觉,就像能听到风在树叶间轻轻沙沙作响。

中间图像: 中间图像在色彩选择上更为大胆和生动,呈现了深金色、火红色和绿色的点缀。光影的对比非常强烈,特别是阳光如何透过树冠,照射到森林地面。与左图不同,这个场景更为密集,树木的集中度显得更高。对森林地面的关注,尤其是阳光照射下的散落叶子,营造了一种神奇、近乎梦幻的氛围。

右图: 右图是三幅图像中最具动感和生动的,色彩调色板十分抢眼,展示了明亮的橙色、红色和对比鲜明的蓝色。图中有一个看似溪流或水坑的倒影,双倍增强了秋天色彩的影响,并创造了树木的镜像效果。这幅画感觉比其他画作更具抽象性,笔触更加大胆,反射效果的运用使其似乎是在雨后场景中观看。画作强调了运动感,可能是由于水面波纹效果和落叶的方向性。

对比反馈: 虽然这三幅画作都美丽地捕捉了秋季树林的精髓,但它们以不同的方式展现。左边的画作提供了平静而柔和的表现,专注于树林的宁静。相比之下,中间的画作将观众沉浸在阳光照射下的光辉森林中,散发着温暖和迷人。右图因其大胆的颜色和抽象性而脱颖而出,利用反射和生动的色调来传达季节的动态特征。每幅画都有自己独特的魅力,使它们各自都很迷人。

哇!这是对三幅画作的极佳而全面的分析。再次强调,所有评论都非常积极。我喜欢它如何从描述第二幅图像开始比较这些图像,“与左图不同,这个场景更为密集…” 它还早早地把第三幅图像标榜为赢家,“右图是三幅图像中最具动感和生动的…” 但它以积极的语调结束,每幅画作都得到了赞扬,“每幅画都有自己独特的魅力…”

寻找一些具体的建设性批评,我问了这个问题。

RobG: 简要描述每幅画作可以如何改进。

GPT-4V: 左图: 为了增强其魅力,艺术家可以在颜色上引入更多的对比度,以赋予场景更多的深度。添加一些更明亮、更鲜艳的秋季色彩也可能帮助某些元素突出,确保图像不会显得过于单调或褪色。

中间图像:虽然光影的表现非常出色,但艺术家可以进一步定义树木,给它们增加更多的纹理或树皮图案的变化。这将打破单一性,并提供额外的兴趣点。

右侧图片:这幅画的动态特性是它的强项,但如果有一个更清晰的焦点会更好。无论是特定的树木、倒影还是其他元素,给观众的眼睛一个休息的地方,可能会使场景更具平衡感。艺术家还可以细化水中的倒影,确保它们与所映照的树木更自然地对齐。

这里是再次提供的三张图片供参考。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自 Dream Studio 生成的画作 (左), DALL-E 3 (中), 和 Midjourney (右), 作者提供的图片

我同意这三条建议。左侧图片可以增加对比度和色彩饱和度。中间的图片需要在树木上增加一些定义。而右侧的图片缺少一个中央的焦点对象。

结论与下一步

在这次探索中,我发现 GPT-4V 作为艺术评论家的能力既有前景又富有洞察力。通过将其分析能力与各种形式的视觉艺术进行对比,很明显,该模型能够提供积极的反馈和建设性的批评,具有相当的深度。

从我画作的反馈到更复杂的互动装置和 AI 生成的艺术作品,GPT-4V 展现了对艺术的深刻理解和令人惊讶的敏锐眼光。虽然该模型的评价显著积极,这可能反映了 OpenAI 的设计决定,以避免过于负面的回应,但在被要求时,它毫不犹豫地提供了改进建议。

然而,必须记住的是,虽然 GPT-4V 可以提供分析,但艺术的实际价值往往在于观众的主观体验。像 GPT-4V 这样的 AI 工具可以提供反馈,但它们不应替代人类的触感,后者在艺术解释中带来个人的视角、情感和体验。

未来,探索 GPT-4V 对更抽象艺术形式的反应或者深入进行历史艺术时期的比较分析将是非常有趣的。例如,比较两幅法国印象派画作,并观察它是否能识别它们,将是很有趣的。此外,随着模型的不断发展和改进,还有可能对艺术、设计和其他视觉媒介提供更深入的见解。

总之,GPT-4V 为寻求反馈的艺术家提供了一个独特且有价值的工具。但仍需以平衡的视角来对待其批评,记住艺术不仅仅关乎技巧或视觉吸引力,更与人类经验密切相关。

致谢

我感谢 Jennifer Lim 和 Oliver Strimpel 审阅这篇文章并提供反馈。

参考文献

[1] OpenAI, GPT-4 技术报告 (2023)

[2] OpenAI, Be My Eyes — Be My Eyes 使用 GPT-4 改变视觉可及性 (2023)

[3] T. Brown 等人,语言模型是少样本学习者(2020)

附言

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

粉丝纠正:从投球手的投球区到本垒板不是 90 英尺!,图片作者

尽管 GPT-4V 喜欢我那幅“秋天的沃伦公园”画作,但康纳·奥布莱恩并没有那么友好。你可以在 2013 年的这段“粉丝纠正”视频中听到他对我画作的评价,从 01:36 开始。

使用 Python 和 Kafka

原文:towardsdatascience.com/using-kafka-with-python-54dc20717cf7

了解如何使用 Python 创建生产者和消费者,并绘制动态散点图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Wei-Meng Lee

·发表于 Towards Data Science ·7 分钟阅读·2023 年 3 月 20 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 Markus Winkler 提供,来源于 Unsplash

在我之前关于 Kafka 的文章中,我介绍了 Kafka 用于数据流处理的使用。我还展示了如何启动 Kafka 代理服务,并演示了如何使用 Kafka 生产者控制台应用程序发送消息以及如何使用 Kafka 消费者控制台应用程序接收消息。

在这篇文章中,我将向你展示如何使用 Python 利用 Kafka。具体来说,我将:

  • 使用 Python 向 Kafka 代理服务发送消息

  • 使用 Python 从 Kafka 代理服务接收消息

  • 构建一个动态图表应用程序,用于绘制和更新散点图,随时接收来自代理服务的新数据

使用 Python 和 Kafka

至少有三个 Python 库可供 Python 开发者与 Kafka 代理服务接口。它们是:

  • Kafka-Python

  • PyKafka

  • Confluent Kafka Python

对于本文,我将使用 Confluent Kafka Python 包。

要安装 Confluent Kafka Python 包,请使用 pip 命令:

!pip install confluent-kafka

生成消息

首先,让我们先从生产者开始。生产者是向 Kafka 代理服务发送消息的组件。以下代码片段指定了要连接的 Kafka 代理服务器:

from confluent_kafka import Producer
import socket

conf = {
    'bootstrap.servers': "localhost:9092",
    'client.id': socket.gethostname()
}

producer = Producer(conf)

你需要确保你的 Kafka 代理服务正在运行。有关如何启动服务的详细信息,请参阅 towardsdatascience.com/using-apache-kafka-for-data-streaming-9199699623fa

## 使用 Apache Kafka 进行数据流处理

了解如何安装和使用 Kafka 发送和接收消息

towardsdatascience.com](/using-apache-kafka-for-data-streaming-9199699623fa?source=post_page-----54dc20717cf7--------------------------------)

要发送消息,你可以使用Producer对象的produce()函数。你可以传递四个参数给它:

  • 要发送的主题

  • 消息负载的关键字

  • 消息负载

  • 轮询生产者以了解消息是否成功传递(或未传递)时要调用的回调函数。

以下代码片段将消息发送到 Kafka 代理服务:

def acked(err, msg):
    if err is not None:
        print("Failed to deliver message: %s: %s" % (str(msg), str(err)))
    else:
        print("Message produced: %s" % (str(msg)))

producer.produce("SomeTopic", key="key1", value="Hello", callback=acked)     
producer.poll(1)   # Maximum time (1s) to block while waiting for events

poll()函数返回处理的事件数量(回调服务的数量)。

让我们发送另一条具有不同关键字的消息:

producer.produce("SomeTopic", key="key2", value="World", callback=acked)     
producer.poll(1)

消费消息

消息发送完毕后,你现在可以处理消费者。以下代码片段连接到 Kafka 代理服务:

from confluent_kafka import Consumer

conf = {
    'bootstrap.servers': "localhost:9092",
    'group.id': "1",
    'auto.offset.reset': 'latest'
}

consumer = Consumer(conf)

group.id指示你属于哪个消费者组。如果有两个消费者分配了相同的组 ID 到同一个主题,它们将共享从同一主题读取的工作。

auto.offset.reset指示…指定当从主题分区消费时没有初始偏移量时,消费者应如何行为。

我将在另一篇文章中讨论偏移量。

为了消费消息,让我们定义一个名为consume()的函数。它接受消费者和要订阅的主题:

from confluent_kafka import KafkaError, KafkaException

def consume(consumer, topics):    
    try:
        consumer.subscribe(topics)
        # use this as a way to stop the loop
        t = threading.currentThread()
        while getattr(t, "run", True):
            msg = consumer.poll(timeout=5.0)
            if msg is None: 
                continue

            if msg.error():
                if msg.error().code() == KafkaError._PARTITION_EOF:
                    # End of partition event
                    sys.stderr.write('%% %s [%d] reached end at offset %d\n' %
                                     (msg.topic(), msg.partition(), msg.offset()))
                elif msg.error():
                    raise KafkaException(msg.error())
            else:
                key = msg.key().decode("utf-8")
                data = msg.value().decode("utf-8")
                print(key, data)
    finally:
        # Close down consumer to commit final offsets.
        consumer.close()

在这个函数中,你首先订阅了你想要监听的主题。然后,你使用threading.currentThread()函数检查当前线程上是否设置了名为run的属性,该线程用于运行此函数。这用于控制是否继续等待下一条消息或退出函数。

我们将使用无限循环来不断轮询 Kafka 代理服务。timeout参数允许你设置阻塞调用的时间,直到代理服务返回消息。如果你想更频繁地轮询代理,请将timeout设置为较低的值,例如0.5秒。

如果返回了消息,你可以提取其关键字和值,然后打印出来。最后,如果无限循环被终止,你将关闭消费者。

要运行consume()函数,我们将使用threading包:

import threading
thread = threading.Thread(target=consume, 
                          args=(consumer, ["SomeTopic"]))
thread.start()

start()函数将consume()函数作为独立线程运行,以免冻结你的 Jupyter Notebook。

你现在应该能看到由生产者发送的两个传入消息:

key1 Hello
key2 World

要终止消费者,只需将threadrun属性设置为Falseconsume()函数将停止运行:

thread.run = False

绘制图表

现在你已经能够使用 Confluent Kafka Python 包来生产和消费消息,是时候利用这项新知识做些有用的事情了!

让我们使用生产者模拟一个 IOT 设备向 Kafka 代理服务发送传感器数据,并在消费者端读取这些数据并绘制图表。随着新数据的接收,图表将动态更新。所有这些将在 Jupyter Notebook 中直接运行。

发送传感器数据

让我们定义一个名为 send_message() 的函数,它接受四个参数:

  • topic — 消息的主题

  • datetime — 收集的传感器数据的日期时间

  • temp1 — 传感器 1 的温度读数

  • temp2 — 传感器 2 的温度读数

这四个参数将用于发送消息:

def send_message(topic, datetime, temp1, temp2):
    producer.produce(topic, key="key", value=f"{datetime},{temp1},{temp2}", callback=acked)
    producer.poll(1)

我们还将定义一个名为 update() 的函数,它每 2 秒调用一次 send_message() 函数,传入一些随机值:

import threading
import datetime
import random

def update():
    threading.Timer(2.0, update).start()     # call update() every 5s
    send_message('SensorData',
                 datetime.datetime.utcnow(), # datetime in UTC
                 random.uniform(20, 39),     # temperature1
                 random.uniform(10, 29))     # temperature2

update()

消费消息并绘制图表

对于消费者,我们来创建 Consumer 对象:

from confluent_kafka import Consumer

conf = {
    'bootstrap.servers': "localhost:9092",
    'group.id': "1",
    'auto.offset.reset': 'latest'
}

consumer = Consumer(conf)

然后我们将利用 Plotly 向 FigureWidget 中添加两个散点图:

FigureWidget 是一个图形库,可以在 Jupyter Notebook 中显示图表。

from confluent_kafka import KafkaError, KafkaException

import time
import plotly.graph_objects as go
import numpy as np

# initialize a plot
fig = go.FigureWidget()

# add two scatter plots
fig.add_scatter(fill='tozeroy')
fig.add_scatter(fill='tozeroy')

我们现在可以从 Kafka broker 服务中轮询消息:

def consume(consumer, topics):
    counter = 0
    x  = []   # datetime
    y1 = []   # first temp
    y2 = []   # second temp
    n  = 12   # the number of points to display on the plot
    try:
        consumer.subscribe(topics)        
        t = threading.currentThread()
        while getattr(t, "run", True):
            msg = consumer.poll(timeout=2.0)
            if msg is None:         
                continue

            if msg.error():
                if msg.error().code() == KafkaError._PARTITION_EOF:
                    # End of partition event
                    sys.stderr.write('%% %s [%d] reached end at offset %d\n' %
                                     (msg.topic(), msg.partition(), msg.offset()))
                elif msg.error():
                    raise KafkaException(msg.error())
            else:
                data = msg.value().decode("utf-8")
                x.append(data.split(',')[0])          # datetime
                y1.append(float(data.split(',')[1]))  # first temp
                y2.append(float(data.split(',')[2]))  # second temp

                #---display the last n points---                
                # first scatter plot
                fig.data[0].x = x[-n:]                # datetime
                fig.data[0].y = y1[-n:]               # temp                
                # second scatter plot
                fig.data[1].x = x[-n:]                # datetime
                fig.data[1].y = y2[-n:]               # temp
    finally:
        # Close down consumer to commit final offsets.
        consumer.close()

display(fig)

让我们分析一下上面的代码片段。当从 broker 获取到一条消息时,它会被拆分为三部分 —— datetimetemp1temp2。它们分别被添加到 xy1y2 列表中:

data = msg.value().decode("utf-8")
                x.append(data.split(',')[0])          # datetime
                y1.append(float(data.split(',')[1]))  # first temp
                y2.append(float(data.split(',')[2]))  # second temp

随着时间的推移,列表会包含大量数据。因此,我们只希望绘制最近的 n 个点(在此示例中设置为 12)。要更新第一个散点图,设置 fig.data[0].xfig.data[0].y 属性。对于第二个散点图,设置 fig.data[1].xfig.data[1].y 属性:

 #---display the last n points---                
                # first scatter plot
                fig.data[0].x = x[-n:]                # datetime
                fig.data[0].y = y1[-n:]               # temp                

                # second scatter plot
                fig.data[1].x = x[-n:]                # datetime
                fig.data[1].y = y2[-n:]               # temp

就这样!每当接收到新消息时,散点图将会自动更新!

目前,当你运行代码时,会显示一个空的图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供

你现在可以准备开启一个线程来运行 consume() 函数:

import threading
thread = threading.Thread(target=consume, args=(consumer, ["SensorData"]))
thread.start()

过一段时间后,你应该会看到两个散点图更新:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供

这是更新图表的视频:

视频由作者提供

如常,若要暂停 consume() 函数,将 threadrun 属性设置为 False

thread.run = False

如果你喜欢阅读我的文章并且它对你的职业/学习有所帮助,请考虑注册成为 Medium 会员。每月 $5,你可以无限制访问 Medium 上的所有文章(包括我的文章)。如果你使用以下链接注册,我将获得少量佣金(对你没有额外费用)。你的支持意味着我可以花更多时间写出像这样的文章。

[## 使用我的推荐链接加入 Medium - 韦孟李]

阅读 Wei-Meng Lee 的每个故事(以及 Medium 上其他成千上万位作家的故事)。你的会员费用直接支持…

weimenglee.medium.com](https://weimenglee.medium.com/membership?source=post_page-----54dc20717cf7--------------------------------)

总结

本文展示了一个你可以使用 Kafka 构建的有用应用。特别是,我向你展示了如何使用 Python 和 Plotly 构建一个动态图表应用。Kafka 的实时流式特性使其成为需要低延迟数据更新的应用(如物联网应用)的理想选择。敬请关注下一篇 Kafka 文章!

使用大型语言模型作为推荐系统

原文:towardsdatascience.com/using-large-language-models-as-recommendation-systems-49e8aeeff29b?source=collection_archive---------0-----------------------#2023-04-10

最近研究的综述及自定义实现

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Mohamad Aboufoul

·

关注 发布于 Towards Data Science · 8 分钟阅读 · 2023 年 4 月 10 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来源:卢卡·巴吉奥Unsplash

近年来,大型语言模型(LLMs)在数据科学界和新闻界引起了极大的关注。自 2017 年变压器架构问世以来,我们见证了这些模型在自然语言任务复杂性方面的指数级进步,包括分类、意图与情感提取,以及生成与人类相似的文本。

从应用角度来看,将 LLMs 与各种现有技术结合使用,来弥补它们的缺陷(我最喜欢的之一是GPT + Wolfram Alpha 组合 用于处理数学和符号推理问题),其可能性似乎无穷无尽。

但令我惊讶的是,LLMs 也可以作为推荐系统单独使用,而无需任何额外的特征工程或其他常见推荐系统中的手动过程。这种能力主要归功于 LLMs 的预训练方式及其操作方式。

目录

  • LLMs 和变换器如何工作的回顾

  • LLMs 作为推荐系统

  • 使用自定义数据实现/复制 P5

  • 复制尝试 2 — 阿拉伯语

  • LLMs 作为推荐系统的优点和缺点

  • 最终思考

  • 代码

LLMs 和变换器如何工作的回顾

语言模型是概率模型,试图映射一系列标记(短语、句子等)的发生概率。它们在各种文本上进行训练,并相应地推导概率分布。对于它们可以处理的各种任务(总结、问答等),它们通过条件概率迭代地选择最可能的标记/词汇来继续提示。请参见下面的示例:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

基于上下文的后续标记的概率示例(作者提供的图片)

LLMs 是经过大量文本训练的语言模型,这些模型具有庞大的架构,并利用了大量计算资源。它们通常由变换器架构驱动,这种架构在 Google 的著名 2017 年论文“Attention Is All You Need”中被引入。这种架构利用了“自注意力”机制,使得模型能够在预训练过程中学习不同标记之间的关系。

在对足够大的文本集合进行预训练后,相似的词汇将具有相似的嵌入(例如:“King”,“Monarch”),而不同的词汇将具有更大的差异。此外,利用这些嵌入,我们将看到词汇之间的代数映射,使模型能够更有效地确定序列的正确下一个标记。

自注意力嵌入的附加好处是,它们会根据周围的词汇而有所变化,使其更贴合于特定上下文中的含义。

斯坦福大学的克里斯托弗·曼宁博士提供了一个关于 LLMs 如何工作的高层次概述

LLMs 作为推荐系统

2022 年,Rutger’s University 的研究人员发布了论文**《推荐作为语言处理(RLP):统一预训练、个性化提示与预测范式(P5)》**(Geng et. al)。论文中介绍了一种“灵活统一的文本到文本范式”,将多个推荐任务结合在一个系统中:P5。该系统能够通过自然语言序列执行以下操作:

  • 顺序推荐

  • 评分预测

  • 解释生成

  • 评论总结

  • 直接推荐

让我们来看看论文中的一个顺序推荐任务示例。

Input: "I find the purchase history list of user_15466:
4110 -> 4467 -> 4468 -> 4472
I wonder what is the next item to recommend to the user. Can you help
me decide?"
Output: "1581"

研究人员为用户和每个项目分配了唯一的 ID。使用包含数千名用户(及其购买历史)和唯一项目的训练集,LLM 能够学习到某些项目彼此相似以及某些用户对某些项目有倾向(由于自注意力机制的特性)。在所有这些购买序列的预训练过程中,模型本质上经历了一种协同过滤的形式。它查看用户购买了相同的项目以及哪些项目往往一起购买。结合 LLM 生成上下文嵌入的能力,我们突然拥有了一个非常强大的推荐系统。

在上述示例中,尽管我们不知道每个 ID 对应的项目是什么,但我们可以推断出项“1581”被选择的原因是其他用户购买了它,并且与“user_15466”已经购买的任何项一起购买了。

关于 P5 的架构,它**“利用预训练的 T5 检查点作为骨干”**(Geng et. al)。

  • T5 是另一个 LLM,谷歌几年前发布的。它被设计来处理多种类型的序列到序列任务,因此作为这种系统的起点是合理的。

使用自定义数据实现/复制 P5

我对这篇论文印象深刻,想看看是否可以在较小的规模上复制顺序推荐能力。我决定利用 Hugging Face 的开源 T5 模型(T5-large),并制作了自己的自定义数据集来微调它以产生推荐。

我制作的数据集包含了超过 100 个运动设备购买的示例以及下一个要购买的项目。例如:

Input: “Soccer Goal Post, Soccer Ball, Soccer Cleats, Goalie Gloves”
Target Output: “Soccer Jersey”

当然,为了使其更为强健,我决定使用更具体的提示。提示如下:

输入: “购买的物品: {足球门框, 足球, 足球鞋, 守门员手套} — 推荐候选: {足球球衣, 篮球球衣, 橄榄球球衣, 棒球球衣, 网球衬衫, 曲棍球球衣, 篮球, 橄榄球, 棒球, 网球, 曲棍球, 篮球鞋, 橄榄球鞋, 棒球鞋, 网球鞋, 曲棍球头盔, 篮球臂套, 橄榄球护肩, 棒球帽, 网球拍, 曲棍球滑冰鞋, 篮球架, 橄榄球头盔, 棒球棒, 曲棍球棍, 足球标志, 篮球短裤, 棒球手套, 曲棍球护具, 足球护腿板, 足球短裤} — 推荐: ”

目标输出: “足球球衣”

上面你可以看到用户目前购买的物品规格,随后是尚未购买的推荐候选列表(这是整个库存)。

在使用 Hugging Face 的 Trainer API (Seq2SeqTrainer 训练了约 10 个周期) 对 T5 模型进行微调后,我获得了一些令人惊讶的好结果!一些示例评估:

输入: “购买的物品: {足球球衣, 足球门框, 足球鞋, 守门员手套} — 推荐候选: {篮球球衣, 橄榄球球衣, 棒球球衣, 网球衬衫, 曲棍球球衣, 足球, 篮球, 橄榄球, 棒球, 网球, 曲棍球, 篮球鞋, 橄榄球鞋, 棒球鞋, 网球鞋, 曲棍球头盔, 篮球臂套, 橄榄球护肩, 棒球帽, 网球拍, 曲棍球滑冰鞋, 篮球架, 橄榄球头盔, 棒球棒, 曲棍球棍, 足球标志, 篮球短裤, 棒球手套, 曲棍球护具, 足球护腿板, 足球短裤} — 推荐: ”

模型输出: “足球”

输入: “购买的物品: {篮球球衣, 篮球, 篮球臂套} — 推荐候选: {足球球衣, 橄榄球球衣, 棒球球衣, 网球衬衫, 曲棍球球衣, 足球, 橄榄球, 棒球, 网球, 曲棍球, 足球鞋, 橄榄球鞋, 棒球鞋, 网球鞋, 曲棍球头盔, 守门员手套, 橄榄球护肩, 棒球帽, 网球拍, 曲棍球滑冰鞋, 足球门框, 篮球架, 橄榄球头盔, 棒球棒, 曲棍球棍, 足球标志, 篮球短裤, 棒球手套, 曲棍球护具, 足球护腿板, 足球短裤} — 推荐: ”

模型输出: “篮球鞋”

这当然是主观的,因为推荐不一定是二元的成功/失败,但输出与迄今为止的购买项相似,确实令人印象深刻。

复制尝试 2 — 阿拉伯语

接下来,我想看看是否可以为阿拉伯语做这个,所以我翻译了我的数据集,并寻找了一些能够处理阿拉伯语文本的公开可用 T5 模型(AraT5, MT5等)。在尝试了十几个我在Hugging Face Hub上找到的变体后,我遗憾地发现无法得到令人满意的结果。

模型(经过微调后)会推荐相同的 1 或 2 件商品,不管购买历史如何——通常是“كرة القدم”,即“soccer ball”(不过,也许它知道阿拉伯语使用者喜欢足球,并且总是寻找新的足球)。即使尝试了这些模型的更大版本,如 MT5-xl,我也得到了相同的结果。这很可能是由于这些 LLM 在英语以外的语言上的数据稀缺。

对于我的最后一次尝试,我决定尝试将 Google Translate API 与我的英语微调 T5 模型结合使用。过程如下:

  • 将阿拉伯语输入 → 翻译成英语 → 输入到经过英语微调的模型中 → 获取模型的英语预测 → 翻译回阿拉伯语

不幸的是,这仍然没能帮助多少,因为翻译器会犯一些错误(例如:“كرة القدم”,我们用来代替“soccer”的词直接翻译成“foot ball”),这让模型出错,导致始终推荐相同的 1-2 件商品。

LLM 作为推荐系统的优点和陷阱

这种技术最突出的优点在于它作为独立系统实施的简便性。由于上述 LLM 和预训练技术的性质,我们可以绕过繁重的手动特征工程——模型应该能够自然地学习表示和关系。此外,我们可以在一定程度上绕过新商品的冷启动问题——商品的名称/描述可以被提取并自然地与用户已经购买/选择的现有商品相关联。

然而,这种方法有一些陷阱(不要急着丢弃你当前的推荐系统!),主要是由于对推荐内容的控制缺乏。

  • 因为没有对用户在检查后购买商品的不同操作/事件进行加权,所以我们完全依赖 LLM 预测的最可能的下一个 token(s)进行推荐。我们无法考虑用户书签、查看了一段时间、放入购物车等操作。

  • 此外,对于这些 LLM,我们确实面临大多数推荐基于相似性的风险(即与目前购买的商品语义相似的商品),尽管我认为通过大量用户购买历史数据,我们可以通过这种方法模拟的“协同过滤”方法来改善这个问题。

  • 最后,由于大型语言模型(LLMs)理论上可以生成任何文本,输出可能是一个与库存中的条目不完全匹配的字符串(尽管我认为这种情况发生的可能性较低)。

最终想法

根据 P5 论文的结果以及我尝试在 T5 模型上进行一些微调和提示的结果,我推测这种技术可以应用于许多语言模型。使用更强大的序列到序列模型可能会有显著帮助,尤其是当微调数据足够大且提示技术得到完善时。

然而,我不会建议(没有双关的意思)任何人单独使用这种方法。我建议将其与其他推荐系统技术结合使用,这样我们可以避免上述提到的陷阱,同时获得好处。如何实现这一点——我不确定,但我认为通过一些创造力,这种 LLM 技术可以以有益的方式集成(也许通过提取基于嵌入的特征用于协同过滤,或者与“双塔”架构结合使用,可能性是无限的)。

代码

参考文献

[1] S. Geng, S. Liu, Z. Fu, Y. Ge, Y. Zhang, 推荐作为语言处理(RLP):统一的预训练、个性化提示与预测范式(P5)(2023),第 16 届 ACM 推荐系统会议

使用 LazyPredict 评估 ML 算法

原文:towardsdatascience.com/using-lazypredict-for-evaluating-ml-algorithms-f912a43eef2

使用 LazyPredict 库自动选择最佳机器学习算法的过程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Wei-Meng Lee

·发表于 Towards Data Science ·10 分钟阅读·2023 年 3 月 27 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由 Victoriano Izquierdo 摄影,来自 Unsplash

评估机器学习算法是数据科学家常做的任务。虽然数据科学家需要了解不同类型的机器学习算法以应对不同类型的问题,但至关重要的是,他/她需要在自己的数据集上应用这些算法。只有这样,他/她才能更好地了解该使用哪种算法来训练模型,以及如何进行超参数调整。然而,选择合适的算法是一个耗时且令人疲惫的过程。理想情况下,应该有一个自动化的过程,只需提供数据,理想的机器学习算法将会为你选择。

这个问题的答案是 LazyPredictLazyPredict 是一个 Python 库,帮助你部分自动化选择最佳算法来训练你的数据集的过程。通过提供你的数据,LazyPredict 将使用超过 60 种机器学习算法来训练模型。最终结果将呈现给你。之后,你可以选择表现最好的机器学习算法进一步训练或优化你的数据集。

手动选择机器学习 (ML) 模型

要欣赏 LazyPredict 的美妙,了解通常如何手动完成这些事情总是有益的。因此,在本节中,我将使用糖尿病数据集作为示例,看看我们如何使用它来评估几种 ML 算法并选择与之最匹配的理想算法。为了简化起见,我们将使用以下 ML 算法:

  • 逻辑回归

  • K-最近邻 (KNN)

  • 支持向量机

糖尿病数据集: www.kaggle.com/datasets/mathchi/diabetes-data-set许可: CC0: 公开领域

加载数据

第一步是将 diabetes.csv 文件加载到 Pandas DataFrame 中,然后打印出其详细信息:

import numpy as np
import pandas as pd

df = pd.read_csv('diabetes.csv')
df.info()

特别是,数据框中没有NaN值:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 768 entries, 0 to 767
Data columns (total 9 columns):
 #   Column                    Non-Null Count  Dtype  
---  ------                    --------------  -----  
 0   Pregnancies               768 non-null    int64  
 1   Glucose                   768 non-null    int64  
 2   BloodPressure             768 non-null    int64  
 3   SkinThickness             768 non-null    int64  
 4   Insulin                   768 non-null    int64  
 5   BMI                       768 non-null    float64
 6   DiabetesPedigreeFunction  768 non-null    float64
 7   Age                       768 non-null    int64  
 8   Outcome                   768 non-null    int64  
dtypes: float64(2), int64(7)
memory usage: 54.1 KB

让我们查看数据框本身:

df

注意到一些列有 0 值,例如PregnanciesSkinThicknessInsulinOutcome

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

所有图片均由作者提供

清理数据

由于数据框中没有NaN值,现在检查一下具体哪些列有 0 值:

#---check for 0s---
print(df.eq(0).sum())

从下面的输出中,你可以看到只有DiabetesPedigreeFunctionAge列没有 0 值:

Pregnancies                 111
Glucose                       5
BloodPressure                35
SkinThickness               227
Insulin                     374
BMI                          11
DiabetesPedigreeFunction      0
Age                           0
Outcome                     500
dtype: int64

对于其他具有 0 值的列,只有PregnanciesOutcome列可以有 0 值——Pregnancies的 0 表示患者以前从未怀孕,而Outcome的 0 表示患者不是糖尿病患者。对于其他列,值为 0 是不合逻辑的——0 皮肤厚度,真的吗?

所以现在让我们替换这些列中的 0 值,以便它们具有更有意义的值。第一步是用NaN替换 0:

df[['Glucose','BloodPressure','SkinThickness',
    'Insulin','BMI']] = \
    df[['Glucose','BloodPressure','SkinThickness',
        'Insulin','BMI']].replace(0,np.NaN)
df

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后,用每列的均值替换NaN值:

df.fillna(df.mean(), inplace = True)   # replace the rest of the NaNs with the mean

你现在可以验证所有列中除了PregnanciesOutcome外都没有 0 值:

print(df.eq(0).sum())
Pregnancies                 111
Glucose                       0
BloodPressure                 0
SkinThickness                 0
Insulin                       0
BMI                           0
DiabetesPedigreeFunction      0
Age                           0
Outcome                     500
dtype: int64

检查特征之间的相关性

尽管数据集中有多个特征,但并非所有特征都对结果有贡献。因此,计算每列的相关因子是有用的:

corr = df.corr()
print(corr)

这是结果:

 Pregnancies  Glucose  BloodPressure  SkinThickness  \
Pregnancies                      1.00     0.13           0.21           0.08   
Glucose                          0.13     1.00           0.22           0.19   
BloodPressure                    0.21     0.22           1.00           0.19   
SkinThickness                    0.08     0.19           0.19           1.00   
Insulin                          0.06     0.42           0.07           0.16   
BMI                              0.02     0.23           0.28           0.54   
DiabetesPedigreeFunction        -0.03     0.14          -0.00           0.10   
Age                              0.54     0.27           0.32           0.13   
Outcome                          0.22     0.49           0.17           0.22   

                          Insulin  BMI  DiabetesPedigreeFunction  Age  Outcome  
Pregnancies                  0.06 0.02                     -0.03 0.54     0.22  
Glucose                      0.42 0.23                      0.14 0.27     0.49  
BloodPressure                0.07 0.28                     -0.00 0.32     0.17  
SkinThickness                0.16 0.54                      0.10 0.13     0.22  
Insulin                      1.00 0.17                      0.10 0.14     0.21  
BMI                          0.17 1.00                      0.15 0.03     0.31  
DiabetesPedigreeFunction     0.10 0.15                      1.00 0.03     0.17  
Age                          0.14 0.03                      0.03 1.00     0.24  
Outcome                      0.21 0.31                      0.17 0.24     1.00 

绘制特征之间的相关性

使用热图可视化特征之间的相关性,使理解这些数字变得更加容易:

%matplotlib inline
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(10, 10))
cax     = ax.matshow(corr,cmap='coolwarm', vmin=-1, vmax=1)

fig.colorbar(cax)
ticks = np.arange(0,len(df.columns),1)
ax.set_xticks(ticks)

ax.set_xticklabels(df.columns)
plt.xticks(rotation = 90)

ax.set_yticklabels(df.columns)
ax.set_yticks(ticks)

#---print the correlation factor---
for i in range(df.shape[1]):
    for j in range(9):
        text = ax.text(j, i, round(corr.iloc[i][j],2),
                       ha="center", va="center", color="w")
plt.show()

这是相关因子的热图。我们感兴趣的是查看哪些特征与Outcome高度相关(无论是正相关还是负相关)。因此,我们将查看Outcome列,并关注那些深红色(正相关)和深蓝色(负相关;此案例中没有)的单元格:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

你还可以通过编程找到最相关的特征:

#---get the top four features that has the highest correlation---
print(df.corr().nlargest(4, 'Outcome').index)

#---print the top 4 correlation values---
print(df.corr().nlargest(4, 'Outcome').values[:,8])

你可以看到,Outcome最相关的前三个特征是GlucoseBMIAge

Index(['Outcome', 'Glucose', 'BMI', 'Age'], dtype='object')
[1\.         0.49292767 0.31192439 0.23835598]

评估机器学习算法

数据清理完成后,下一步是选择不同的算法来使用你的数据训练模型。

使用逻辑回归

首先使用逻辑回归来训练模型。我们将使用交叉验证来评分模型:

from sklearn import linear_model
from sklearn.model_selection import cross_val_score

#---features---
X = df[['Glucose','BMI','Age']]

#---label---
y = df.iloc[:,8]

log_regress = linear_model.LogisticRegression()
log_regress_score = cross_val_score(log_regress, X, y, cv=10, scoring='accuracy').mean()

print(log_regress_score)

对于逻辑回归,我获得了 0.7669856459330144 的分数。我将把结果添加到列表中,以便稍后可以与其他模型进行比较:

result = []
result.append(log_regress_score)

使用 K-最近邻

接下来,我们将使用 K-最近邻算法来训练模型:

from sklearn.neighbors import KNeighborsClassifier

#---empty list that will hold cv (cross-validates) scores---
cv_scores = []

#---number of folds---
folds = 10

#---creating odd list of K for KNN---
ks = list(range(1,int(len(X) * ((folds - 1)/folds)), 2))

#---perform k-fold cross validation---
for k in ks:
    knn = KNeighborsClassifier(n_neighbors=k)
    score = cross_val_score(knn, X, y, cv=folds, scoring='accuracy').mean()
    cv_scores.append(score)

#---get the maximum score---
knn_score = max(cv_scores)

#---find the optimal k that gives the highest score---
optimal_k = ks[cv_scores.index(knn_score)]

print(f"The optimal number of neighbors is {optimal_k}")
print(knn_score)
result.append(knn_score)

我们将尝试不同的 K 值,并逐一打分。我们将选择最高的分数并打印出最佳的 K 值。结果如下:

The optimal number of neighbors is 19
0.7721462747778537

使用支持向量机

我们要使用的最终算法是支持向量机(SVM)。我们将尝试两种类型的核函数。首先尝试linear核函数:

from sklearn import svm

linear_svm = svm.SVC(kernel='linear')
linear_svm_score = cross_val_score(linear_svm, X, y,
                                   cv=10, scoring='accuracy').mean()
print(linear_svm_score)
result.append(linear_svm_score)

接下来是rbf(径向基函数)核:

rbf = svm.SVC(kernel='rbf')
rbf_score = cross_val_score(rbf, X, y, cv=10, scoring='accuracy').mean()
print(rbf_score)
result.append(rbf_score)

选择最佳性能算法

现在我们已经用不同的算法训练了数据集,我们可以汇总所有结果并进行比较:

algorithms = ["Logistic Regression", "K Nearest Neighbors", "SVM Linear Kernel", "SVM RBF Kernel"]
cv_mean = pd.DataFrame(result,index = algorithms)
cv_mean.columns=["Accuracy"]
cv_mean.sort_values(by="Accuracy",ascending=False)

从下图可以看出,KNN 是赢家,但其他模型也不落后。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

根据这个结果,你现在知道 KNN 是这个特定数据集的最佳算法。

使用 LazyPredict 进行分类问题

尽管我们从之前的结果中知道 KNN 在使用的四种算法中表现最好,但结论并非绝对。你可能会发现还有其他更适合你的数据集的算法。这时你可以使用 LazyPredict 自动训练你的数据集,利用不同的算法。

LazyPredict 支持回归和分类算法。

关于数据集,我将使用我之前清理过的数据。你可以使用从 CSV 文件中读取的原始数据,LazyPredict 会自动预处理你的数据——它将用均值(对于数值列)和常量值(对于分类列)替换缺失值。然后它会标准化数值列并编码分类列。

然而,自己进行数据预处理总是更好,因为你最了解自己的数据(正如我们数据集中某些列的 0 值不可接受所示)。

因此,我将从清理后的数据框df中提取前 8 列的特征,将第九列作为标签:

#---features---
X = df.iloc[:,:8]

#---label---
y = df.iloc[:,8]

接下来,安装 LazyPredict:

!pip install lazypredict

对于分类问题,导入LazyClassifier类。你还需要导入其他所需模块:

import lazypredict

# for classification problem
from lazypredict.Supervised import LazyClassifier

# split dataset into training and testing sets
from sklearn.model_selection import train_test_split

初始化LazyClassifier类,特别是将predictions参数设置为True

clf = LazyClassifier(verbose=0, ignore_warnings=True, 
                     custom_metric = None, predictions=True)

将数据集拆分为 80%的训练集和 20%的测试集:

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.2, random_state = 42)

你现在可以使用clf分类器来拟合(训练)你的数据,并使用各种分类算法进行预测:

scores, predictions = clf.fit(X_train, X_test, y_train, y_test)
scores

scores变量是一个数据框,显示了各种机器学习模型及其各自的指标,如准确率、ROC AUC、F1 分数等:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

你可以看到结果与我们最初的测试非常接近,其中 K-Nearest Neighbor 表现得相当不错(在这种情况下是第二好的模型)。当然,现在我们知道ExtraTreesClassifier算法效果更好。

predictions变量是一个数据框,包含了每个模型的预测值:

predictions

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用 LazyPredict 解决回归问题

在结束这篇文章之前,让我们使用LazyPredict处理一个回归问题。这一次,我们将利用sk-learn库中附带的 Boston 数据集。对于回归问题,使用LazyRegressor类:

from lazypredict.Supervised import LazyRegressor
from sklearn.model_selection import train_test_split
from sklearn import datasets

# load the Boston dataset
data = datasets.load_boston()
X, y = data.data, data.target

# split the data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.2, random_state=42)

clf = LazyRegressor(predictions=True)

# fit the data using different algorithms
models, predictions = clf.fit(X_train, X_test, y_train, y_test)
models

评估结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以及每个算法的预测值:

predictions

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你喜欢阅读我的文章并且这些文章对你的职业/学习有所帮助,请考虑成为 Medium 会员。会员费用为每月$5,可以无限制访问 Medium 上的所有文章(包括我的)。如果你通过以下链接注册,我将获得一小部分佣金(不会增加你的额外费用)。你的支持意味着我可以投入更多时间撰写类似的文章。

[## 使用我的推荐链接加入 Medium - Wei-Meng Lee

阅读 Wei-Meng Lee 的每一个故事(以及 Medium 上的其他成千上万的作家)。你的会员费用直接支持…

weimenglee.medium.com

总结

这篇文章展示了如何使用LazyPredict库简化机器学习算法选择的过程。一旦你确定了理想的算法,应该通过超参数调整进一步优化你的模型。如果你想快速了解这个话题,请查看我之前的文章:

## 使用 GridSearchCV 调整机器学习模型的超参数

学习如何使用 GridSearchCV 函数优化你的机器学习模型

[towardsdatascience.com

本研究利用Sen+MK方法分析了特定区域内的ET(蒸散发)趋势,重点评估了使用遥感数据的ET空间变化。该方法结合了Sen斜率估算器和Mann-Kendall(MK)检验,为评估长期趋势提供了稳健的框架,同时考虑了时间变化和统计显著性。 主要过程与结果: 1.ET趋势可视化:研究利用ET数据,通过ET-MK和ET趋势图展示了蒸散发在不同区域的空间和时间变化。这些图通过颜色渐变表示不同的ET水平及其趋势。 2.Mann-Kendall检验:应用MK检验来评估ET趋势的统计显著性。检验结果以二元分类图呈现,标明ET变化的显著性,帮助识别出有显著变化的区域。 3.重分类结果:通过重分类处理,将区域根据ET变化的显著性进行分类,从而聚焦于具有显著变化的区域。这一过程确保分析集中在具有实际意义的发现上。 4.最终输出:最终结果以栅格图和png图的形式呈现,支持各种应用,包括政策规划、水资源管理和土地利用变化分析,这些都是基于详细的时空分析。 ------------------------------------------------------------------- 文件夹构造: data文件夹:原始数据,支持分析的基础数据(MOD16A2H ET数据 宁夏部分)。 results文件夹:分析结果与可视化,展示研究成果。 Sen+MK_optimized.py:主分析脚本,适合批量数据处理和自动化分析。 Sen+MK.ipynb:Jupyter Notebook,复现可视化地图。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值