生成合成数据(第一部分)

使用大型语言模型(LLM)生成合成数据为解决一个普遍存在的问题提供了一个强大的解决方案:高质量、多样化且符合隐私要求的数据可用性。这可以用于多种场景,例如训练数据科学机器学习模型(SVM、决策树、KNN)、用数据微调另一个 GPT 模型、作为冷启动问题的解决方案、帮助构建具有现实数据的引人注目的演示/应用程序、场景测试等。

您可能希望利用合成数据的一些关键驱动因素。

  1. 人类数据可能包含我们不想使用的隐私限制和/或可识别数据。
  2. 合成数据可以比真实数据更结构化,因此更容易操作。
  3. 在数据稀疏或某些类别数据稀疏的领域,我们可能希望扩充数据。
  4. 在处理不平衡数据集或缺乏多样性的数据集时,我们可能希望创建数据来提高数据集的丰富性。

与传统的数据增强或手动数据创建方法不同,使用 LLM 可以生成丰富、细致且与上下文相关的合成数据集,从而显著提高其对企业和开发者的实用性。

我们将本教程分为两部分。在本食谱中,我们将遵循以下议程:

  1. 结构化提示的 CSV
  2. Python 程序的 CSV
  3. Python 程序的 Multitable CSV
  4. 简单地创建文本数据
  5. 处理不平衡或非多样化的文本数据 而在第二部分,我们将研究用于获取更好文本数据的提示策略。

最后两项对于创建用于微调另一个 GPT 模型的合成数据特别有用。例如,使用 gpt-4o 生成的更高质量数据来微调更便宜、更快的 gpt-3.5-turbo,以提高性能并降低成本。

设置

%pip install openai
%pip install pandas
%pip install scikit-learn
%pip install matplotlib
from openai import OpenAI
import os
import re
import numpy as np
import pandas as pd
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import json
import matplotlib

client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "<your OpenAI API key if not set as env var>"))

1. 结构化提示的 CSV

在这里,我们以最简单的方式创建数据。您可以通过解决三个关键点来快速生成数据:告诉它数据的格式(CSV)、模式以及有关列之间如何关联的有用信息(LLM 将能够从列名推断出这一点,但提供帮助将提高性能)。

datagen_model = "gpt-4o-mini"
question = """
创建一个包含 10 行房屋数据的 CSV 文件。
每行应包含以下字段:

 - id(从 1 开始的递增整数)
 - 房屋面积(平方米)
 - 房屋价格
 - 位置
 - 卧室数量

确保数字是合理的(即,房间越多通常面积越大,更贵的位置会增加价格。面积越大通常价格越高等等,确保所有数字都合理)。另外,只回复 CSV。
"""

response = client.chat.completions.create(
  model=datagen_model,
  messages=[
    {"role": "system", "content": "您是一个旨在生成合成数据的有用助手。"},
    {"role": "user", "content": question}
  ]
)
res = response.choices[0].message.content
print(res)
```csv
id,house_size_m2,house_price,location,number_of_bedrooms
1,50,150000,Suburban,2
2,75,250000,City Center,3
3,100,350000,Suburban,4
4,120,450000,Suburban,4
5,80,300000,City Center,3
6,90,400000,City Center,3
7,150,600000,Premium Area,5
8,200,750000,Premium Area,5
9,55,180000,Suburban,2
10,300,950000,Premium Area,6
```

2. Python 程序的 CSV

直接生成数据的问题在于我们能生成的数据量受限于上下文。相反,我们可以要求 LLM 生成一个 Python 程序来生成合成数据。这使我们能够扩展到更多数据,同时也通过检查 Python 程序来了解数据的生成方式。

然后,这使我们能够根据需要编辑 Python 程序,同时为其提供一个良好的起点。

question = """
创建一个 Python 程序来生成 100 行房屋数据。
我希望您在最后输出一个包含 100 行数据的 pandas DataFrame。
每行应包含以下字段:

 - id(从 1 开始的递增整数)
 - 房屋面积(平方米)
 - 房屋价格
 - 位置
 - 卧室数量

确保数字是合理的(即,房间越多通常面积越大,更贵的位置会增加价格。面积越大通常价格越高等等,确保所有数字都合理)。
"""

response = client.chat.completions.create(
  model=datagen_model,
  messages=[
    {"role": "system", "content": "您是一个旨在生成合成数据的有用助手。"},
    {"role": "user", "content": question}
  ]
)
res = response.choices[0].message.content
print(res)
当然!下面是一个根据您的规范生成合成房屋数据的 Python 程序。我们将创建一个具有定义的字段和特征的 pandas DataFrame。

```python
import pandas as pd
import random

def generate_housing_data(num_rows):
    data = []

    locations = [
        ('City Center', 10000, 150),  # (location name, base price per m², base size)
        ('Suburban Area', 8000, 100),
        ('Country Side', 5000, 80),
        ('Coastal Region', 12000, 110),
        ('Urban Neighborhood', 9000, 130)
    ]

    for i in range(1, num_rows + 1):
        # Randomly pick a location
        location, base_price_per_m2, base_size = random.choice(locations)

        # Generate number of bedrooms (1 to 5)
        number_of_bedrooms = random.randint(1, 5)

        # Calculate house size based on the number of bedrooms
        house_size = base_size + (10 * number_of_bedrooms) + random.randint(-5, 15)  # Adding some noise

        # Calculate house price based on house size and location
        house_price = base_price_per_m2 * house_size + random.randint(-5000, 10000)  # Adding some noise

        # Append the generated data to the list
        data.append({
            'id': i,
            'house_size_m2': house_size,
            'house_price': house_price,
            'location': location,
            'number_of_bedrooms': number_of_bedrooms
        })

    # Create a pandas DataFrame
    df = pd.DataFrame(data)
    return df

# Generate 100 rows of housing data
housing_data_df = generate_housing_data(100)

# Show the result
print(housing_data_df)
```

### Explanation:

- The `generate_housing_data` function creates synthetic housing data for a specified number of rows (`num_rows`).
- We define different locations with corresponding base prices per square meter and average house sizes.
- For each house, we randomly select a location, number of bedrooms, and calculate house size and price to ensure a sensible correlation between the values.
- Finally, we create a pandas DataFrame from the generated data and return it.

You can run this program in your Python environment, and it will output a DataFrame containing 100 rows of synthetic housing data.

我们需要确保正确解析此输出,因为通常会有围绕 Python 代码的文本。我们还可以明确要求它说明它对正在生成的数据所做的所有假设,但在这种情况下,它会自动告诉我们。

3. Python 程序的 Multitable CSV

然而,对于更复杂的关系,我们需要确保指定更多特征。

要创建多个相互关联的不同数据集(例如,房屋、位置、房屋类型),与之前一样,我们需要指定格式、模式和有用信息。但是,要获得良好性能所需的有用信息现在更高了。这是特定于案例的,但描述一些要点将是很有帮助的,例如数据集如何相互关联,处理数据集的大小以及它们之间的关系,确保主键和外键得到适当创建,并最好使用先前生成的数据集来填充新数据集,以便实际数据值在必要时匹配。

question = """
创建一个 Python 程序来生成 3 个不同的 pandas DataFrame。

1. 房屋数据
我需要 100 行。每行应包含以下字段:

 - id(从 1 开始的递增整数)
 - 房屋面积(平方米)
 - 房屋价格
 - 位置
 - 卧室数量
 - 房屋类型
 + 任何相关外键

2. 位置
每行应包含以下字段:

 - id(从 1 开始的递增整数)
 - 国家
 - 城市
 - 人口
 - 面积(平方米)
 + 任何相关外键

 3. 房屋类型
 - id(从 1 开始的递增整数)
 - 房屋类型
 - 平均房屋类型价格
 - 房屋数量
 + 任何相关外键

确保数字是合理的(即,房间越多通常面积越大,更贵的位置会增加价格。面积越大通常价格越高等等,确保所有数字都合理)。
确保 DataFrame 通常遵循常识性检查,例如,DataFrame 的大小相对于彼此来说是合理的。
确保外键匹配,并且您可以在创建每个连续的 DataFrame 时使用先前生成的 DataFrame。
"""

