大语言模型到底是个啥?从零看懂大语言模型(LLM)的本质

1. 简介

大语言模型代表了机器学习应用在自然语言处理 (NLP) 的一项巨大的技术突破。 机器学习非常擅长处理非结构化数据,机器学习可以将非结构化的数据以数学的形式结构化,例如,机器学习可以把文字、图片等转化为向量。这一转化方法有非常广泛的应用空间,也非常有助于进行统计分析。因此,基于机器学习技术的大语言模型可以用于很多场景,例如预测、监控和新闻、社交媒体以及政策报告的情感分析。

本指南介绍了经济学家等社会科学研究者可能会用到的大语言模型知识。本文会覆盖例如模型选择、预处理技术、主题建模和量化分析等方面。并且,为了展示大语言模型在社会科学研究中的具体应用,本文将利用大语言模型的方法,分析美国股价变化的驱动因素。

2. 支撑大语言模型的关键思想和技术

2.1 大语言模型技术的核心思想

机器学习技术非常擅长将非结构化数据转化为数学结构,在自然语言处理中,这一个过程叫做 “嵌入” (embedding)。 不同词语之间的关系,在向量空间中,被表示为 “欧氏距离“,如果欧氏距离越小,说明这两个词的关系越密切。例如,"football (足球) " 和 "basketball (篮球) " 两个单词语义接近,但是 “football” 和 "monsoon (季风) "的词义就差距较大,但是 “monsoon” 就和 "cloud (云) " 词义更相近。这种词嵌入的方式,可以很好地传达词语与词语之间的关系。如果是为句子、段落做嵌入,则可以看做是词语的加权平均,代表整句话或者整个段落的意思 (Arora et al., 2017)。嵌入为在语言处理中引入数学工具做好了准备,为后续的文本处理工作,例如情绪分析、翻译、句子完善等功能打好基础。

早期开发的自然语言处理工具,只能识别出单词的唯一词义,不能结合语境进行判断。 早期用于自然语言处理的神经网络工具,例如 Word2vec,为每个词语分配了一个唯一的向量。这些早期自然语言处理的方法在开发之后已经被经济学家们广泛使用。但是,这种方法只能关注于一个词语本身的意思,不能识别出每个词语在不同语境下可能存在的语义变化。例如,在 " The bank raises rates to lower inflation. (银行提高利率以降低通货膨胀) ",早期的工具无法准确识别出 " bank " 是中央银行的意思,它可能会认为是一个商业银行或者一个河岸。

让大语言模型成为自然语言处理技术最前沿的功能,就是它的 “transformer architecture”。 Transformer 可以准确识别不同词语在不同语境里的不同含义,不只是字典中的意思。例如,在上述的例子中,大语言模型可以准确地将 “bank” 识别为靠近 “money” 的词意,因为 “bank” 经常和 “money”、“rate” 出现在同个文本中,因此不会识别为 “河岸” 的意思。并且,大语言模型也会考虑词语在句子中的顺序,从而明确区分出 “The bank raises rates to lower inflation” 和 “The bank lowers rates to raise inflation.” 两句话的不同含义。

2.2 大语言模型技术的核心方法

传统的 Transformer 有两个最基础的工具:

  • encoder (编码),将文本转化为一个嵌入向量
  • decoder (解码),将嵌入向量转化为本文。

BERT (bidirectional encoder representations from transformer) 实际上就是基于 encoder 思想开发的,而 GPT (generative pretrained transformer) 借鉴的则是 decoder 的思想。

2025061015185020250610151850

GPT 根据每个单词的顺序、先前的文本和语义,将向量自行转化为文本,GPT 的自生成的过程,与自回归模型进行递归预测的思想是相似的。BERT 使用单词前和后的文本一同分析,从而对每个单词实现词嵌入,其思想类似于使用全样本进行计量分析。GPT 得到了更广泛的认可,但是不是所有任务都适用,而BERT 更适用于量化分析。

经济学家可以使用大语言模型,以更准确、高效地提取和分析大量文本。 大语言模型并不是一个白纸,它是通过互联网的大量信息预训练出来的模型。经济学家可以直接选用训练好的模型,或者可以根据其领域常用的一些经济学文本,调整 LLM 的参数、重新训练和估计 LLM (这一过程叫做 “微调 (fine - tuning)”),生成更加准确有效的模型进行预测。

如果不使用微调的方法,经济学家也可以直接利用 “chatbox” 使用大语言模型 (例如 ChatGPT, Gemini 等),或者调用它们提供的 API (application programming interface)。这种方法允许用户通过修改提示词 (prompts),结合 AI 上下文的提示来获得更好的答案,但是这种模型是无法微调的,对处理专业性强、复杂性大的任务,不够准确。

在这里插入图片描述

3. 如何将大语言模型应用于科研工作

3.1 数据处理

第一,准备好需要处理的文本数据,例如政策报告、新闻、政府发言等。

第二,将这些文本数据整理成 chunk (块)。 注意每一个 chunk 的文本内容需要兼顾到颗粒度和内容范围的广度,它需要足够长以覆盖关键信息,但是又不能太长,以至于将一大块文本折叠成单一的向量,失去了不同信息的细微差别。

第三,将单词分解成为词根 (root) 形式,简化 LLM 的嵌入处理过程。 Tokenisation 是将单词分解成较小的单位 (token)。词型还原 (lemmatisation) 则是反过来,将单词简化为其基本形式,专注于它们的核心意义。例如,Tokenisation 会把 “disinflationary” 分解为 “dis”, “inflation”, “ary”; Lemmatisation 会把 “lowered” 还原成 “lower”,“pressures” 还原成 “pressure”。不同的大语言模型 Tokenisation 和 lemmatisation 的具体技术规则不同,具体需要用什么大语言模型,如何使用,需要研究者甄别。

