目录

什么是语义嵌入?

数据集一览

第一步:数据预处理

第二步:生成改进的语义嵌入

第三步:用 t-SNE 可视化嵌入

1. 评论语义聚类(按类别和评分)

2. 关键词语义空间

第四步:语义搜索的威力

查询示例:“电子产品质量好”

查询示例:“服务态度差”

第五步:数据分析与可视化

1. 评分分布

2. 类别分布

3. 各类别平均评分

4. 评分分布 by 类别

结论与应用

互动环节


想知道如何从海量的亚马逊评论中挖掘出有价值的洞察?或者如何让产品推荐系统变得更聪明、更贴近用户需求?在这篇博客中,我们将带你走进语义嵌入(Semantic Embeddings)和 t-SNE 可视化的世界,展示如何通过 Python 代码对亚马逊评论进行深度分析和语义搜索优化。无论你是数据科学爱好者、机器学习工程师,还是电商分析师,这篇文章都将为你提供一个清晰且实用的指南。


什么是语义嵌入?

语义嵌入是一种将文本转化为数值向量的方法,能够捕捉文字的含义和上下文。与传统的关键词匹配不同,语义嵌入可以理解“手机电池续航优秀”和“电池寿命长”在语义上的相似性。这种技术为语义搜索(Semantic Search)奠定了基础,让我们能够根据评论的真正含义而非仅仅是字面关键词来检索相关内容。

在这篇文章中,我们将使用一个包含 90 条模拟亚马逊评论 的数据集,涵盖六大类别:电子产品、服装、书籍、食品、家居用品和服务,并通过改进的语义嵌入技术对其进行分析。


数据集一览

我们使用的数据集包含 90 条模拟亚马逊评论,每条评论包括:

  • 摘要:简短的评论标题,如“手机电池续航优秀”。
  • 文本:详细的评论内容,如“这款手机的电池续航能力让我非常满意,一天重度使用完全没问题”。
  • 评分:从 1.0 到 5.0 的用户评分。
  • 类别:评论所属的产品类别,如“电子产品”或“服装”。

这些评论被设计为多样化,既有正面评价(如“耳机音质清晰”),也有负面反馈(如“屏幕有坏点”),为我们提供了丰富的分析素材。


第一步:数据预处理

在生成语义嵌入之前,我们需要对文本进行清洗。预处理步骤包括:

  • 去除标点和无关字符:确保文本干净。
  • 转为小写:统一格式。
  • 移除停用词:剔除如“的”、“是”、“在”等常见但意义不大的词语。

例如,“这款手机的电池续航能力让我非常满意”经过预处理后可能变成“手机 电池 续航 能力 满意”。这一步骤为后续的嵌入生成奠定了基础。

def preprocess_text(text):
    # 简单预处理示例
    text = text.lower().replace("'", "").replace(",", "")
    stop_words = {'的', '是', '在'}
    return " ".join(word for word in text.split() if word not in stop_words)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

第二步:生成改进的语义嵌入

我们采用了一种混合方法来生成语义嵌入,结合了 TF-IDF(词频-逆文档频率)和 类别特定关键词,并融入了情感信号。具体步骤如下:

  1. TF-IDF 特征提取:衡量每个词在文本中的重要性。
  2. 类别关键词增强:为每个类别(如“电子产品”)定义关键词(如“手机”、“电池”),并在嵌入中强化这些关键词的信号。
  3. 情感调整:根据正面词(如“优秀”、“满意”)和负面词(如“差”、“坏”)调整嵌入向量,突出评论的情感倾向。
def get_semantic_embedding(text, category_keywords):
    processed_text = preprocess_text(text)
    embedding_dim = 300
    base_vector = np.zeros(embedding_dim)
    
    # 类别中心
    category_centers = {
        '电子产品': np.array([10, 0, 0, 0, 0]),
        '服装': np.array([0, 10, 0, 0, 0]),
        # 其他类别略
    }
    
    # 检测主要类别
    main_category = max(category_keywords.items(), 
                       key=lambda x: sum(kw in processed_text for kw in x[1]))[0]
    base_vector[:5] = category_centers.get(main_category, np.zeros(5)) + np.random.normal(0, 0.5, 5)
    
    # 情感编码
    positive_words = ['好', '优秀', '满意']
    negative_words = ['差', '坏', '慢']
    pos_score = sum(word in processed_text for word in positive_words)
    neg_score = sum(word in processed_text for word in negative_words)
    base_vector[5] = 5 if pos_score > neg_score else -5 if neg_score > pos_score else 0
    
    # 填充噪声
    base_vector[6:] = np.random.normal(0, 0.1, embedding_dim - 6)
    return base_vector.tolist()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