response = client.chat.completions.create(
  model=datagen_model,
  messages=[
    {"role": "system", "content": "您是一个旨在生成合成数据的有用助手。"},
    {"role": "user", "content": question}
  ]
)
res = response.choices[0].message.content
print(res)
当然!下面是一个 Python 程序,用于生成指定的三个 pandas DataFrame,用于房屋数据、位置数据和房屋类型。每个 DataFrame 将包含必要的字段,并且外键将确保它们之间的正确关系。

```python
import pandas as pd
import numpy as np

# Set random seed for reproducibility
np.random.seed(0)

# Function to generate location DataFrame
def generate_location_data(num_locations):
    locations = {
        "id": range(1, num_locations + 1),
        "country": np.random.choice(['USA', 'Canada', 'UK'], num_locations),
        "city": np.random.choice(['New York', 'Toronto', 'London', 'Vancouver', 'Manchester'], num_locations),
        "population": np.random.randint(50000, 1000000, num_locations),
        "area": np.random.randint(10000, 500000, num_locations)
    }
    return pd.DataFrame(locations)

# Function to generate house types DataFrame
def generate_house_type_data(num_house_types):
    house_types = {
        "id": range(1, num_house_types + 1),
        "house_type": np.random.choice(['Detached', 'Semi-Detached', 'Terraced', 'Flat'], num_house_types),
        "average_house_type_price": np.random.randint(100000, 1000000, num_house_types),
        "number_of_houses": np.random.randint(10, 1000, num_house_types)
    }
    return pd.DataFrame(house_types)

# Function to generate housing data DataFrame
def generate_housing_data(num_houses, location_df, house_type_df):
    house_sizes = np.random.randint(50, 300, num_houses)  # size in m^2
    location_ids = np.random.choice(location_df['id'], num_houses)
    house_type_ids = np.random.choice(house_type_df['id'], num_houses)

    # Generate prices based on size, location, and house type
    house_prices = (house_sizes * np.random.randint(2000, 5000, num_houses) // 10) + \
                   (location_ids * 1000) + \
                   (house_type_df.loc[house_type_ids - 1, 'average_house_type_price'].values // 4)

    housing_data = {
        "id": range(1, num_houses + 1),
        "house_size": house_sizes,
        "house_price": house_prices,
        "location_id": location_ids,
        "bedrooms": np.random.randint(1, 6, num_houses),
        "house_type_id": house_type_ids
    }

    return pd.DataFrame(housing_data)

# Generate DataFrames
num_locations = 10
num_house_types = 4
num_houses = 100

location_df = generate_location_data(num_locations)
house_type_df = generate_house_type_data(num_house_types)
housing_df = generate_housing_data(num_houses, location_df, house_type_df)

# Display the generated DataFrames
print("Location DataFrame:")
print(location_df.head(), "\n")

print("House Types DataFrame:")
print(house_type_df.head(), "\n")

print("Housing DataFrame:")
print(housing_df.head(), "\n")

# Printing the DataFrame shapes
print(f"Shapes: \nLocation: {location_df.shape}, House Types: {house_type_df.shape}, Housing: {housing_df.shape}")
```

### Explanation of the Code:

1. **Location DataFrame:** 
   - Generates random locations with attributes such as country, city, population, and area.

2. **House Types DataFrame:** 
   - Generates different types of houses along with average prices and quantity available.

3. **Housing DataFrame:** 
   - Generates housing data with increments on price based on house size, location, and house type, while also ensuring foreign keys (IDs) for location and house type.

### Output:
The three DataFrames generated will logically relate to one another with consistent data types and primary–foreign key relationships, resulting in a coherent representation of the housing dataset. The output displays heads of each DataFrame and their shapes for verification.

4. 简单地创建文本数据

在这里,我们首次了解如何创建文本数据。这可以用于微调另一个 GPT 模型。在这种情况下,我们设想自己是一家零售商,试图简化为他们销售的商品创建描述的过程。我们仍然需要指定数据的格式,特别是我们想要一种易于解析的输出格式。

我们下面考虑的示例是我们希望为 GPT 模型创建输入输出训练对以进行微调的示例。我们将产品名称及其所属类别作为输入,输出将是描述。

明确指定输出结构并发出不偏离此结构的命令有助于强制执行输出结构。您可以循环运行此程序并附加数据以生成更多合成数据。同样,与之前一样,我们需要很好地解析数据,以便我们后续的代码不会中断。

output_string = ""
for i in range(3):
  question = f"""
  我正在创建输入输出训练对来微调我的 gpt 模型。用例是零售商为产品目录中的产品生成描述。我希望输入是产品名称和类别(产品所属的类别),输出是描述。
  格式应为:
  1.
  输入:product_name, category
  输出:description
  2.
  输入:product_name, category
  输出:description

  请勿在该格式周围添加任何额外字符,否则会导致输出解析中断。
  创建尽可能多的训练对。
  """

  response = client.chat.completions.create(
    model=datagen_model,
    messages=[
      {"role": "system", "content": "您是一个旨在生成合成数据的有用助手。"},
      {"role": "user", "content": question}
    ]
  )
  res = response.choices[0].message.content
  output_string += res + "\n" + "\n"
print(output_string[:1000]) # displaying truncated response
1.
输入:无线蓝牙耳机, 电子产品
输出:戴上这款无线蓝牙耳机,沉浸在高品质音质中,它具有主动降噪功能和舒适的包耳式设计,可延长聆听时间。

2.
输入:有机绿茶, 饮料
输出:享用一杯清爽的有机绿茶,精选最优质的茶叶,富含抗氧化剂,非常适合随时提神醒脑。

3.
输入:不锈钢厨房刀, 厨具
输出:使用这款不锈钢厨房刀精确轻松地切割,它的人体工程学手柄和锋利的刀片设计可满足您的所有烹饪需求。

4.
输入:登山背包, 户外装备
输出:这款耐用的登山背包是您探索户外活动的理想选择,它拥有多个隔层以实现最佳整理,并且透气的设计可确保长途跋涉的终极舒适度。

5.
输入:空气炸锅, 厨房电器
输出:用这款空气炸锅,用更少的油烹饪您最喜欢的菜肴

注意:上面的输出被截断了。现在我们可以像下面这样解析它,以获取产品、类别和描述列表。例如,让我们看一下它生成的产品。

# regex to parse data
pattern = re.compile(r'Input:\s*(.+?),\s*(.+?)\nOutput:\s*(.+?)(?=\n\n|\Z)', re.DOTALL)
matches = pattern.findall(output_string)
products = []
categories = []
descriptions = []

for match in matches:
    product, category, description = match
    products.append(product.strip())
    categories.append(category.strip())
    descriptions.append(description.strip())
products
['无线蓝牙耳机',
 '有机绿茶',
 '不锈钢厨房刀',
 '登山背包',
 '空气炸锅',
 "儿童教育平板电脑",
 '蓝牙音箱',
 '瑜伽垫',
 '记忆棉床垫',
 '智能手表',
 '皮质钱包',
 '便携式手机充电器',
 '不粘锅套装',
 '宠物狗床',
 '健身追踪器',
 '无线耳塞',
 '有机绿茶',
 '可重复使用水瓶',
 '瑜伽垫',
 '皮质钱包',
 '空气炸锅',
 '游戏鼠标',
 '钩针编织套装',
 '登山靴',
 '香薰蜡烛',
 '蓝牙音箱',
 '不锈钢炊具套装',
 '健身追踪器',
 '装饰性抱枕',
 '环保清洁用品',
 '无线降噪耳机',
 '有机绿茶',
 '可调节瑜伽垫',
 '蓝牙智能秤',
 '不锈钢水瓶',
 '柔软棉质床上用品套装',
 '多功能厨房搅拌机',
 '环保可重复使用袋',
 '便携式手机充电器',
 '经典皮质钱包',
 '绒面革切尔西靴',
 '不粘锅套装',
 '宠物友好室内植物',
 '高蛋白能量棒',
 '带 USB 端口的 LED 台灯']