第四,当所有的文本块被分解化和还原化后,继续进行词嵌入化处理。 如果使用类似 BERT 的模型,模型会将整个语料块进行全局嵌入化,这被称为分类嵌入化 (classification (CLS) embedding)。如果使用基于 GPT 的模型,每个词块的含义是每个单词的加权平均。无论使用哪种方法,都可以用现成科技公司训练出来的模型进行处理,例如 Google, Meta 或者 OpenAI 等。除此之外,研究者们也可以用自己的数据和文本去训练自己的模型,对现有模型进行微调。

3.2 信号提取

研究者需要通过降维的方法。从文本中提取出信号和关键信息。 它通过提取对语义解释的最关键信息,降低高维的嵌入向量,提高计算性能。在大语言模型的分析中,能够完成这一方法的工具包括主题词建模 (topic modelling) 、聚类方法 (clustering techniques) 或者类似于 UMAP (Uniform Manifold Approximation and Projection) 的基于嵌入法的降维方法。本文主要关注 topic modelling 这一方法,因为它被较为广泛地应用。主题词建模可以是无监督的,也可以是有监督的。

无监督主题词模型通过关键词表,总结出每段文本的主要主题。 以 BERTopic 为例,一般来说,会先把每个词块嵌入化,降维之后,会将比较相似的嵌入组合进一个聚类中。在无监督主题词模型下,研究者需要总结出一个标签,能够最好的概括每个语料的 cluster。这些标签通常是研究者从原始的关键词名单中手动选择出一个最接近的单词,一方面可以反映出研究者的研究兴趣,也可以反映出不同语料聚类的主题差别。但是,这个方法的弊端是,无监督学习可能会生成研究者不感兴趣的聚类。 例如,在对股票市场的文本进行学习的时候,无监督主题词建模经常会将某家资产管理公司或者主要上市公司名称为主题的文本进行聚类,但是这对于那些研究宏观金融的研究者价值不大。

有监督学习可以避免产生这一问题,有监督学习允许研究者从外部选择一些自己感兴趣的主题。 一个常见的选项是 seeding,可以输入一系列与研究者研究兴趣有关的词语,引导主题词建模的过程。例如,研究者可以将 " 联邦储备委员会 “、” 政策利率 " 关键词输入给有监督学习模型,这种情况下,主题词聚类时就会更偏向宏观金融相关的主题。数据处理、Tokenizastion、数据嵌入化和主题词分类等主要步骤的流程如 Graph 1 所示。

img

3.3 定量分析

当文本数据被转化为向量,并按主题分类后,即可用于定量分析。 由于嵌入化的结果为向量格式,研究者可采用标准计量经济学工具进行深入分析,例如面板回归和时间序列回归模型。在后续示例中,我们将聚焦于情感分析这一话题。

在情感分析时,需要将预先定义的标签输入给每个文本块,分类可以是两类 (积极、消极) ,也可以是三类 (积极、消极、中性) ,或者更多类别。 如果没有大语言模型,情感分析的处理可能需要依靠研究者预先设定的词典来判断。这种方法这种方法很费力,而且容易出错。

情感分析可根据研究需求选择不同分析粒度。局部分析 (小文本块) 适用于捕捉文本中不同段落的情感变化 (如同时描述股市的积极和消极因素) ,能揭示多维度细节;**全局分析 (整篇文档) **则聚焦整体信息 (如货币政策声明的最终结论) ,忽略局部波动。选择依据取决于分析目标——需细节时用局部,需核心结论时用全局。

**情感分析中模型的选择需综合考虑任务复杂度、文本量、标注数据可用性、计算资源及专业需求等因素。**对于大多数应用场景,预训练的 encoder 模型 (如BERT (Devlin et al, 2019)、RoBERTa (Liu et al, 2019)) 是理想选择,因其能高效捕捉上下文情感信息且运行速度快;在高度专业化领域 ( 如央行文件分析) ,针对性训练的专用模型 (如CB-LMs) 对特定文本的细微语义识别更具优势。而基于 decoder 的 GPT 模型虽规模庞大,但因架构适配性和耗时问题,通常不是情感分类任务的最优解。

所以,应该如何选择 BERT 和 GPT 呢?在情感分析任务中,BERT 类模型和 GPT 类模型的应用方式存在显著差异:基于 BERT 的模型需通过带标签数据集进行微调,以优化嵌入表示和情感分类边界,适用于需要精准分类的场景;而基于 GPT 的预训练大模型通常无需微调,通过低成本上下文学习即可直接处理原始文本,适合快速部署和零样本任务。

3.4 输出结果评估

大语言模型作为机器学习工具,其核心评估标准在于预测的性能表现。 与传统的统计原则不同,大语言模型在分类任务中,应以最小化误分类率为目标。现代 LLMs 具有千亿级参数和高维嵌入向量,通过正则化、随机梯度下降等技术可以有效解决过拟合问题。在对大语言模型输出结果进行评估时,需根据具体应用场景选择误差指标:存在离群值时推荐绝对误差的标准,输出量级差异大时采用对数误差的标准,在类别不平衡且误判成本不均时,使用 F1 分数 (精确率和召回率的调和平均数) 能有效兼顾 “false positives” 和 “false negatives” 的平衡。作者在后文的举例中,并没有对如何进行输出结果评估的过程进行展示。

4. 实例分析:股票市场驱动因素的研究

本研究的目标是使用美国新闻报道的文本,识别美国股票价格的影响因素。本研究包括了 2021 年至 2023 年 63388 份日报新闻,覆盖了福布斯、路透社和 MarketWatch 等网站。样本期覆盖了美国的货币政策急剧收紧的时期和通货膨胀率较高的时期,作者操作的流程如下所示,主要包括了数据处理、主题词分类、情感分类和量化分析四大步骤

img

由于数据版权限制,作者提供的数据不是原始数据,代码里提供的是 arxiv 上一份生物学的文本数据,与股票市场毫无关系,因此本推文无法复现出原文呈现的结果,仅对代码和重要结果做讲解。