最终,每条评论生成一个 300 维向量(可扩展至 1536 维),捕捉语义、类别和情感。 


第三步:用 t-SNE 可视化嵌入

使用 t-SNE 将高维嵌入降至 2D,直观展示效果。

def plot_enhanced_tsne_visualization(embeddings, labels, title, sentiment_scores=None):
    """增强的t-SNE可视化"""
    print("正在进行t-SNE降维...")
    embeddings_array = np.array(embeddings)

    # 调整t-SNE参数以获得更好的聚类效果
    tsne = TSNE(
        n_components=2,
        random_state=42,
        perplexity=min(20, max(5, len(embeddings)//3)),  # 动态调整perplexity
        learning_rate=200,
        n_iter=1000,
        early_exaggeration=12
    )
    tsne_results = tsne.fit_transform(embeddings_array)

    # 创建更清晰的可视化
    plt.figure(figsize=(15, 10))

    # 为每个类别分配不同的颜色
    unique_labels = list(set(labels))
    colors = plt.cm.tab10(np.linspace(0, 1, len(unique_labels)))

    # 绘制散点图
    for i, label in enumerate(unique_labels):
        mask = [l == label for l in labels]
        x_coords = tsne_results[mask, 0]
        y_coords = tsne_results[mask, 1]

        # 根据情感评分调整点的形状
        if sentiment_scores is not None:
            scores = [sentiment_scores[j] for j, m in enumerate(mask) if m]
            # 高分用圆形,低分用三角形
            high_score_mask = np.array(scores) >= 4.0
            low_score_mask = np.array(scores) < 3.0
            mid_score_mask = (np.array(scores) >= 3.0) & (np.array(scores) < 4.0)

            if np.any(high_score_mask):
                plt.scatter(x_coords[high_score_mask], y_coords[high_score_mask],
                            c=[colors[i]], label=f'{label} (好评)',
                            s=80, alpha=0.8, marker='o', edgecolors='black', linewidth=0.5)
            if np.any(low_score_mask):
                plt.scatter(x_coords[low_score_mask], y_coords[low_score_mask],
                            c=[colors[i]], label=f'{label} (差评)',
                            s=80, alpha=0.8, marker='^', edgecolors='red', linewidth=1)
            if np.any(mid_score_mask):
                plt.scatter(x_coords[mid_score_mask], y_coords[mid_score_mask],
                            c=[colors[i]], label=f'{label} (中评)',
                            s=60, alpha=0.6, marker='s', edgecolors='gray', linewidth=0.5)
        else:
            plt.scatter(x_coords, y_coords, c=[colors[i]], label=label,
                        s=80, alpha=0.8, edgecolors='black', linewidth=0.5)

    plt.title(title, fontsize=18, fontweight='bold', pad=20)
    plt.xlabel('t-SNE 维度 1', fontsize=14)
    plt.ylabel('t-SNE 维度 2', fontsize=14)

    # 添加图例
    plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', fontsize=10)

    # 添加网格
    plt.grid(True, alpha=0.3)

    plt.tight_layout()
    plt.show()
    print("t-SNE可视化完成!")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.

以下是两个关键的可视化结果:

1. 评论语义聚类(按类别和评分)

解锁亚马逊评论的秘密:基于语义嵌入与 t-SNE 可视化的深度分析_搜索

  • 描述:图中每个点代表一条评论,颜色表示类别(如蓝色为“书籍”,青色为“电子产品”),形状表示情感(圆形为好评 ≥ 4.0,三角形为差评 < 3.0,方形为中评 3.0-4.0)。
  • 观察
  • 同类别的评论(如“电子产品”)倾向于聚集在一起,表明嵌入很好地捕捉了类别特性。
  • 好评(圆形)通常形成较大的集群,而差评(三角形)则集中在较小的区域,可能反映特定问题(如“屏幕坏点”)。
  • 意义:这种聚类效果证明了嵌入能够区分不同类别和情感的评论,为后续分析提供了可靠基础。
2. 关键词语义空间

解锁亚马逊评论的秘密:基于语义嵌入与 t-SNE 可视化的深度分析_#语义嵌入_02

  • 描述:此图展示了 20 个关键词(如“手机”、“衣服”、“质量”)的语义嵌入分布,每个点用不同颜色标注。
  • 观察
  • 相关关键词(如“手机”和“电脑”)聚在一起,显示出语义上的相似性。
  • 类别无关的词(如“质量”、“价格”)分布较分散,反映其通用性。
  • 意义:关键词的聚类验证了嵌入方法在捕捉语义关系上的能力,这对优化语义搜索至关重要。

第四步:语义搜索的威力

基于生成的嵌入,我们实现了一个 语义搜索系统,能够根据查询返回语义上最相似的评论。

class EnhancedSemanticSearch:
    def __init__(self, texts, embeddings, categories, scores):
        self.texts, self.embeddings, self.categories, self.scores = texts, np.array(embeddings), categories, scores
    
    def search(self, query, top_k=3):
        query_embedding = get_semantic_embedding(query, category_keywords)
        similarities = cosine_similarity([query_embedding], self.embeddings)[0]
        top_indices = similarities.argsort()[-top_k:][::-1]
        return [{'text': self.texts[i], 'category': self.categories[i], 
                'score': self.scores[i], 'similarity': similarities[i]} 
                for i in top_indices]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

以下是一些示例:

查询示例:“电子产品质量好”
  • 结果
  1. 相似度 0.95 | 电子产品 | 评分 4.8
    文本:“这款手机的电池续航能力让我非常满意,一天重度使用完全没问题。”
  2. 相似度 0.91 | 电子产品 | 评分 4.6
    文本:“充电器的充电速度真的很快,半小时就能充到80%。”
  • 分析:即使评论中没有直接出现“质量好”,系统仍能识别出语义上的相似性,体现了嵌入的上下文理解能力。
查询示例:“服务态度差”
  • 结果
  1. 相似度 0.93 | 服务 | 评分 1.9
    文本:“客服态度很差,不耐烦,服务质量低。”
  2. 相似度 0.89 | 服务 | 评分 2.0
    文本:“包装很粗糙,东西都压坏了,保护不到位。”
  • 分析:系统准确检索出负面服务相关的评论,展示了情感嵌入的效果。

第五步:数据分析与可视化

为了进一步挖掘数据中的规律,我们生成了四种数据分析图表:

1. 评分分布

解锁亚马逊评论的秘密:基于语义嵌入与 t-SNE 可视化的深度分析_#语义嵌入_03

  • 观察:评分呈现双峰分布,高峰在 2.0-2.5(负面)和 4.5-5.0(正面),中立评价较少。
  • 意义:用户倾向于给出极端评价,可能反映强烈的满意或不满情绪。
2. 类别分布

解锁亚马逊评论的秘密:基于语义嵌入与 t-SNE 可视化的深度分析_#语义嵌入_04

  • 观察:六大类别各占 16.7%,分布均衡。
  • 意义:数据覆盖全面,便于跨类别比较。
3. 各类别平均评分

解锁亚马逊评论的秘密:基于语义嵌入与 t-SNE 可视化的深度分析_#t-SNE_05

  • 观察:电子产品(~4.2)和服务(~4.1)平均评分最高,食品(~3.7)最低。
  • 意义:电子产品和服务满意度较高,而食品可能因新鲜度等问题评分较低。
4. 评分分布 by 类别

解锁亚马逊评论的秘密:基于语义嵌入与 t-SNE 可视化的深度分析_搜索_06

  • 观察:电子产品和服务好评较多,食品和家居用品差评较多。
  • 意义:揭示了不同类别的用户体验差异,为改进方向提供线索。
def main():
    # 1. 加载增强的数据
    print("1. 加载增强的Amazon评论数据...")
    df = create_enhanced_sample_data()
    print(f"数据加载完成,共 {len(df)} 条评论")

    # 2. 数据预处理
    print("\n2. 数据预处理...")
    df['预处理文本'] = df['文本'].apply(preprocess_text)

    # 3. 定义类别关键词用于改进嵌入
    category_keywords = {
        '电子产品': ['手机', '电脑', '耳机', '充电', '屏幕', '处理器', '摄像头', '内存', '电池', '性能', '速度', '音质'],
        '服装': ['衣服', '面料', '版型', '颜色', '做工', '裤子', '鞋子', '材质', '款式', '舒适', '时尚', '质量'],
        '书籍': ['书', '内容', '知识', '学习', '印刷', '装帧', '理论', '案例', '实用', '作者', '文字', '纸张'],
        '食品': ['食品', '味道', '新鲜', '包装', '营养', '食材', '调味', '保质期', '口感', '健康', '美味'],
        '家居用品': ['家具', '设计', '实用', '材质', '组装', '收纳', '尺寸', '环保', '外观', '功能', '空间'],
        '服务': ['客服', '物流', '包装', '售后', '配送', '服务', '态度', '速度', '专业', '及时', '满意']
    }

    # 4. 生成改进的嵌入
    print("\n3. 生成改进的语义嵌入...")
    review_embeddings = get_embeddings_for_texts(df['预处理文本'].tolist(), category_keywords)

    # 5. 增强的t-SNE可视化
    print("\n4. 创建增强的评论t-SNE可视化...")
    plot_enhanced_tsne_visualization(
        review_embeddings,
        df['类别'].tolist(),
        "Amazon评论语义聚类可视化(按类别和评分)",
        df['评分'].tolist()
    )

    # 6. 词级嵌入可视化
    print("\n5. 创建词级语义嵌入可视化...")
    sample_words = ['手机', '电脑', '衣服', '鞋子', '书籍', '食品', '家具', '客服',
                    '质量', '价格', '服务', '速度', '舒适', '美味', '实用', '满意',
                    '好评', '差评', '推荐', '不推荐']
    word_embeddings = get_embeddings_for_texts(sample_words, category_keywords)

    plot_enhanced_tsne_visualization(
        word_embeddings,
        sample_words,
        "关键词语义空间可视化"
    )

    # 7. 增强的语义搜索演示
    print("\n6. 增强的语义搜索演示...")
    search_engine = EnhancedSemanticSearch(
        df['文本'].tolist(),
        review_embeddings,
        df['类别'].tolist(),
        df['评分'].tolist()
    )

    # 测试查询
    test_queries = [
        "电子产品质量好",
        "衣服穿着舒适",
        "书籍内容丰富",
        "服务态度差",
        "性价比高的产品"
    ]

    for query in test_queries:
        results = search_engine.search(query, top_k=3)
        search_engine.display_search_results(query, results)

    # 8. 数据分析可视化
    print("\n7. 创建数据分析可视化...")
    fig, axes = plt.subplots(2, 2, figsize=(15, 10))

    # 评分分布
    axes[0, 0].hist(df['评分'], bins=20, alpha=0.7, color='skyblue', edgecolor='black')
    axes[0, 0].set_title('评分分布', fontsize=14)
    axes[0, 0].set_xlabel('评分')
    axes[0, 0].set_ylabel('频次')

    # 类别分布
    category_counts = df['类别'].value_counts()
    axes[0, 1].pie(category_counts.values, labels=category_counts.index,
                   autopct='%1.1f%%', startangle=90)
    axes[0, 1].set_title('类别分布', fontsize=14)

    # 各类别平均评分
    avg_scores = df.groupby('类别')['评分'].mean().sort_values(ascending=True)
    axes[1, 0].barh(avg_scores.index, avg_scores.values, color='lightgreen', edgecolor='black')
    axes[1, 0].set_title('各类别平均评分', fontsize=14)
    axes[1, 0].set_xlabel('平均评分')

    # 评分vs类别散点图
    for i, category in enumerate(df['类别'].unique()):
        cat_data = df[df['类别'] == category]
        axes[1, 1].scatter([i] * len(cat_data), cat_data['评分'],
                           alpha=0.6, s=50, label=category)
    axes[1, 1].set_title('评分分布 by 类别', fontsize=14)
    axes[1, 1].set_xticks(range(len(df['类别'].unique())))
    axes[1, 1].set_xticklabels(df['类别'].unique(), rotation=45)
    axes[1, 1].set_ylabel('评分')
    axes[1, 1].legend(bbox_to_anchor=(1.05, 1), loc='upper left')

    plt.tight_layout()
    plt.show()

    print("\n所有演示完成!")
    print(f"数据统计:")
    print(f"- 总评论数: {len(df)}")
    print(f"- 类别数: {df['类别'].nunique()}")
    print(f"- 平均评分: {df['评分'].mean():.2f}")
    print(f"- 好评率 (≥4分): {(df['评分'] >= 4.0).mean()*100:.1f}%")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.

结论与应用

通过语义嵌入、t-SNE 可视化和数据分析,我们不仅能够从亚马逊评论中提取语义模式,还能实现精准的语义搜索和深入的洞察。这种技术有以下潜在应用:

  • 产品改进:识别食品类低评分原因(如“变质”),优化供应链。
  • 推荐系统:基于语义相似性推荐相关产品。
  • 客户服务:快速定位负面反馈并及时响应。

对于数据科学家和电商从业者来说,这套方法是一个强大的工具箱。文中的代码为了方便理解都是简化过的代码,你可以从绑定的资源中获取完整代码,尝试应用到自己的数据集上!