5. 处理不平衡或非多样化的文本数据

生成高质量合成数据的一些最重要方面是准确性(数据是否合理)、一致性(同一输入的两个单独数据点是否大致相同)和多样性(确保我们的数据分布尽可能匹配生产中的分布)。

为了增加数据的多样性,我们首先通过聚类来开始。这将为我们提供有关哪些集群代表性不足(不平衡数据集)或哪些数据根本未被处理(扩大数据分布)的信息。然后,我们将建议新的集群(使用 GPT 的自我反思调用)或要求我们的合成生成调用的下一轮明确针对代表性不足的集群。

我们可以递归地运行此生成和集群循环,以自动化生成多样化的合成数据。

为了演示目的,我们明确提示 LLM 生成有关 4 个不同主题领域的信息:车辆、服装、洗浴用品、食品。然后,我们将对数据进行聚类,看看它是否找到了这 4 个主题领域。

output_string = ""
for i in range(3):
  question = f"""
  我正在创建输入输出训练对来微调我的 gpt 模型。我希望输入是产品名称和类别,输出是描述。类别应该是诸如:手机、鞋子、耳机、笔记本电脑、电动牙刷等,而且更重要的是,类别应归入 4 个主要主题:车辆、服装、洗浴用品、食品)
  在每个示例的编号后,还要注明主题区域。格式应为:

  1. topic_area
  输入:product_name, category
  输出:description

  请勿在该格式周围添加任何额外字符,否则会导致输出解析中断。

  这里有一些有用的示例,以便您获得正确的输出样式。

  1) 服装
  输入:“鞋子名称, 鞋子”
  输出:“体验无与伦比的舒适感。这些鞋子融合了现代风格和传统的卓越缓震技术,非常适合那些时刻处于运动状态的人。”
  """

  response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
      {"role": "system", "content": "您是一个旨在生成合成数据的有用助手。"},
      {"role": "user", "content": question}
    ]
  )
  res = response.choices[0].message.content
  output_string += res + "\n" + "\n"
print(output_string[:1000]) # displaying truncated response
1. 车辆  
输入:“特斯拉 Model 3, 电动汽车”  
输出:“特斯拉 Model 3 是一款革命性的电动汽车,拥有令人印象深刻的续航里程和尖端技术,旨在提供激动人心的驾驶体验,同时最大限度地减少对环境的影响。”

2. 服装  
输入:“耐克 Air Max, 鞋子”  
输出:“穿上耐克 Air Max,提升您的运动鞋格调。这些鞋子融合了标志性风格与卓越的舒适度和支撑性,非常适合运动和休闲穿着。”

3. 洗浴用品  
输入:“欧乐 B Pro 1000, 电动牙刷”  
输出:“使用欧乐 B Pro 1000 实现卓越的清洁效果。这款电动牙刷采用 3D 清洁动作,可脉动和振荡,比普通手动牙刷去除更多牙菌斑。”

4. 食品  
输入:“奇多希腊酸奶, 酸奶”  
输出:“享用营养美味的奇多希腊酸奶。富含蛋白质和美味口味,它是健康早餐或随时享用的完美选择。”

5. 车辆

注意:上面的输出被截断了。在上面的示例中,我们会在每个示例中明确包含主题区域,因为它有助于引导后续输出并倾向于提供更好的性能。我们还可以给它一个实际的输出示例,以便它能正确理解样式,同时也帮助强制执行结构。

pattern = re.compile(r'(\d+)\.\s*(\w+)\s*Input:\s*"(.+?),\s*(.+?)"\s*Output:\s*"(.*?)"', re.DOTALL)
matches = pattern.findall(output_string)

topics = []
products = []
categories = []
descriptions = []

for match in matches:
    number, topic, product, category, description = match
    topics.append(topic)
    products.append(product)
    categories.append(category)
    descriptions.append(description)
products
['特斯拉 Model 3',
 '耐克 Air Max',
 '欧乐 B Pro 1000',
 '奇多希腊酸奶',
 '福特 F-150',
 "李维斯 511",
 '飞利浦 Sonicare',
 '桂格燕麦片',
 '丰田凯美瑞',
 '阿迪达斯 Ultraboost',
 '丰田凯美瑞',
 '耐克 Air Max',
 '高露洁电动牙刷',
 '蓝钻杏仁',
 '哈雷戴维森 Fat Boy',
 '阿迪达斯 Ultraboost',
 '多芬男士沐浴露',
 '桂格燕麦',
 '福特 F-150',
 "李维斯 501 牛仔裤",
 '特斯拉 Model 3',
 '耐克 Air Max',
 '欧乐 B Pro 1000',
 '有机杏仁酱',
 '雅马哈 YZF-R3',
 '阿迪达斯 Ultraboost',
 '飞利浦 Sonicare',
 '有机藜麦']

现在我们将对数据进行聚类以进行分析。我们将使用 K-means 聚类来分隔数据。K-means 的一个重要参数是 K,即集群的数量。

我们知道应该有 4 个集群(4 个主题),因为我们在提示中指定了这一点:车辆、电子产品、服装、食品。但总的来说,对于我们的数据,我们不知道集群的数量。因此,我们将使用肘部法则来找到最佳集群数量。