首先,在运行之前,需要按照要求配置环境,安装并导入如下 Python 包。

!pip install --quiet -r https://raw.githubusercontent.com/bis-med-it/LLM_Primer_for_Economists/main/requirements.txt

import re
import json
import requests
import pandas as pd
import numpy as np
import torch

from tqdm import tqdm
from bertopic import BERTopic
from umap import UMAP
from hdbscan import HDBSCAN
from bertopic.vectorizers import ClassTfidfTransformer
from sentence_transformers import SentenceTransformer

from transformers import AutoTokenizer, AutoModel, BitsAndBytesConfig
from gensim import corpora
from gensim.models.ldamodel import LdaModel
from sklearn.feature_extraction.text import CountVectorizer
from bertopic.representation import KeyBERTInspired

pd.set_option('display.max_colwidth', 1000)  # 这个设置会让pandas完整显示列内容,直到达到1000字符的长度才会截断。

4.1 数据处理

研究从 Factiva (美国媒体报道数据库) 获取 63388 篇与美股 (按与标普 500 的相关性筛选) 相关的新闻文章,将其拆分为 349896 个文本块 (每块 100 词) ,并利用 Llama 3.1 8B 模型将每个词转换为 4096 维向量。通过平均每文本块的 100 个词嵌入,最终生成代表整块核心信息的 4096 维向量。

## 读取数据
arxiv_jsonfile = r'https://github.com/bis-med-it/LLM_Primer_for_Economists/blob/main/arxiv.json?raw=true'# 读取数据,是一个从 ArXiv随机选取的json文件,不是报纸文件
word_chunk_size = 100# 设置每个文本块大小为100词
embeddingmodel = 'microsoft/Phi-3-mini-4k-instruct'# 选择分词模型

# 从URL中提取数据
response = requests.get(arxiv_jsonfile)
response.raise_for_status()  # 对错误的状态码提出异常

# 读取json数据
data = json.loads(response.text)
dfarxiv = pd.DataFrame(data)

# 预览数据
dfarxiv.head()

接着,对文本进行分块和 Tokenisation。

# 初始化变量名
docs = []
df_docs_mapper = []
docs_cnt = 0

# 遍历DataFrame中的每条记录并生成文本块
## 使用tqdm显示进度条,total参数设置总进度条长度
for i, rec in tqdm(dfarxiv.iterrows(), total=len(dfarxiv)):
    # 获取当前记录的摘要文本
    text = rec['summary']
    
    # 文本预处理:
    # 1. 将句点和换行符替换为空格
    text2 = re.sub(r'[\.\n]', ' ', text)  
    # 2. 将多个连续空格合并为单个空格
    text2 = re.sub(r'\s+', ' ', text2) 
    # 3. 移除非字母数字字符(只保留字母、数字和空格),并去除首尾空格
    text2 = re.sub(r'[^a-zA-Z0-9 ]', '', text2).strip() 
    
    # 将处理后的文本按空格分割成单词列表
    words = text2.split()

    # 从清洗后的文本创建单词块
    word_idx = 0# 初始化单词索引
    while word_idx < len(words):
        # 获取当前块(从当前索引开始,取 word_chunk_size 个单词)
        word_piece = words[word_idx: word_idx + word_chunk_size]
        # 检查当前块是否达到指定大小(word_chunk_size)
        is_piece_chunksize = len(word_piece) == word_chunk_size
        # 将单词列表重新组合成字符串
        chunk_text = ' '.join(word_piece)

        # 如果当前块达到指定大小且不在文档集合中,则添加到文档集合并更新映射关系
        if is_piece_chunksize and chunk_text notin docs:
            docs.append(chunk_text)  # 将文本块添加到文档列表
            df_docs_mapper.append((i, docs_cnt))  # 记录映射关系:(原始记录索引, 文档块索引)
            docs_cnt += 1# 文档计数器递增
        
        # 移动到下一个块的起始位置
        word_idx = word_idx + word_chunk_size
        
# 将文档映射关系列表转换为DataFrame
# df_docs_mapper原本是一个包含元组的列表,每个元组格式为(text_id, doc_id),现在将其转换为DataFrame,并指定列名为'text_id'和'doc_id'
df_docs_mapper = pd.DataFrame(df_docs_mapper, columns=['text_id', 'doc_id'])

# 将文档块列表(docs)转换为DataFrame
# 默认情况下,这个DataFrame只有一列(索引列+文本内容列)
# 合并两个DataFrame
df_docs = df_docs_mapper.merge(pd.DataFrame(docs), left_index=True, right_index=True)

# 汇报总页面,分块后的结果
print(f'Total number of pages: {len(df_docs_mapper.text_id.drop_duplicates())}, total number of chunks (each chunk contains {word_chunk_size} words): {len(docs)}')

剔除文档分块数超过全体文档平均分块数 75 百分位数的文档,并且和新闻发布日期合并,获得最终需要的 Dataframe。

# 计算文档分块数量的75百分位阈值(用于识别异常文档)
# chunk_stat 是一个包含分块数量统计信息的DataFrame,loc['75%']获取75百分位数
num_chunk_per_article_cufoff = chunk_stat.loc['75%'][0]

# 统计每篇文章(text_id)对应的分块数量
# 通过groupby对text_id分组,count()计算每个text_id对应的doc_id数量
doc_cnt_per_article = df_docs_mapper.groupby('text_id').count()

# 每篇文章允许的最大分块数阈值
print(f'Cutoff chunk size per article: {num_chunk_per_article_cufoff}')

# 筛选有效文章ID列表:
# 选择分块数量小于等于阈值的文章,提取这些文章的index(即text_id)并转为列表
valid_article_id = doc_cnt_per_article[doc_cnt_per_article['doc_id'] <= num_chunk_per_article_cufoff].index.to_list()