在肘部法则中,我们迭代一系列不同的 K 值,每次存储惯性。惯性衡量每个点与其集群质心之间的平方距离之和,从而告诉我们每个集群的分离程度和密度。如果我们绘制 K 与惯性的关系图,我们可以看到惯性如何下降,以及惯性下降最慢的地方(通常呈肘部形状),我们可以设置最佳集群数量。您可以在此处深入了解肘部法则(https://en.wikipedia.org/wiki/Elbow_method_(clustering))。

首先,让我们将数据存储在 pandas DataFrame 中以便于分析。

data = {
    'Product': products,
    'Category': categories,
    'Description': descriptions
}

df = pd.DataFrame(data)

接下来,让我们嵌入数据,因为嵌入是我们将在其中聚类的数据,如果它们在向量空间中相似,它们应该彼此靠近。

def get_embedding(text, model="text-embedding-3-small"):
    text = text.replace("\n", " ")

    response = client.embeddings.create(input=[text], model=model)

    return response.data[0].embedding

embedding_model = "text-embedding-3-small"
df["embedding"] = df.Category.apply(lambda x: get_embedding(x, model=embedding_model))

# Ensure there are embeddings to concatenate
if len(df.embedding.values) > 0:
    matrix = np.vstack(df.embedding.values)
else:
    matrix = np.array([])  # Handle the case where there are no embeddings
df
Product Category Description embedding
0 特斯拉 Model 3 电动汽车 特斯拉 Model 3 是一款革命性的电动汽车,拥有令人印象深刻的续航里程和尖端技术,旨在提供激动人心的驾驶体验,同时最大限度地减少对环境的影响。 [0.003255360759794712, -0.039260633289813995, ...
1 耐克 Air Max 鞋子 穿上耐克 Air Max,提升您的运动鞋格调。这些鞋子融合了标志性风格与卓越的舒适度和支撑性,非常适合运动和休闲穿着。 [0.03943369910120964, 0.022045187652111053, -0...
2 欧乐 B Pro 1000 电动牙刷 使用欧乐 B Pro 1000 实现卓越的清洁效果。这款电动牙刷采用 3D 清洁动作,可脉动和振荡,比普通手动牙刷去除更多牙菌斑。 [-0.003470012918114662, -0.01911414973437786, ...
3 奇多希腊酸奶 酸奶 享用营养美味的奇多希腊酸奶。富含蛋白质和美味口味,它是健康早餐或随时享用的完美选择。 [0.0208318829536438, -0.02645781636238098, -0....
4 福特 F-150 皮卡车 福特 F-150 是终极皮卡车,以其耐用性和多功能性而闻名,非常适合工作和娱乐。 [0.007467855699360371, -0.05288049206137657, -...
5 李维斯 511 牛仔裤 穿着李维斯 511 牛仔裤,时尚出行。这些牛仔裤采用经典设计和舒适的贴合度,非常适合日常穿着。 [0.0037206460256129503, 0.022772302851080894, ...
6 飞利浦 Sonicare 电动牙刷 使用飞利浦 Sonicare 体验全新水平的口腔护理。这款电动牙刷采用声波技术,可提供卓越的清洁效果。 [-0.00724813062697649, -0.011600878089666367, ...
7 桂格燕麦片 早餐谷物 用桂格燕麦片开始您的一天。这款燕麦片富含纤维和营养,是健康早餐的完美选择。 [-0.006529285106807947, 0.007865572348237038, ...
8 丰田凯美瑞 轿车 丰田凯美瑞在轿车类别中脱颖而出,以其可靠性、燃油效率和舒适的乘坐体验而闻名。 [-0.02088991366326809, -0.006191295105963945, ...
9 阿迪达斯 Ultraboost 跑鞋 穿上阿迪达斯 Ultraboost,前所未有地奔跑。这款跑鞋采用响应式缓震和舒适的贴合度,非常适合跑步爱好者。 [0.02679188922047615, 0.014639599248766899, 8....
10 丰田凯美瑞 汽车 丰田凯美瑞是一款可靠的中型轿车,以其燃油效率和舒适的乘坐体验而闻名。 [0.008056452497839928, -0.007912316359579563, ...
11 耐克 Air Max 鞋子 穿上耐克 Air Max,提升您的运动鞋格调。这些鞋子采用标志性设计和卓越的缓震技术,非常适合日常穿着。 [0.03943241760134697, 0.02208484522998333, -0....
12 高露洁电动牙刷 电动牙刷 使用高露洁电动牙刷改变您的口腔卫生习惯。这款电动牙刷提供卓越的清洁效果,有助于去除牙菌斑。 [-0.003470012918114662, -0.01911414973437786, ...
13 蓝钻杏仁 坚果 健康零食蓝钻杏仁。这些杏仁富含营养和美味,是您零食的完美选择。 [-0.013289917260408401, 0.036334190517663956, ...
14 哈雷戴维森 Fat Boy 摩托车 骑上哈雷戴维森 Fat Boy,体验开放道路的刺激。这款摩托车以其标志性的设计和强大的性能而闻名。 [0.012365399859845638, 0.03552943095564842, -0...
15 阿迪达斯 Ultraboost 运动鞋 在阿迪达斯 Ultraboost 中享受舒适与性能的完美结合。这款运动鞋采用响应式缓震和透气设计,非常适合跑步和日常穿着。 [0.013107392005622387, 0.02963760495185852, -0...
16 多芬男士沐浴露 沐浴露 使用多芬男士沐浴露,焕活和滋润您的肌肤。这款沐浴露可温和清洁并滋润肌肤,令肌肤感觉柔软健康。 [0.03760576993227005, -0.008475445210933685, -...
17 桂格燕麦 燕麦 用桂格燕麦开始您的一天。这款燕麦片富含营养和纤维,是健康早餐的完美选择。 [-0.00903365109115839, 0.00896345917135477, 0....
18 福特 F-150 卡车 福特 F-150 是一款耐用可靠的卡车,以其强大的性能和多功能性而闻名。非常适合工作和娱乐。 [0.023461222648620605, -0.026651185005903244, ...
19 李维斯 501 牛仔裤 牛仔裤 发现李维斯 501 牛仔裤的永恒风格。这些牛仔裤采用经典设计和舒适的贴合度,非常适合任何场合。 [0.003762696636840701, 0.02275814116001129, -0...
20 特斯拉 Model 3 手机 通过特斯拉 Model 3 探索驾驶的未来。这款电动汽车提供先进的技术和卓越的性能,是现代驾驶员的理想选择。 [0.03703858703374863, 0.03407958149909973, 0.0...
21 耐克 Air Max 鞋子 穿上耐克 Air Max,提升您的比赛水平。这些鞋子采用标志性设计和卓越的缓震技术,非常适合运动和休闲穿着。 [0.03943369910120964, 0.022045187652111053, -0...
22 欧乐 B Pro 1000 电动牙刷 使用欧乐 B Pro 1000 实现卓越的清洁效果。这款电动牙刷采用 3D 清洁动作,可脉动和振荡,比普通手动牙刷去除更多牙菌斑。 [-0.003470012918114662, -0.01911414973437786, ...
23 有机杏仁酱 食品 享用有机杏仁酱的奶油美味。这款杏仁酱富含营养和健康脂肪,是健康零食的完美选择。 [-0.014613640494644642, -0.002179765608161688,...
24 雅马哈 YZF-R3 手机 隆重推出雅马哈 YZF-R3,终极跑车。这款摩托车提供卓越的性能和操控性,非常适合寻求刺激的骑手。 [0.03703858703374863, 0.03407958149909973, 0.0...
25 阿迪达斯 Ultraboost 鞋子 发现阿迪达斯 Ultraboost,这是一款提供卓越舒适度和性能的鞋子。非常适合跑步和日常穿着。 [0.03944042697548866, 0.022062409669160843, -0...
26 飞利浦 Sonicare 电动牙刷 使用飞利浦 Sonicare 体验牙科护理革命。这款电动牙刷提供卓越的清洁效果,有助于改善口腔健康。 [-0.003470012918114662, -0.01911414973437786, ...
27 有机藜麦 食品 用有机藜麦滋养您的身体。这款藜麦富含营养和纤维,是健康饮食的完美选择。 [-0.014613640494644642, -0.002179765608161688,...

现在我们执行肘部方法。

# Determine the optimal number of clusters using the elbow method
inertias = []
range_of_clusters = range(1, 13)  # Adjust the range as necessary

for n_clusters in range_of_clusters:
    kmeans = KMeans(n_clusters=n_clusters, init="k-means++", random_state=42, n_init=10)
    kmeans.fit(matrix)
    inertias.append(kmeans.inertia_)

这将为我们输出一个图表,我们可以在其中直观地确定最佳集群点。我们可以看到惯性逐渐减小,而不是急剧的肘部,但惯性下降最陡峭的点似乎发生在 3、4 或 5 个集群左右,这与我们的预期相符。

# Plotting the elbow plot
plt.figure(figsize=(10, 6))
plt.plot(range_of_clusters, inertias, '-o')
plt.title('Elbow Method to Determine Optimal Number of Clusters')
plt.xlabel('Number of Clusters')
plt.ylabel('Inertia')
plt.xticks(range_of_clusters)
plt.show()

png

elbow_chart

为了演示,我们将选择 5 作为最佳集群数量,以表明只要我们大致正确,确切的选择位置并不重要。有许多正确的方法可以对数据进行分类。我们还存储每个数据点所属的集群。

n_clusters = 5

kmeans = KMeans(n_clusters=n_clusters, init="k-means++", random_state=42)
kmeans.fit(matrix)
labels = kmeans.labels_
df["Cluster"] = labels

我们现在来分析集群数据。我们将解决两个独立的问题。1. 数据不平衡,2. 扩展数据分布。

首先,对于数据不平衡,我们计算每个集群中的示例数量。然后,我们从每个集群中随机选择一些示例,并要求 LLM 确定这些示例属于哪些主题。

cluster_counts = df["Cluster"].value_counts().sort_index()
print(cluster_counts)
Cluster
0    5
1    7
2    8
3    6
4    2
Name: count, dtype: int64

我们可以在这里看到找到的主题: 环保交通、奢侈品和休闲用品、个人护理用品、电动牙刷和服装与服饰 与我们最初的提示: 车辆、服装、洗浴用品、食品 足够匹配,但并不完全相同。

由于我们选择了 5 个集群,它将洗浴用品分成了护肤品和个人护理品,这对我们下游的影响不大。

df
Product Category Description embedding Cluster
0 特斯拉 Model 3 电动汽车 特斯拉 Model 3 是一款革命性的电动汽车,拥有令人印象深刻的续航里程和尖端技术,旨在提供激动人心的驾驶体验,同时最大限度地减少对环境的影响。 [0.003255360759794712, -0.039260633289813995, ... 1
1 耐克 Air Max 鞋子 穿上耐克 Air Max,提升您的运动鞋格调。这些鞋子融合了标志性风格与卓越的舒适度和支撑性,非常适合运动和休闲穿着。 [0.03943369910120964, 0.022045187652111053, -0... 2
2 欧乐 B Pro 1000 电动牙刷 使用欧乐 B Pro 1000 实现卓越的清洁效果。这款电动牙刷采用 3D 清洁动作,可脉动和振荡,比普通手动牙刷去除更多牙菌斑。 [-0.003470012918114662, -0.01911414973437786, ... 1
3 奇多希腊酸奶 酸奶 享用营养美味的奇多希腊酸奶。富含蛋白质和美味口味,它是健康早餐或随时享用的完美选择。 [0.0208318829536438, -0.02645781636238098, -0.... 3
4 福特 F-150 皮卡车 福特 F-150 是终极皮卡车,以其耐用性和多功能性而闻名,非常适合工作和娱乐。 [0.007467855699360371, -0.05288049206137657, -... 0
5 李维斯 511 牛仔裤 穿着李维斯 511 牛仔裤,时尚出行。这些牛仔裤采用经典设计和舒适的贴合度,非常适合日常穿着。 [0.0037206460256129503, 0.022772302851080894, ... 2
6 飞利浦 Sonicare 电动牙刷 使用飞利浦 Sonicare 体验全新水平的口腔护理。这款电动牙刷采用声波技术,可提供卓越的清洁效果。 [-0.00724813062697649, -0.011600878089666367, ... 1
7 桂格燕麦片 早餐谷物 用桂格燕麦片开始您的一天。这款燕麦片富含纤维和营养,是健康早餐的完美选择。 [-0.006529285106807947, 0.007865572348237038, ... 3
8 丰田凯美瑞 轿车 丰田凯美瑞在轿车类别中脱颖而出,以其可靠性、燃油效率和舒适的乘坐体验而闻名。 [-0.02088991366326809, -0.006191295105963945, ... 0
9 阿迪达斯 Ultraboost 跑鞋 穿上阿迪达斯 Ultraboost,前所未有地奔跑。这款跑鞋采用响应式缓震和舒适的贴合度,非常适合跑步爱好者。 [0.02679188922047615, 0.014639599248766899, 8.... 2
10 丰田凯美瑞 汽车 丰田凯美瑞是一款可靠的中型轿车,以其燃油效率和舒适的乘坐体验而闻名。 [0.008056452497839928, -0.007912316359579563, ... 0
11 耐克 Air Max 鞋子 穿上耐克 Air Max,提升您的运动鞋格调。这些鞋子采用标志性设计和卓越的缓震技术,非常适合日常穿着。 [0.03943241760134697, 0.02208484522998333, -0.... 2
12 高露洁电动牙刷 电动牙刷 使用高露洁电动牙刷改变您的口腔卫生习惯。这款电动牙刷提供卓越的清洁效果,有助于去除牙菌斑。 [-0.003470012918114662, -0.01911414973437786, ... 1
13 蓝钻杏仁 坚果 健康零食蓝钻杏仁。这些杏仁富含营养和美味,是您零食的完美选择。 [-0.013289917260408401, 0.036334190517663956, ... 3
14 哈雷戴维森 Fat Boy 摩托车 骑上哈雷戴维森 Fat Boy,体验开放道路的刺激。这款摩托车以其标志性的设计和强大的性能而闻名。 [0.012365399859845638, 0.03552943095564842, -0... 0
15 阿迪达斯 Ultraboost 运动鞋 在阿迪达斯 Ultraboost 中享受舒适与性能的完美结合。这款运动鞋采用响应式缓震和透气设计,非常适合跑步和日常穿着。 [0.013107392005622387, 0.02963760495185852, -0... 2
16 多芬男士沐浴露 沐浴露 使用多芬男士沐浴露,焕活和滋润您的肌肤。这款沐浴露可温和清洁并滋润肌肤,令肌肤感觉柔软健康。 [0.03760576993227005, -0.008475445210933685, -... 1
17 桂格燕麦 燕麦 用桂格燕麦开始您的一天。这款燕麦片富含营养和纤维,是健康早餐的完美选择。 [-0.00903365109115839, 0.00896345917135477, 0.... 3
18 福特 F-150 卡车 福特 F-150 是一款耐用可靠的卡车,以其强大的性能和多功能性而闻名。非常适合工作和娱乐。 [0.023461222648620605, -0.026651185005903244, ... 0
19 李维斯 501 牛仔裤 牛仔裤 发现李维斯 501 牛仔裤的永恒风格。这些牛仔裤采用经典设计和舒适的贴合度,非常适合任何场合。 [0.003762696636840701, 0.02275814116001129, -0... 2
20 特斯拉 Model 3 手机 通过特斯拉 Model 3 探索驾驶的未来。这款电动汽车提供先进的技术和卓越的性能,是现代驾驶员的理想选择。 [0.03703858703374863, 0.03407958149909973, 0.0... 4
21 耐克 Air Max 鞋子 穿上耐克 Air Max,提升您的比赛水平。这些鞋子采用标志性设计和卓越的缓震技术,非常适合运动和休闲穿着。 [0.03943369910120964, 0.022045187652111053, -0... 2
22 欧乐 B Pro 1000 电动牙刷 使用欧乐 B Pro 1000 实现卓越的清洁效果。这款电动牙刷采用 3D 清洁动作,可脉动和振荡,比普通手动牙刷去除更多牙菌斑。 [-0.003470012918114662, -0.01911414973437786, ... 1
23 有机杏仁酱 食品 享用有机杏仁酱的奶油美味。这款杏仁酱富含营养和健康脂肪,是健康零食的完美选择。 [-0.014613640494644642, -0.002179765608161688,... 3
24 雅马哈 YZF-R3 手机 隆重推出雅马哈 YZF-R3,终极跑车。这款摩托车提供卓越的性能和操控性,非常适合寻求刺激的骑手。 [0.03703858703374863, 0.03407958149909973, 0.0... 4
25 阿迪达斯 Ultraboost 鞋子 发现阿迪达斯 Ultraboost,这是一款提供卓越舒适度和性能的鞋子。非常适合跑步和日常穿着。 [0.03944042697548866, 0.022062409669160843, -0... 2
26 飞利浦 Sonicare 电动牙刷 使用飞利浦 Sonicare 体验牙科护理革命。这款电动牙刷提供卓越的清洁效果,有助于改善口腔健康。 [-0.003470012918114662, -0.01911414973437786, ... 1
27 有机藜麦 食品 用有机藜麦滋养您的身体。这款藜麦富含营养和纤维,是健康饮食的完美选择。 [-0.014613640494644642, -0.002179765608161688,... 3

现在我们执行肘部方法。

# Determine the optimal number of clusters using the elbow method
inertias = []
range_of_clusters = range(1, 13)  # Adjust the range as necessary

for n_clusters in range_of_clusters:
    kmeans = KMeans(n_clusters=n_clusters, init="k-means++", random_state=42, n_init=10)
    kmeans.fit(matrix)
    inertias.append(kmeans.inertia_)

这将为我们输出一个图表,我们可以在其中直观地确定最佳集群点。我们可以看到惯性逐渐减小,而不是急剧的肘部,但惯性下降最陡峭的点似乎发生在 3、4 或 5 个集群左右,这与我们的预期相符。

# Plotting the elbow plot
plt.figure(figsize=(10, 6))
plt.plot(range_of_clusters, inertias, '-o')
plt.title('Elbow Method to Determine Optimal Number of Clusters')
plt.xlabel('Number of Clusters')
plt.ylabel('Inertia')
plt.xticks(range_of_clusters)
plt.show()

png

elbow_chart

为了演示,我们将选择 5 作为最佳集群数量,以表明只要我们大致正确,确切的选择位置并不重要。有许多正确的方法可以对数据进行分类。我们还存储每个数据点所属的集群。

n_clusters = 5

kmeans = KMeans(n_clusters=n_clusters, init="k-means++", random_state=42)
kmeans.fit(matrix)
labels = kmeans.labels_
df["Cluster"] = labels

我们现在来分析集群数据。我们将解决两个独立的问题。1. 数据不平衡,2. 扩展数据分布。

首先,对于数据不平衡,我们计算每个集群中的示例数量。然后,我们从每个集群中随机选择一些示例,并要求 LLM 确定这些示例属于哪些主题。

cluster_counts = df["Cluster"].value_counts().sort_index()
print(cluster_counts)
Cluster
0    5
1    7
2    8
3    6
4    2
Name: count, dtype: int64

我们可以在这里看到找到的主题: 环保交通、奢侈品和休闲用品、个人护理用品、电动牙刷和服装与服饰 与我们最初的提示: 车辆、服装、洗浴用品、食品 足够匹配,但并不完全相同。

由于我们选择了 5 个集群,它将洗浴用品分成了护肤品和个人护理品,这对我们下游的影响不大。

df
Product Category Description embedding Cluster
0 特斯拉 Model 3 电动汽车 特斯拉 Model 3 是一款革命性的电动汽车,拥有令人印象深刻的续航里程和尖端技术,旨在提供激动人心的驾驶体验,同时最大限度地减少对环境的影响。 [0.003255360759794712, -0.039260633289813995, ... 1
1 耐克 Air Max 鞋子 穿上耐克 Air Max,提升您的运动鞋格调。这些鞋子融合了标志性风格与卓越的舒适度和支撑性,非常适合运动和休闲穿着。 [0.03943369910120964, 0.022045187652111053, -0... 2
2 欧乐 B Pro 1000 电动牙刷 使用欧乐 B Pro 1000 实现卓越的清洁效果。这款电动牙刷采用 3D 清洁动作,可脉动和振荡,比普通手动牙刷去除更多牙菌斑。 [-0.003470012918114662, -0.01911414973437786, ... 1
3 奇多希腊酸奶 酸奶 享用营养美味的奇多希腊酸奶。富含蛋白质和美味口味,它是健康早餐或随时享用的完美选择。 [0.0208318829536438, -0.02645781636238098, -0.... 3
4 福特 F-150 皮卡车 福特 F-150 是终极皮卡车,以其耐用性和多功能性而闻名,非常适合工作和娱乐。 [0.007467855699360371, -0.05288049206137657, -... 0
5 李维斯 511 牛仔裤 穿着李维斯 511 牛仔裤,时尚出行。这些牛仔裤采用经典设计和舒适的贴合度,非常适合日常穿着。 [0.0037206460256129503, 0.022772302851080894, ... 2
6 飞利浦 Sonicare 电动牙刷 使用飞利浦 Sonicare 体验全新水平的口腔护理。这款电动牙刷采用声波技术,可提供卓越的清洁效果。 [-0.00724813062697649, -0.011600878089666367, ... 1
7 桂格燕麦片 早餐谷物 用桂格燕麦片开始您的一天。这款燕麦片富含纤维和营养,是健康早餐的完美选择。 [-0.006529285106807947, 0.007865572348237038, ... 3
8 丰田凯美瑞 轿车 丰田凯美瑞在轿车类别中脱颖而出,以其可靠性、燃油效率和舒适的乘坐体验而闻名。 [-0.02088991366326809, -0.006191295105963945, ... 0
9 阿迪达斯 Ultraboost 跑鞋 穿上阿迪达斯 Ultraboost,前所未有地奔跑。这款跑鞋采用响应式缓震和舒适的贴合度,非常适合跑步爱好者。 [0.02679188922047615, 0.014639599248766899, 8.... 2
10 丰田凯美瑞 汽车 丰田凯美瑞是一款可靠的中型轿车,以其燃油效率和舒适的乘坐体验而闻名。 [0.008056452497839928, -0.007912316359579563, ... 0
11 耐克 Air Max 鞋子 穿上耐克 Air Max,提升您的运动鞋格调。这些鞋子采用标志性设计和卓越的缓震技术,非常适合日常穿着。 [0.03943241760134697, 0.02208484522998333, -0.... 2
12 高露洁电动牙刷 电动牙刷 使用高露洁电动牙刷改变您的口腔卫生习惯。这款电动牙刷提供卓越的清洁效果,有助于去除牙菌斑。 [-0.003470012918114662, -0.01911414973437786, ... 1
13 蓝钻杏仁 坚果 健康零食蓝钻杏仁。这些杏仁富含营养和美味,是您零食的完美选择。 [-0.013289917260408401, 0.036334190517663956, ... 3
14 哈雷戴维森 Fat Boy 摩托车 骑上哈雷戴维森 Fat Boy,体验开放道路的刺激。这款摩托车以其标志性的设计和强大的性能而闻名。 [0.012365399859845638, 0.03552943095564842, -0... 0
15 阿迪达斯 Ultraboost 运动鞋 在阿迪达斯 Ultraboost 中享受舒适与性能的完美结合。这款运动鞋采用响应式缓震和透气设计,非常适合跑步和日常穿着。 [0.013107392005622387, 0.02963760495185852, -0... 2
16 多芬男士沐浴露 沐浴露 使用多芬男士沐浴露,焕活和滋润您的肌肤。这款沐浴露可温和清洁并滋润肌肤,令肌肤感觉柔软健康。 [0.03760576993227005, -0.008475445210933685, -... 1
17 桂格燕麦 燕麦 用桂格燕麦开始您的一天。这款燕麦片富含营养和纤维,是健康早餐的完美选择。 [-0.00903365109115839, 0.00896345917135477, 0.... 3
18 福特 F-150 卡车 福特 F-150 是一款耐用可靠的卡车,以其强大的性能和多功能性而闻名。非常适合工作和娱乐。 [0.023461222648620605, -0.026651185005903244, ... 0
19 李维斯 501 牛仔裤 牛仔裤 发现李维斯 501 牛仔裤的永恒风格。这些牛仔裤采用经典设计和舒适的贴合度,非常适合任何场合。 [0.003762696636840701, 0.02275814116001129, -0... 2
20 特斯拉 Model 3 手机 通过特斯拉 Model 3 探索驾驶的未来。这款电动汽车提供先进的技术和卓越的性能,是现代驾驶员的理想选择。 [0.03703858703374863, 0.03407958149909973, 0.0... 4
21 耐克 Air Max 鞋子 穿上耐克 Air Max,提升您的比赛水平。这些鞋子采用标志性设计和卓越的缓震技术,非常适合运动和休闲穿着。 [0.03943369910120964, 0.022045187652111053, -0... 2
22 欧乐 B Pro 1000 电动牙刷 使用欧乐 B Pro 1000 实现卓越的清洁效果。这款电动牙刷采用 3D 清洁动作,可脉动和振荡,比普通手动牙刷去除更多牙菌斑。 [-0.003470012918114662, -0.01911414973437786, ... 1
23 有机杏仁酱 食品 享用有机杏仁酱的奶油美味。这款杏仁酱富含营养和健康脂肪,是健康零食的完美选择。 [-0.014613640494644642, -0.002179765608161688,... 3
24 雅马哈 YZF-R3 手机 隆重推出雅马哈 YZF-R3,终极跑车。这款摩托车提供卓越的性能和操控性,非常适合寻求刺激的骑手。 [0.03703858703374863, 0.03407958149909973, 0.0... 4
25 阿迪达斯 Ultraboost 鞋子 发现阿迪达斯 Ultraboost,这是一款提供卓越舒适度和性能的鞋子。非常适合跑步和日常穿着。 [0.03944042697548866, 0.022062409669160843, -0... 2
26 飞利浦 Sonicare 电动牙刷 使用飞利浦 Sonicare 体验牙科护理革命。这款电动牙刷提供卓越的清洁效果,有助于改善口腔健康。 [-0.003470012918114662, -0.01911414973437786, ... 1
27 有机藜麦 食品 用有机藜麦滋养您的身体。这款藜麦富含营养和纤维,是健康饮食的完美选择。 [-0.014613640494644642, -0.002179765608161688,... 3

我们现在可以计算集群数据。我们将解决两个独立的问题。1. 数据不平衡,2. 扩展数据分布。

首先,对于数据不平衡,我们计算每个集群中的示例数量。然后,我们从每个集群中随机选择一些示例,并要求 LLM 确定这些示例属于哪些主题。

selected_examples = df.groupby('Cluster').apply(lambda x: x.sample(3, replace=True)).reset_index(drop=True)

# Format the selected examples
formatted_examples = "\n".join(
    f'Input: "{row["Product"]}, {row["Category"]}"\nOutput: "{row["Description"]}"\nCluster: "{row["Cluster"]}"'
    for _, row in selected_examples.iterrows()
)

topic_prompt = f"""
    我之前生成了一些输入输出训练对,然后根据类别对它们进行了聚类。我从每个集群中挑选了 3 个示例数据点,您可以在下面找到它们。
    我希望您识别这些集群所属的广泛主题领域。
    之前的示例:
    {formatted_examples}


    您的输出应严格遵循以下格式:
    Cluster: number, topic: topic
    Cluster: number, topic: topic
    Cluster: number, topic: topic

    请勿在该格式周围添加任何额外字符,否则会导致输出解析中断。
    """

response = client.chat.completions.create(
  model=datagen_model,
  messages=[
    {"role": "system", "content": "您是一个旨在分析聚类数据的有用助手。"},
    {"role": "user", "content": topic_prompt}
  ]
)
res = response.choices[0].message.content

pattern = re.compile(r"Cluster: (\d+), topic: ([^\n]+)")
matches = re.findall(pattern, res)
clusters = [{"cluster": int(cluster), "topic": topic} for cluster, topic in matches]
json_output = json.dumps(clusters, indent=2)
print(json_output)
[
  {
    "cluster": 0,
    "topic": "汽车  "
  },
  {
    "cluster": 1,
    "topic": "个人护理  "
  },
  {
    "cluster": 2,
    "topic": "鞋类  "
  },
  {
    "cluster": 3,
    "topic": "食品  "
  },
  {
    "cluster": 4,
    "topic": "汽车  "
  }
]

我们现在有了集群及其计数,因此我们可以提示 LLM 在我们想要的主题中生成更多示例。但是,在此示例中,我们不会进一步进行,因为它们已很好地分开,您只需按照上述过程提示模型生成数据即可。

接下来,我们将尝试处理增加数据分布多样性的问题。

首先,我们以类似的方式开始,从每个集群中随机选择一些示例,并要求 LLM 确定这些示例属于哪些主题。此外,在同一个 LLM 调用中,我们将要求它生成更多主题以增加我们数据的多样性。我们这样做是为了节省时间/成本。

selected_examples = df.groupby('Cluster').apply(lambda x: x.sample(3, replace=True)).reset_index(drop=True)

# Format the selected examples
formatted_examples = "\n".join(
    f'Input: "{row["Product"]}, {row["Category"]}"\nOutput: "{row["Description"]}"\nCluster: "{row["Cluster"]}"'
    for _, row in selected_examples.iterrows()
)

topic_prompt = f"""
    我之前生成了一些输入输出训练对,然后根据类别对它们进行了聚类。我从每个集群中挑选了 3 个示例数据点,您可以在下面找到它们。
    我希望通过类别来提高示例的多样性,因此请遵循以下过程:

    1. 您必须确定这些集群所属的广泛主题领域。
    2. 您应该生成不存在的进一步主题领域,以便我可以在这些主题中生成数据以提高多样性。


    之前的示例:
    {formatted_examples}


    您的输出应严格遵循以下格式:

    1. Cluster topic mapping
    Cluster: number, topic: topic
    Cluster: number, topic: topic
    Cluster: number, topic: topic

    2. New topics
    1. topic
    2. topic
    3. topic
    4. topic

    请勿在该格式周围添加任何额外字符,否则会导致输出解析中断。坚持该输出格式非常重要
    """

response = client.chat.completions.create(
  model=datagen_model,
  messages=[
    {"role": "system", "content": "您是一个旨在分析聚类数据的有用助手。"},
    {"role": "user", "content": topic_prompt}
  ]
)
res = response.choices[0].message.content
print(res)
1. Cluster topic mapping
Cluster: 0, topic: Automotive
Cluster: 1, topic: Personal Care
Cluster: 2, topic: Footwear
Cluster: 3, topic: Food
Cluster: 4, topic: Electric Vehicles

2. New topics
1. topic: Home Appliances
2. topic: Outdoor Equipment
3. topic: Smart Home Technology
4. topic: Fitness Equipment

我们在这里再次看到,我们明确提示了它应该遵循的输出结构。我还告诉它生成主题的目的(促进多样性),以便模型获得完整的上下文。

然后,我们将数据解析为集群映射 JSON 列表和主题列表。

parts = res.split("\n\n")
cluster_mapping_part = parts[0]
new_topics_part = parts[1]

# Parse cluster topic mapping
cluster_topic_mapping_lines = cluster_mapping_part.split("\n")[1:]  # Skip the first two lines
cluster_topic_mapping = [{"cluster": int(line.split(",")[0].split(":")[1].strip()), "topic": line.split(":")[2].strip()} for line in cluster_topic_mapping_lines]

# Parse new topics
new_topics_lines = new_topics_part.split("\n")[1:]  # Skip the first line
new_topics = [line.split(". ")[1] for line in new_topics_lines]

cluster_topic_mapping, new_topics
([{'cluster': 0, 'topic': 'Automotive'},
  {'cluster': 1, 'topic': 'Personal Care'},
  {'cluster': 2, 'topic': 'Footwear'},
  {'cluster': 3, 'topic': 'Food'},
  {'cluster': 4, 'topic': 'Electric Vehicles'}],
 ['topic: Home Appliances',
  'topic: Outdoor Equipment',
  'topic: Smart Home Technology',
  'topic: Fitness Equipment'])

最后,我们可以使用此信息来进一步提示模型以继续生成合成数据。我们通过将 JSON 列表中的所有主题传递给下面的提示来完成此操作。

output_string = ""
for i in range(3):
  question = f"""
  我正在创建输入输出训练对来微调我的 gpt 模型。我希望输入是产品名称和类别,输出是描述。类别应该是诸如:手机、鞋子、耳机、笔记本电脑、电动牙刷等,而且更重要的是,类别应归入一些主要主题:{[entry['topic'] for entry in cluster_topic_mapping]})
  在每个示例的编号后,还要注明主题区域。格式应为:

  1. topic_area
  输入:product_name, category
  输出:description

  请勿在该格式周围添加任何额外字符,否则会导致输出解析中断。

  这里有一些有用的示例,以便您获得正确的输出样式。

  1) 服装
  输入:“鞋子名称, 鞋子”
  输出:“体验无与伦比的舒适感。这些鞋子融合了现代风格和传统的卓越缓震技术,非常适合那些时刻处于运动状态的人。”
  """

  response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
      {"role": "system", "content": "您是一个旨在生成合成数据的有用助手。"},
      {"role": "user", "content": question}
    ]
  )
  res = response.choices[0].message.content
  output_string += res + "\n" + "\n"
print(output_string)
1. 汽车  
输入:“特斯拉 Model S, 电动汽车”  
输出:“特斯拉 Model S 凭借先进的电动技术提供激动人心的性能,提供时尚的设计、令人印象深刻的续航里程和行业领先的信息娱乐系统。”

2. 个人护理  
输入:“欧乐 B Pro 1000, 电动牙刷”  
输出:“欧乐 B Pro 1000 采用 3D 清洁动作,可振荡、旋转和脉动,以去除牙菌斑,确保更深层清洁,使牙龈更健康。”

3. 鞋类  
输入:“耐克 Air Max 270, 鞋子”  
输出:“穿上耐克 Air Max 270,享受舒适与时尚。这款鞋子采用大型 Max Air 气垫,提供卓越的缓震效果,透气的鞋面带来舒适的贴合感。”

4. 电子产品  
输入:“苹果 iPhone 12, 手机”  
输出:“苹果 iPhone 12 将强大的性能与惊艳的设计相结合,配备 A14 仿生芯片和先进的摄像头系统,可捕捉每一个瞬间的精彩细节。”

5. 食品  
输入:“Nature Valley 能量棒, 小吃”  
输出:“Nature Valley 能量棒采用简单美味的原料制成,提供健康的嘎吱嘎吱口感,是您冒险之旅的完美能量补充。”

6. 汽车  
输入:“福特 F-150, 电动汽车”  
输出:“福特 F-150 处于耐用性和创新性的前沿,其强大的电动版本为卡车类别设定了新的强度和可持续性标准。”

7. 个人护理  
输入:“飞利浦 Sonicare, 电动牙刷”  
输出:“飞利浦 Sonicare 通过动态技术提供卓越的清洁效果,每分钟提供高达 31,000 次振动,使口腔更健康、笑容更明亮。”

8. 鞋类  
输入:“阿迪达斯 Ultraboost, 鞋子”  
输出:“阿迪达斯 Ultraboost 是跑鞋领域的游戏规则改变者,采用响应式缓震和针织鞋面,带来舒适贴合的支撑,可适应任何跑步。”

9. 电子产品  
输入:“戴尔 XPS 13, 笔记本电脑”  
输出:“戴尔 XPS 13 以其惊艳的 InfinityEdge 显示屏、强大的性能和时尚的设计重新定义了笔记本电脑体验。非常适合寻求便携性和功能性的专业人士和学生。”

10. 食品  
输入:“卡夫通心粉和奶酪, 速食”  
输出:“卡夫通心粉和奶酪提供快速便捷的舒适食品,将奶油奶酪酱与完美煮熟的意大利面相结合,制作出令人满意的简单餐点。”

1. 汽车  
输入:“丰田凯美瑞, 手机”  
输出:“丰田凯美瑞是一款中型轿车,将效率与现代技术相结合。它提供宽敞的内饰和最新的功能,带来愉快的驾驶体验。”

2. 个人护理  
输入:“欧乐 B Pro 1000, 电动牙刷”  
输出:“欧乐 B Pro 1000 不仅提供强大的清洁功能,还通过其智能压力传感器和各种清洁模式来增强您的口腔卫生习惯。”

3. 鞋类  
输入:“耐克 Air Max, 鞋子”  
输出:“穿上耐克 Air Max,享受舒适。凭借尖端技术和时尚的设计,这些鞋子非常适合运动员和休闲穿着者。”

4. 食品  
输入:“Nature's Valley 能量棒, 食品”  
输出:“品尝 Nature's Valley 能量棒的健康美味。这款能量棒采用真正的原料制成,可为您的一天提供美味和嘎吱嘎吱的满足感。”

5. 电动汽车  
输入:“特斯拉 Model 3, 手机”  
输出:“特斯拉 Model 3 是一款革命性的电动汽车,将性能与可持续性相结合,拥有直观的界面和尖端技术,可提供卓越的驾驶体验。”

1. 汽车  
输入:“特斯拉 Model 3, 电动汽车”  
输出:“特斯拉 Model 3 将尖端技术与环保驾驶相结合。享受时尚的设计、令人印象深刻的续航里程和一流的安全功能,使其成为现代驾驶员的理想电动汽车。”

2. 个人护理  
输入:“欧乐 B Pro 1000, 电动牙刷”  
输出:“欧乐 B Pro 1000 可实现卓越的清洁效果。这款电动牙刷采用先进的 3D 清洁动作,可脉动和振荡,比普通手动牙刷去除更多牙菌斑,让您保持最佳口腔健康。”

3. 鞋类  
输入:“耐克 Air Max, 鞋子”  
输出:“穿上耐克 Air Max 鞋子,提升您的比赛水平。这些鞋子融合了标志性的缓震技术和大胆的风格,可提供终极舒适度和支撑性,非常适合休闲穿着和运动表现。”

4. 食品  
输入:“奥利奥饼干, 小吃”  
输出:“品尝经典的奥利奥饼干。它们酥脆的巧克力威化饼夹着令人无法抗拒的奶油夹心,是随时满足您甜食需求的完美选择。”

5. 个人护理  
输入:“嘉娜宝洁面水, 护肤品”  
输出:“嘉娜宝洁面水可温和地去除化妆品和杂质,同时滋润肌肤。这种舒缓配方适合所有肤质,是您日常护肤程序中的必备品。”

6. 汽车  
输入:“福特 F-150, 卡车”  
输出:“福特 F-150 是典型的皮卡车,结合了动力、可靠性和创新技术。配备先进的牵引能力和宽敞的内饰,它专为工作和娱乐而设计。”

7. 电子产品  
输入:“三星 Galaxy S21, 手机”  
输出:“通过三星 Galaxy S21 体验移动技术的未来。这款智能手机拥有令人惊叹的显示屏、强大的处理器和多种摄像头选项,非常适合以高清捕捉生活中的精彩瞬间。”

8. 鞋类  
输入:“阿迪达斯 Ultraboost, 鞋子”  
输出:“穿着阿迪达斯 Ultraboost 鞋子,时尚地跑步。这些鞋子以其舒适性和性能而闻名,采用响应式缓震技术,可提供无与伦比的能量回馈。”

9. 电子产品  
输入:“戴尔 XPS 13, 笔记本电脑”  
输出:“戴尔 XPS 13 以其惊艳的 InfinityEdge 显示屏、强大的性能和时尚的设计重新定义了笔记本电脑体验。非常适合寻求便携性和功能性的专业人士和学生。”

10. 个人护理  
输入:“飞利浦 Sonicare, 电动牙刷”  
输出:“飞利浦 Sonicare 的电动牙刷凭借其先进的声波技术保证了卓越的清洁体验。这款牙刷不仅有助于去除牙菌斑,还能促进牙龈更健康,让您的笑容更灿烂。”

您可以循环运行此程序以附加到您之前的数据,这样您就可以继续生成更多文本合成数据来训练另一个 GPT 模型,同时确保我们能够处理不平衡的数据集并生成多样化的数据。

您现在已经完成了合成数据生成教程的第一部分,我们已经介绍了:

  • 结构化提示的 CSV
  • Python 程序的 CSV
  • Python 程序的 Multitable CSV
  • 简单地创建文本数据
  • 处理不平衡或非多样化的文本数据

在第二部分,您将了解用于增强文本合成数据生成的更好提示技术。