# 过滤原始文档映射表,只保留有效文章
df_docs_mapper = df_docs_mapper[df_docs_mapper.text_id.isin(valid_article_id)]

# 获取有效文档ID列表(过滤后的doc_id)
valid_docs_id = df_docs_mapper.doc_id.to_list()

# 打印有效文章数量和有效文档数量
print(f'Valid number of article, docs: {len(valid_article_id)}, {len(valid_docs_id)}')

# 将文档块与映射关系及发布日期进行合并
# - df_docs: 最终生成的DataFrame,包含文档块内容、对应的文档ID和原始文本ID,以及发布日期(如果有)
# 将文档块列表(docs)转换为临时DataFrame(默认会有数字列名)
docs_df = pd.DataFrame(docs)  # 临时DataFrame,包含所有文档块内容

# 执行合并操作:
# 1. 以df_docs_mapper为左表(包含text_id和doc_id的映射关系)
# 2. 通过inner join方式合并,确保只保留两边都存在的记录
# 3. 合并条件:左表的doc_id列 匹配 右表(docs_df)的索引
df_docs = df_docs_mapper.merge(docs_df, 
                              how='inner', 
                              left_on='doc_id', 
                              right_index=True)

# 重命名列,使数据结构更清晰:
# - text_id: 原始文本ID
# - doc_id: 文档块ID 
# - chunk: 实际的文本块内容
df_docs.columns = ['text_id', 'doc_id', 'chunk']

4.2 信号提取

本研究采用 BERTopic 对文本块进行初始主题聚类。 过滤无关主题 (如经济、政策等太宽泛的内容) 后,结合 KeyBERT 提取关键词并优化筛选,最终,本文通过 LDA 将约 2000 个主题压缩为更精简的关键词集群,LDA 的方法,使我们能够在更大的主题中分析文本。

为给主题分配更直观的标签,本研究采用 Llama 3.1 根据分组关键词集生成初始标签。 也可以在一开始的时候直接用 Llama 3.1 来主题词建模,但是这很消耗计算机算力。最后,我们对主题词建模的结果进行人工检查核对。结合 LDA 最早的主题词分组结果和 Llama 3.1 根据分组关键词集生成初始标签,我们将新闻分成三个大类:基本面 (含 KeyBERT 的关键词,如利润、经济、就业) 、货币政策 (如美联储和利率) 以及市场情绪 (如超买、热议、波动性和 IPO) 。该分析框架系统性地解构了影响股价的三重机制:基本面决定价值基础,货币政策影响资金成本,市场情绪形成风险溢价,这非常有助于读者理解股价波动的原因。

经过 BERTopic 和 LDA 主题建模处理后,数据集规模缩减至原始大小的 10%,最终产出 38751 个定向文本块,并按以下三类完成划分:基本面分析 (16879 个文本块) ,市场情绪 (14468 个文本块) 和货币政策 (7404 个文本块) 。

上述具体操作可分为三大步骤:词嵌入化、主题词建模、情感分析,最后进行量化分析。

4.2.1 词嵌入化

第一步,完成词嵌入化。这一步的核心目的是,利用预训练语言模型生成句子嵌入向量。

其中,代码里两个关键函数是:

  • get_sentence_embedding 通过分词器和模型生成单句嵌入向量的函数。具体而言,该函数将一个句子作为输入,对其进行标记,并将其传递给模型。
  • embeddings 存储整个数据集文档词嵌入向量的列表。

使用 CPU 和 GPU 的环境,在运行效率上存在差异:

  • CPU环境 直接加载预计算的嵌入向量,代码中是直接从作者的 GitHub 托管的 JSON 文件读取的,因为 CPU 实时生成嵌入效率较低。
  • GPU环境 实时调用指定模型和分词器进行嵌入计算,充分发挥硬件加速优势。
  • 输出处理 将最终嵌入列表转换为 numpy 数组格式,便于下游机器学习任务使用。

最后,将最终嵌入列表转换为 numpy 数组格式,便于下游机器学习任务使用。具体代码如下:

# 检测当前运行的设备(优先使用GPU,否则使用CPU)
device = torch.device("cuda"if torch.cuda.is_available() else"cpu")

if device.type == 'cpu':
    # CPU模式:从GitHub加载预计算的嵌入向量
    import io
    # 预训练嵌入文件的URL(添加raw=true参数获取原始文件)
    npzfileurl = 'https://github.com/bis-med-it/LLM_Primer_for_Economists/blob/main/embeddings_arxiv_msphi3.npz?raw=true'
    
    # 发起HTTP请求获取文件
    response = requests.get(npzfileurl)
    response.raise_for_status()  # 检查请求是否成功
    
    # 加载npz文件内容到内存
    with np.load(io.BytesIO(response.content)) as data:
        embeddings = data['array']  # 提取存储的嵌入数组
        
else:
    # GPU模式:实时计算嵌入向量
    # 加载预训练模型(自动分配到可用设备)
    llm_engine = AutoModel.from_pretrained(
        embeddingmodel,       # 模型名称/路径
        device_map='auto',    # 自动分配设备
        torch_dtype=torch.float16,  # 使用半精度减少显存占用
   ).to(device)  # 确保模型在目标设备上
    
    # 加载对应的分词器
    tokenizer = AutoTokenizer.from_pretrained(embeddingmodel)

    # 定义嵌入生成函数
    def get_sentence_embedding(sentence):
        # 文本分词化并转换为PyTorch张量
        inputs = tokenizer(sentence, return_tensors='pt').to(device)
        
        # 禁用梯度计算
        with torch.no_grad():
            outputs = llm_engine(**inputs)  # 模型前向传播
            
        # 获取最后一层隐藏状态
        # 在BERT等Transformer模型中,“最后一层的隐藏状态”(last_hidden_state)是指模型最后一层(即最终输出层)生成的所有输入token的上下文向量表示。它是模型对输入文本的深度编码结果,包含了每个token在全局上下文中的语义信息。
        last_hidden_state = outputs.last_hidden_state
        # 沿序列维度取平均,并降维
        sentence_embedding = torch.mean(last_hidden_state, dim=1).squeeze().tolist()
        return sentence_embedding

    # 批量处理文档(使用tqdm显示进度条)
    embeddings = [get_sentence_embedding(doc) for doc in tqdm(docs)]
    # 将列表转换为numpy数组
    embeddings = np.array(embeddings)

# (可选)保存计算结果,供后续使用
# np.savez_compressed('embeddings_arxiv_msphi3.npz', array=embeddings)
4.2.2 主题词建模

img

主题词建模具体步骤如上图所示:首先用 BERTopic 建模,将文本分为 25 个主题后,再用 LDA 对 25 个主题进行重新聚合,最后生成 5 个主题。第一步,BERTopic 建模。其中关键的函数定义如下:

  • 核心词数量 num_top_words 是每个主题的关键词数量。
  • KeyBERT关键词 num_keybert_words 是使用 KeyBERT 模型生成的主题特征词。
  • 主题数量上限 topic_limit 是允许生成的最大主题数。
# 主题建模参数配置
num_top_words = 30        # 每个主题显示的关键词数量
num_keybert_words = 10    # KeyBERT提取的每个主题特征词数量
topic_limit = 20          # 最大主题数量限制
min_cluster_size = 10     # 最小聚类样本量(低于此值不视为独立主题)
n_gram_range = (1, 3)     # 关键词组合长度范围(1-3个单词)

# 初始化KeyBERT主题表示模型
representation_model = {
    "KeyBERT": KeyBERTInspired(
        top_n_words=num_keybert_words,  # 每个主题提取的特征词数量
        nr_repr_docs=20                 # 每个主题使用的代表文档数量
   )
}

# 文本向量化模型(移除英文停用词)
vectorizer_model = CountVectorizer(stop_words="english")

# 步骤1 - 配置词嵌入模型
embedding_model = 'sentence-transformers/all-MiniLM-L6-v2'# 轻量级句子嵌入模型

# 步骤2 - 降维模型配置
umap_model = UMAP(
    n_neighbors=5,      # 邻域样本数(值越大越关注全局结构)
    n_components=10,    # 降维后的特征维度
    min_dist=0.0,       # 最小间距参数
    metric='euclidean'# 距离度量标准
)

# 步骤3 - 聚类模型配置
hdbscan_model = HDBSCAN(
    min_cluster_size=min_cluster_size,  # 最小聚类规模
    metric='euclidean',                 # 距离度量标准
    cluster_selection_method='eom',     # 聚类选择算法
    prediction_data=True                # 启用预测功能
)

# 步骤4 - 文本向量化增强配置
vectorizer_model = CountVectorizer(
    stop_words="english",   # 过滤英文停用词
    ngram_range=n_gram_range  # 允许的关键词组合长度
)

# 步骤5 - TF-IDF加权转换器
ctfidf_model = ClassTfidfTransformer()

# 步骤6 - (可选) KeyBERT优化配置
representation_model = {
    "KeyBERT": KeyBERTInspired(
        top_n_words=15,    # 优化后每个主题提取词数
        nr_repr_docs=12,   # 优化后每个主题代表文档数
        nr_samples=300     # 每个主题候选文档采样量
   )
}

# 整合所有组件构建BERTopic模型
topic_model = BERTopic(
    embedding_model=embedding_model,            # 步骤1:嵌入模型
    umap_model=umap_model,                      # 步骤2:降维模型  
    hdbscan_model=hdbscan_model,                # 步骤3:聚类模型
    vectorizer_model=vectorizer_model,          # 步骤4:向量化模型
    ctfidf_model=ctfidf_model,                  # 步骤5:TF-IDF转换
    representation_model=representation_model,  # 步骤6:表示优化
    n_gram_range=n_gram_range                   # 关键词长度范围
)

# 执行模型训练与转换
topics, initial_probabilities = topic_model.fit_transform(docs, embeddings)

# 构建结果DataFrame
df_results = pd.DataFrame({
    'Topic': topics,                      # 文档所属主题编号
    'Probability': initial_probabilities  # 主题归属概率
})

# 获取主题详细信息并合并结果
df_topic_info = topic_model.get_topic_info()
df_results = df_results.merge(
    df_topic_info, 
    how='left', 
    on='Topic'
)

# 处理嵌入向量格式
embedding_list = [list(val) for val in embeddings]

# 合并文档映射关系并过滤无效主题
df_results = df_docs_mapper.merge(
    df_results, 
    how='left', 
    left_on='doc_id', 
    right_index=True
)
df_bertopic_results = df_results[
    df_results.Topic != -1.0
].dropna(how='any').reset_index(drop=True)

# 将KeyBERT列转换为元组格式(确保后续分组操作稳定性)
df_results['KeyBERT'] = df_results['KeyBERT'].apply(tuple)

# 统计每个主题下不同 KeyBERT 特征词组合的出现频次
# 按['Topic', 'KeyBERT']双列分组,计算每组记录数(size()),重置索引并将计数列命名为'counts'
topic_keybert_counts = df_results.groupby(['Topic', 'KeyBERT']).size().reset_index(name='counts')
topic_keybert_counts

使用 KeyBERT 输出的部分结果如图所示,这个表统计了每个主题下不同 KeyBERT 特征词组合的出现频次。

img

接着,采用 LDA 算法对文档块进行主题识别。虽然在主分析中采用了人工标注方法确定主题,但 LDA 提供了一种自动化主题识别的补充方案,可用于验证主题结构,并探索潜在的新主题。

  • LDA主题结果 lda_topic_results 用于存储每组文档的 LDA 主题建模输出结果。
  • 待提取主题数 num_topics_to_extract 设定 LDA 需要识别的主题数量。
# 初始化存储LDA建模结果的列表
lda_topic_results = []
# 设置LDA模型需要提取的主题数量
num_topics_to_extract = 5

# 准备LDA建模所需的文档数据与词典
# 从BERTopic结果中提取KeyBERT关键词作为文档内容
document_texts = df_bertopic_results.KeyBERT.to_list()
# 创建词典(词汇到ID的映射)
doc_dictionary = corpora.Dictionary(document_texts)
# 将文档转换为词袋表示(单词ID+词频)
bow_corpus = [doc_dictionary.doc2bow(doc) for doc in document_texts]

# 训练LDA模型(指定主题数)
# 参数说明:
# - corpus: 词袋语料库
# - id2word: 词典映射
# - num_topics: 主题数量
# - passes: 训练迭代次数(提高模型稳定性)
lda_model = LdaModel(
    corpus=bow_corpus,
    id2word=doc_dictionary,
    num_topics=num_topics_to_extract,
    passes=10
)

# 提取每个文档的主题分布并存储结果
document_topic_info = []
for idx, doc_bow in enumerate(bow_corpus):
    # 获取文档的主题概率分布(包含所有主题)
    doc_topics = lda_model.get_document_topics(doc_bow, minimum_probability=0.0)
    # 按概率降序排序
    doc_topics = sorted(doc_topics, key=lambda x: x[1], reverse=True)
    # 提取主导主题
    dominant_topic = doc_topics[0][0]
    
    # 收集主题信息:
    # - 主导主题编号
    # - 主题归属概率
    # - 主题特征词(按词频排序)
    document_topic_info.append({
        'lda_topic': dominant_topic,
        'lda_probability': doc_topics[0][1],
        'lda_words': ' '.join([x[0] for x in sorted(lda_model.show_topic(dominant_topic), reverse=False)])
    })

# 合并所有文档的主题信息
lda_topic_results.extend(document_topic_info)

# 输出建模结果摘要
print(f'The LDA model was trained with {num_topics_to_extract} topics.')
lda_topic_results = pd.DataFrame(document_topic_info)

# 输出总结
print(f'The LDA model was trained with {num_topics_to_extract} topics. The number of documents processed is {len(lda_topic_results)}.')

# 将BERTopic结果和LDA主题结果合并到单个DataFrame中
merged_results = df_bertopic_results.merge(lda_topic_results, how='left', left_index=True, right_index=True)

# 合并LDA主题词和数据
merged_results[['lda_topic','lda_words']].drop_duplicates()

此时,部分的输出结果如图所示。接着,作者为上述无监督学习得到的主题添加了可解释的标签名称。

img

# 为上述无监督学习得到的主题添加可解释的标签名称
# - 'lda_topic': LDA模型自动生成的主题编号(通常为数字)
# - 'topic': 人工或 ChatGPT 标注的主题名称(提供的是作者或者ChatGPT标注的语义化描述,这里因为用的是生物学的文本数据做演示,因此主题都是生物学相关的)
topiclists = [
    {'lda_topic': 2, 'topic': 'Cancer Gene Evolution'},           
    {'lda_topic': 1, 'topic': 'Genome Sequencing Advances'},      
    {'lda_topic': 4, 'topic': 'Transcriptional Genomic Insights'},
    {'lda_topic': 0, 'topic': 'Gene Expression Analysis'},        
    {'lda_topic': 3, 'topic': 'Genetic Association Traits'}       
]

# 将映射列表转换为DataFrame以便合并
# 生成两列结构:lda_topic(int) | topic(str)
dftopiclists = pd.DataFrame(topiclists)

# 执行左连接合并操作(保留原始数据所有记录)
merged_results = merged_results.merge(dftopiclists, how='left', on='lda_topic')
4.2.3 情感分析和量化分析

在 LDA 主题词分析后,作者进一步进行情感分类,再按照主题进行情感分析。 情感分析为每个文本块分配预定义的标签,分类是积极的、中性的或消极的。注意:在该代码中,情感分类是通过随机分配完成的,作者直接展示如何配置 LLM 的环境。在原始数据的分析中,作者使用的是 Llama 3.1 的模型来进行情感分类,采用的 Prompt 如下所示,括号内为对应的中文翻译。

img

prompt_fundamentals = """

Read the following excerpt from the news article about economic fundamentals (e.g., earnings, growth prospects, labor markets, inflation, etc.) and assess the potential impact of the news on the U.S. stock markets. (阅读下面这篇关于经济基本面(如收入、增长前景、劳动力市场、通货膨胀等)的新闻文章,并评估这些新闻对美国股市的潜在影响。)

Assign a sentiment score of -1 for negative, 0 for neutral, or 1 for positive. A positive sentiment means earnings or their outlook are upbeat, GDP growth prospects are bright, labour market remains or should remain tight with low unemployment, inflation tends to be higher rather than lower. A negative sentiment is the opposite of this, where earnings disappoint, growth outlook is weak, labour market slack increases with higher unemployment, and inflation is lower. Neutral sentiment is when the fundamental developments have no clear implications for the stock market one way or the other.(给文章情绪赋分,-1表示消极,0表示中立,1表示积极。积极的情绪意味着收入或他们的前景乐观,GDP增长前景光明,劳动力市场仍然或应该保持低失业率,通货膨胀倾向于更高而不是更低。与此相反的是负面情绪,即收益令人失望,增长前景疲弱,劳动力市场疲软加剧,失业率上升,通胀下降。中性情绪是指基本面发展对股市没有明显的影响。)

Return the result only in JSON format as: {"sentiment_score": score}. Do not provide any further explanation or output. (只返回JSON格式的结果:{"sentiment_score": score}。不要提供任何进一步的解释或输出。)

"""

prompt_monetarypolicy = """

Read the following excerpt from the news article about monetary policy and assess its impact on the U.S. stock markets.(阅读以下关于货币政策的新闻文章节选,并评估其对美国股市的影响。)

Assign a sentiment score of -1 for negative, 0 for neutral, or 1 for positive. A positive sentiment means that the central banks are keeping or expected to keep policy stance accommodative, by cutting interest rate or by delaying increasing interest rate or by maintaining the interest rate at a low level. A positive sentiment may also entail an expansion of the central bank balance sheets (quantitative easing), or a delayed contraction (quantitative tightening). A negative sentiment is the opposite, where central banks are tightening their monetary policy stance, through higher interest rates and smaller balance sheet sizes. A neutral stance is where monetary policy developments do not have clear impact on the US stock market.
(给文章情绪赋分,-1表示消极,0表示中立,1表示积极。积极情绪是指央行通过下调利率、推迟上调利率、维持低利率等方式,保持或预期保持宽松的政策立场。积极的情绪也可能导致央行资产负债表的扩张(量化宽松),或延迟收缩(量化紧缩)。负面情绪则相反,央行正通过加息收紧货币政策立场。中性立场是指货币政策的发展对美国股市没有明显影响。)

Return the result only in JSON format as: {"sentiment_score": score}. Do not provide any further explanation or output.(只返回JSON格式的结果:{"sentiment_score": score}。不要提供任何进一步的解释或输出。)

"""

prompt_marketsentiment = """

Read the following excerpt from the news article about financial market developments and assess their impact on the U.S. stock markets.(阅读以下有关金融市场情绪的新闻文章,并评估其对美国股市的影响。)

Assign a sentiment score of -1 for negative, 0 for neutral, or 1 for positive. A positive sentiment means that financial market conditions and developments imply stronger US stock market. A negative sentiment is the opposite, where financial market conditions and developments imply weaker US stock market. A neutral stance is where there are unclear implications for the US stock market.(给文章情绪赋分,-1表示消极,0表示中立,1表示积极。乐观情绪意味着金融市场状况较好,美国股市走强。负面情绪则相反,金融市场状况不佳,美国股市走弱。中性立场是指其对美国股市的影响不明朗。)

Return the result only in JSON format as: {"sentiment_score": score}. Do not provide any further explanation or output.(只返回JSON格式的结果:{"sentiment_score": score}。不要提供任何进一步的解释或输出。)

"""
"""
以下代码是作者使用随机分配的方式匹配文本和情绪,并没有具体配置 LLM 运行环境。
"""

# 查看合并结果的第一行(不展示代表文档列)
merged_results.head(1).drop(columns=['Representative_Docs'])

# 将原始文档列表转为DataFrame(列名设为'doc')
dfdocs = pd.DataFrame(docs, columns=['doc'])

# 合并主题分析结果与原始文档内容:
# 1. 从merged_results选取关键列:text_id, doc_id, Topic, lda_topic, topic
# 2. 通过doc_id与dfdocs的索引匹配(left_on='doc_id', right_index=True)
dfdocs = merged_results[['text_id','doc_id','Topic','lda_topic','topic']].merge(
    dfdocs, 
    left_on='doc_id', 
    right_index=True
)

# 添加年份信息:
# 通过text_id匹配dfarxiv中的year列(right_index=True表示用dfarxiv的索引匹配)
dfdocs = dfdocs.merge(
    dfarxiv['year'], 
    left_on='text_id', 
    right_index=True
)

# 给文本随机分配情绪(注意,这里是原本使用 LLM 为新闻文本情绪赋分的代码,作者并未展示如何配置 LLM 环境)
sentiments = ['positive','negative','neutral']
dfdocs['sentiment'] = np.random.choice(sentiments, len(dfdocs))
dfdocs.head()

在定量分析过程中,使用报纸数据分析获得的总体情绪得分被证明与美国的 GDP 表现一致,验证的代码如下所示。

# 读取美国GDP文件,并设置日期
dfgdp = pd.read_csv('https://github.com/bis-med-it/LLM_Primer_for_Economists/blob/main/GDPA.csv?raw=true')
dfgdp['DATE'] = pd.to_datetime(dfgdp['DATE'], format='%Y-%m-%d')

# 选取年份和情感分析结果两列
dfsentiment = dfdocs[['year','sentiment']]
# 将年份转为标准日期格式(每年1月1日)
dfsentiment['DATE'] = pd.to_datetime(dfsentiment['year'], format='%Y')
# 按日期和情感标签分组统计
dfsentiment = dfsentiment.groupby(['DATE','sentiment']).size().reset_index()
# 数据透视:行为日期,列为情感类型,值为计数(缺失值填0并转为整数)
dfsentiment = dfsentiment.pivot(index='DATE', columns='sentiment', values=0).fillna(0).astype(int)

# 合并GDP和情绪文件
dfsentgdp = dfsentiment.merge(dfgdp, left_index=True, right_on='DATE')
dfsentgdp = dfsentgdp.set_index('DATE')

# 在这里,会得到一个包括日期、负面情绪词数、中性情绪词数、积极情绪词数和美国GDP四列的表格,如下图所示。

img

为了观察情绪与美国 GDP 表现的相关性,作者使用 Python 进行了画图。具体的分析内容和分析步骤,可以根据研究者的实际需要决定。

# 导入绘图库
import matplotlib.pyplot as plt

# 设置柱状图宽度
bar_width = 100# 加宽柱体提升可视性

# 创建画布和主坐标轴
fig, ax1 = plt.subplots(figsize=(12, 8)) 

# 绘制堆叠柱状图(情感分析结果):
# 1. 底层红色负向情感柱
ax1.bar(dfsentgdp.index, dfsentgdp['negative'], 
        label='Negative', color='red', 
        width=bar_width, align='center')
# 2. 中层蓝色中性情感柱(叠加在负向柱上方)
ax1.bar(dfsentgdp.index, dfsentgdp['neutral'], 
        bottom=dfsentgdp['negative'], 
        label='Neutral', color='blue',
        width=bar_width, align='center')
# 3. 顶层绿色正向情感柱(叠加在前两者上方)
ax1.bar(dfsentgdp.index, dfsentgdp['positive'],
        bottom=dfsentgdp['negative'] + dfsentgdp['neutral'],
        label='Positive', color='green',
        width=bar_width, align='center')

# 设置主坐标轴标签
ax1.set_xlabel('Year')  # X轴标签
ax1.set_ylabel('Sentiment Count')  # 左侧Y轴标签
ax1.tick_params(axis='y')  # 配置Y轴刻度
ax1.set_title('Sentiment and GDPA Over Time')  # 图表标题

# 创建次坐标轴绘制GDPA折线
ax2 = ax1.twinx()  # 共享X轴的次坐标轴
ax2.plot(dfsentgdp.index, dfsentgdp['GDPA'], 
         label='GDPA', color='black', linewidth=2)  # 黑色粗线
ax2.set_ylabel('GDPA')  # 右侧Y轴标签
ax2.tick_params(axis='y', labelcolor='black')  # 设置刻度标签为黑色

# 合并图例并调整位置
fig.legend(loc='upper left', bbox_to_anchor=(0.1, 0.9))

# 添加网格线并自动调整布局
plt.grid(axis='y', linestyle='--', linewidth=0.5)  # 横向虚线网格
plt.tight_layout()  # 防止标签重叠
plt.show()  # 显示图表

最后,画出的图片如下所示。注意,这里使用的不是新闻数据,使用的是生物期刊的范例数据,因此 GDP 和情绪的相关性不大,但是使用报纸数据则可以验证其相关性。该图是作者在公开的代码中展示的图,不是论文中体现的图片。

img

论文中的图如下所示,作者使用原始的报纸数据,分析出来的结果如论文 Graph 3 所示。作者发现,三类情绪赋分求和后,情绪积极性与股市的表现总体是吻合的,也就是说,基于大语言模型对新闻进行情感分析的方法准确性较高。考察三类情绪得分的相对重要性时发现,市场情绪、基本面与股票回报率的联动性最强,相关系数分别达到 0.64 和 0.52。货币政策情绪与股市表现的相关性较弱,仅为 0.30,作者认为可能与不同政策间相互作用有关。

img

5. 总结

本文提出了一套使用大语言模型进行科研工作流程,为充分利用大语言模型做研究提供了有普适性的原则启示与实践指南。在这之中,最关键的点是如何进行合理的资源规划。 LLM 功能强大,但其计算和操作成本高昂。例如,高维嵌入运算或超大规模 LLM 调用等环节,在实际操作中可能仅能执行有限次数,因此,科研人员需要做好研究设计,既要降低冗余计算负荷,又能通过资源聚焦,提升模型效能。

比较具有推广性的做法是,采用模块化的分步流程,使研究者在研究过程中校验和分析中间产出,确保 LLM 处理流程始终按预期生成合理结果。 最后,鉴于 LLM 算法是依靠概率的特性,适当重复操作流程有助于保证结论稳健性。

研究者也需要注意数据的隐私性保护。研究者须确保数据使用符合企业政策、数据许可协议及其他数据保护法规的合规要求。采用本地部署的 LLM 可在一定程度上降低数据使用的法律风险,但无法完全规避法律风险,部分法规的适用性与部署环境无关。唯有在充分认知并有效管控模型局限性的前提下,研究者才能真正释放 LLM 的巨大潜能。

普通人如何抓住AI大模型的风口?

领取方式在文末

为什么要学习大模型?

目前AI大模型的技术岗位与能力培养随着人工智能技术的迅速发展和应用 , 大模型作为其中的重要组成部分 , 正逐渐成为推动人工智能发展的重要引擎 。大模型以其强大的数据处理和模式识别能力, 广泛应用于自然语言处理 、计算机视觉 、 智能推荐等领域 ,为各行各业带来了革命性的改变和机遇 。

目前,开源人工智能大模型已应用于医疗、政务、法律、汽车、娱乐、金融、互联网、教育、制造业、企业服务等多个场景,其中,应用于金融、企业服务、制造业和法律领域的大模型在本次调研中占比超过 30%。
在这里插入图片描述

随着AI大模型技术的迅速发展,相关岗位的需求也日益增加。大模型产业链催生了一批高薪新职业:

在这里插入图片描述

人工智能大潮已来,不加入就可能被淘汰。如果你是技术人,尤其是互联网从业者,现在就开始学习AI大模型技术,真的是给你的人生一个重要建议!

最后

如果你真的想学习大模型,请不要去网上找那些零零碎碎的教程,真的很难学懂!你可以根据我这个学习路线和系统资料,制定一套学习计划,只要你肯花时间沉下心去学习,它们一定能帮到你!

大模型全套学习资料领取

这里我整理了一份AI大模型入门到进阶全套学习包,包含学习路线+实战案例+视频+书籍PDF+面试题+DeepSeek部署包和技巧,需要的小伙伴文在下方免费领取哦,真诚无偿分享!!!
vx扫描下方二维码即可
加上后会一个个给大家发

在这里插入图片描述

部分资料展示

一、 AI大模型学习路线图

整个学习分为7个阶段
在这里插入图片描述
在这里插入图片描述

二、AI大模型实战案例

涵盖AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,皆可用。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

三、视频和书籍PDF合集

从入门到进阶这里都有,跟着老师学习事半功倍。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

四、LLM面试题

在这里插入图片描述
在这里插入图片描述

五、AI产品经理面试题

在这里插入图片描述

六、deepseek部署包+技巧大全

在这里插入图片描述

😝朋友们如果有需要的话,可以V扫描下方二维码联系领取~
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值