KeyBERT Taipy Kenneth Leung 数据科学 机器学习 由Marylou Fortier拍摄的照片(Unsplash) 随着来自社交媒体、客户评论和在线平台等来源的文本数据数量呈指数级增长,我们必须能够理解这些非结构化数据。
关键词提取和分析是强大的自然语言处理(NLP)技术,使我们能够做到这一点。
关键词提取涉及自动识别和提取给定文本中最相关的单词,而关键词分析涉及分析关键词以获得底层模式的见解。
在这个逐步指南中,我们将使用KeyBERT和Taipy这两个强大的工具,在arXiv摘要上构建关键词提取和分析管道以及Web应用程序。
目录
(1) 背景
(2) 工具概述
(3) 逐步指南
(4) 总结
这是本文的GitHub存储库。
https://github.com/kennethleungty/Keyword-Analysis-with-KeyBERT-and-Taipy
鉴于人工智能(AI)和机器学习研究的快速进展,每天发布的众多论文的跟踪可能具有挑战性。
关于这类研究,arXiv无疑是信息的主要来源之一。arXiv(发音为“存档”)是一个开放获取的存档,托管着涵盖计算机科学、数学等各种学科的大量科学论文。
arXiv的一个关键特点是它为上传到其平台的每篇论文提供摘要。这些摘要是理想的数据来源,因为它们简洁、富含技术词汇,并包含领域特定的术语。
因此,我们将利用最新的arXiv摘要批次作为本项目中要处理的文本数据。
目标是创建一个Web应用程序(包括前端界面和后端管道),用户可以根据特定的输入值查看arXiv摘要的关键词和关键短语。
在本项目中,我们将使用三个主要工具:
arXiv API Python包装器
KeyBERT
Taipy
arXiv网站提供了公共API访问,以最大程度地提高其开放性和互操作性。例如,为了在我们的Python工作流程中检索文本摘要,我们可以使用arXiv API的Python包装器。
arXiv API的Python包装器提供了一组函数,用于根据特定条件(如作者、关键词、类别等)搜索数据库中匹配的论文。
它还允许用户检索有关每篇论文的详细元数据,如标题、摘要、作者和出版日期。
KeyBERT(从“关键词”和“BERT”一词中派生)是一个Python库,提供了一个易于使用的界面,用于使用BERT嵌入和余弦相似性提取文档中最具代表性的单词。
KeyBERT的最大优势在于其灵活性。它允许用户轻松修改底层设置(例如参数、嵌入、标记化)以进行实验和微调获得的关键词。
在本项目中,我们将调整以下一组参数:
这两种多样化算法(最大总距离和最大边际相关性)共享相同的基本思想:获取与查询高度相关但内容各异以避免彼此重复的结果。
Taipy是一个开源的Python应用程序构建工具,可让开发人员和数据科学家将数据和机器学习算法快速转化为完整的Web应用程序。
尽管设计为低代码库,但Taipy还提供了高度的用户自定义。因此,它非常适合各种用途,从简单的仪表板到生产就绪的工业应用。
Taipy有两个关键组件:Taipy GUI和Taipy Core。
虽然我们可以独立使用Taipy GUI或Taipy Core,但结合两者可以有效地构建强大的应用程序。
如前文所述,在“背景”部分,我们将构建一个Web应用程序,用于提取和分析所选arXiv摘要的关键词。
让我们开始创建上述管道和Python Web应用程序的步骤。
我们从使用以下相应版本的Python库进行pip安装开始:
由于将使用大量参数,将它们保存在单独的配置文件中是理想的。以下的YAML文件config.yml包含了初始的配置参数值。
QUERY: 'artificial intelligence' # Category of arXiv abstracts
MAX_ABSTRACTS: 30 # Number of abstracts to retrieve from database
NGRAM_MIN: 1 # Min N-gram length
NGRAM_MAX: 1 # Max N-gram length
TOP_N: 3 # Number of keywords to return
DIVERSITY_ALGO: 'mmr' # or 'maxsum'
DIVERSITY: 0.2 # For MMR (higher value = more dissimilar keywords)
NR_CANDIDATES: 20 # For MaxSum (number of candidates)
配置文件设置完成后,我们可以使用以下代码轻松将这些参数值导入到我们的其他Python脚本中:
open ( 'config.yml' ) as f :
cfg = yaml.safe_load(f)
在这一步,我们将创建一系列Python函数,它们构成了管道的重要组成部分。我们创建一个名为functions.py的新Python文件来存储这些函数。
首先,在functions.py中添加一个函数,用于使用arXiv API Python包从arXiv数据库中检索文本摘要。
# Function 1 - Retrieve abstracts from arXiv database
def extract_arxiv(query: str):
search = arxiv.Search(
query=query,
max_results=cfg['MAX_ABSTRACTS'], # No. of abstracts to retrieve (from config)
sort_by=arxiv.SortCriterion.SubmittedDate,
sort_order=arxiv.SortOrder.Descending # Sort by latest date
)
# Returns arXiv object
return search
接下来,编写一个函数,将摘要文本和相应的元数据存储在一个pandas DataFrame中。
# Function 2 - Save abstract text and metadata in pd.DataFrame
def save_in_dataframe(search):
df = pd.DataFrame([{'uid': result.entry_id.split('.')[-1],
'title': result.title,
'date_published': result.published,
'abstract': result.summary} for result in search.results()])
return df
对于数据处理步骤,我们有以下函数,用于将摘要的发布日期解析为适当的格式,同时创建新的空列来存储关键词。
# Function 3 - Preprocess data
def preprocess_data(df: pd.DataFrame):
df['date_published'] = pd.to_datetime(df['date_published'])
# Create empty column to store keyword and similarity scores
df['keywords_and_scores'] = ''
# Create empty column to store keyword texts only
df['keywords'] = ''
return df
接下来,我们创建一个函数,用于运行KeyBERT库中的KeyBert类。KeyBERT类是使用BERT进行关键词提取的最简单方法,是我们入门的最简单方式。
有许多不同的方法可以生成BERT嵌入(例如Flair、Huggingface Transformers和spaCy)。在这种情况下,我们将使用KeyBERT创建者推荐的sentence-transformers。
特别是,我们将使用defaultall-MiniLM-L6-v2模型,因为它在速度和质量之间提供了良好的平衡。
以下函数迭代地从每个摘要中提取关键词,并将它们保存在前面步骤中创建的新DataFrame列中。
# Function 4 - Run KeyBERT
def run_keybert(df: pd.DataFrame, ngram_min: int, ngram_max: int, diversity_algo: str, top_n: int, diversity: float, nr_candidates: int):
kw_model = KeyBERT(model='all-MiniLM-L6-v2')
use_mmr = diversity_algo.lower() == 'mmr'
use_maxsum = diversity_algo.lower() == 'maxsum'
for i, row in df.iterrows():
abstract_text = row['abstract']
kw_output = kw_model.extract_keywords(abstract_text,
keyphrase_ngram_range=(ngram_min, ngram_max),
stop_words='english',
use_mmr=use_mmr,
use_maxsum=use_maxsum,
top_n=top_n,
diversity=diversity,
nr_candidates=nr_candidates)
df.at[i, 'keywords_and_scores'] = kw_output
df.at[i, 'keywords'] = [pair[0] for pair in kw_output]
return df
最后,我们创建一个函数,生成关键词的值计数,以便稍后绘制关键词频率的图表。
# Function 5 - Generate keyword frequency table (aka value counts)
def get_keyword_value_counts(df):
keywords_count = pd.Series(df['keywords'].explode()).value_counts().reset_index()
keywords_count.columns = ['keyword', 'count']
return keywords_count
为了协调和链接后端管道流程,我们将利用Taipy核心的功能。
Taipy核心提供了一个开源框架,可以轻松高效地创建、管理和执行数据管道。它有四个基本概念:数据节点、任务、管道和场景。
为了设置后端,我们将使用配置对象(来自Config类)来模拟和定义上述概念的特征和期望行为。
与大多数数据科学项目一样,我们从处理数据开始。在Taipy核心中,我们使用数据节点来定义我们将使用的数据。
我们可以将数据节点视为Taipy对数据变量的表示。但是,数据节点不直接存储数据,而是包含一组指令,指导如何检索所需的数据。
数据节点可以读取和写入各种数据类型,例如Python对象(例如str、int、list、dict、DataFrame等)、Pickle文件、CSV文件、SQL数据库等。
使用Config.configure_data_node()函数,我们根据步骤2中配置文件中的值定义了关键词参数的数据节点。
from taipy import Config
with open('config.yml') as f:
cfg = yaml.safe_load(f)
data_query_cfg = Config.configure_data_node(id='query',
default_data=cfg['QUERY'])
data_ngram_min_cfg = Config.configure_data_node(id='ngram_min',
default_data=cfg['NGRAM_MIN'])
data_ngram_max_cfg = Config.configure_data_node(id='ngram_max',
default_data=cfg['NGRAM_MAX'])
data_diversity_algo_cfg = Config.configure_data_node(id='diversity_algo',
default_data=cfg['DIVERSITY_ALGO'])
data_top_n_cfg = Config.configure_data_node(id='top_n',
default_data=cfg['TOP_N'])
data_diversity_cfg = Config.configure_data_node(id='diversity',
default_data=cfg['DIVERSITY'])
data_nr_candidates_cfg = Config.configure_data_node(id='nr_candidates',
default_data=cfg['NR_CANDIDATES'])
id参数设置数据节点的名称,而default_data参数定义了默认值。
接下来,我们包括沿着管道的五组数据的配置对象,如下所示:
沿着管道的五个数据节点的示例 | 图片 以下代码定义了五个配置对象:
data_arxiv_search_cfg = Config.configure_data_node(id='data_arxiv_search')
data_raw_df_cfg = Config.configure_data_node(id='data_raw_df')
data_processed_df_cfg = Config.configure_data_node(id='data_processed_df')
data_keywords_df_cfg = Config.configure_data_node(id='data_keywords_df')
data_keywords_count_cfg = Config.configure_data_node(id='data_keywords_count')
在Taipy中,任务可以被视为Python函数。我们可以使用Config.configure_task()来定义任务的配置对象。
我们需要设置五个任务配置对象,分别对应步骤3中构建的五个函数。
from taipy import Config
task_arxiv_extraction_cfg = Config.configure_task(id="task_arxiv_extraction",
function=extract_arxiv,
input=data_query_cfg,
output=data_arxiv_search_cfg,
skippable=True)
task_save_in_df_cfg = Config.configure_task(id="task_save_in_df",
function=save_in_dataframe,
input=data_arxiv_search_cfg,
output=data_raw_df_cfg,
skippable=True)
task_process_data_cfg = Config.configure_task(id='task_process_data',
function=preprocess_data,
input=data_raw_df_cfg,
output=data_processed_df_cfg,
skippable=True)
task_extract_keywords_cfg = Config.configure_task(id='task_extract_keywords',
function=run_keybert,
input=[data_processed_df_cfg,
data_ngram_min_cfg,
data_ngram_max_cfg,
data_diversity_algo_cfg,
data_top_n_cfg,
data_diversity_cfg,
data_nr_candidates_cfg],
output=data_keywords_df_cfg)
task_get_kw_count_cfg = Config.configure_task(id='task_count_keywords',
function=get_keyword_value_counts,
input=data_keywords_df_cfg,
output=data_keywords_count_cfg)
输入和输出参数分别是输入和输出数据节点。
例如,在task_process_data_cfg中,输入是包含arXiv搜索结果的原始pandas DataFrame的数据节点,而输出是存储处理过的数据的DataFrame的数据节点。
skippable参数,当设置为True时,表示如果对输入没有进行更改,则可以跳过任务。
以下是我们迄今为止定义的数据节点和任务的流程图:
管道是由Taipy自动执行的任务序列。它是一个配置对象,包括一系列任务配置对象。
在这种情况下,我们将五个任务分配到两个管道中(一个用于数据准备,另一个用于关键词分析),如下所示:
我们使用以下代码定义了我们的两个管道配置:
pipeline_data_prep_cfg = Config.configure_pipeline(id='pipeline_data_prep',
task_configs=[task_arxiv_extraction_cfg,
task_save_in_df_cfg,
task_process_data_cfg,
])
pipeline_keyword_analysis_cfg = Config.configure_pipeline(id='pipeline_keyword_analysis',
task_configs=[task_extract_keywords_cfg,
task_get_kw_count_cfg
])
与所有配置对象一样,我们使用id参数为这些管道配置分配了名称。
在这个项目中,我们的目标是创建一个应用程序,根据输入参数的更改(例如N-gram长度)反映关键词集(以及相应的分析)的更新。
为了实现这一点,我们利用了场景的强大概念。Taipy场景提供了运行管道的框架,根据用户修改的输入参数或数据,可以在不同条件下运行,还允许我们保存不同输入的输出,以便在同一个应用程序界面中进行比较。
场景还允许我们保存不同输入的输出,以便在同一应用程序界面中进行轻松比较。
由于我们预计要直接按顺序运行管道,所以我们可以将两个管道配置都放入一个场景配置对象中。
scenario_cfg = Config.configure_scenario(id="scenario",
pipeline_configs=[pipeline_data_prep_cfg,
pipeline_keyword_analysis_cfg
])
现在让我们转向并探索应用程序的前端方面。Taipy GUI提供了Python类,使创建具有文本和图形元素的强大Web应用程序界面变得容易。
页面是用户界面的基础,它们包含文本、图像或控件,通过视觉元素显示应用程序中的信息。
需要创建两个页面:(i) 关键词分析仪表板页面和(ii) 数据查看器页面,用于显示关键词DataFrame。
Taipy GUI可以被视为增强版的Markdown,这意味着我们可以使用Markdown语法构建前端界面。
我们从显示提取的arXiv摘要数据的简单前端页面开始。该页面在一个名为data_viewer_md.py的Python脚本中设置,并将Markdown存储在一个名为data_page的变量中。
data_page = """
# Extracted arXiv Abstracts
<|{df}|table|>
"""
在Markdown中创建Taipy构造的基本语法是使用通用格式的文本片段<|…|…|>。
在上面的Markdown中,我们将DataFrame对象df传递给表格元素,表格元素表示表格元素。只需这几行代码,我们就可以获得如下输出:
现在我们转向应用程序的主要仪表板页面,我们可以更改参数并可视化获得的关键词。可视元素将包含在一个名为analysis_md.py的Python脚本中。
此页面有许多组件,因此让我们一步一步来。首先,我们在加载应用程序时实例化参数值。
# Initiate parameter values from config file
with open('config.yml') as f:
cfg = yaml.safe_load(f)
query = cfg['QUERY']
ngram_min = cfg['NGRAM_MIN']
ngram_max = cfg['NGRAM_MAX']
diversity_algo = cfg['DIVERSITY_ALGO']
diversity_algo_options = ['mmr', 'maxsum']
diversity = cfg['DIVERSITY']
top_n = cfg['TOP_N']
nr_candidates = cfg['NR_CANDIDATES']
接下来,我们定义页面的输入部分,用户可以在其中更改参数和场景。这部分将保存在一个名为input_page的变量中,最终将如下所示:
关键词分析页面的输入部分 | 作者提供的图片 在Markdown中,我们创建了一个七列布局,以便可以整齐地组织输入字段(例如文本输入、数字输入、下拉菜单选择器)和按钮。
input_page = """
# Keyword Extraction and Analysis with KeyBERT and Taipy
<br/>
<|layout|columns=1 1 1 1 1 1 1|
<|{query}|input|label=Query Topic|>
<|{ngram_min}|number|label=Min N-gram|>
<|{ngram_max}|number|label=Max N-gram|>
<|{top_n}|number|label=Top n results|>
<|{diversity}|number|label=Diversity (for MMR)|>
<|{nr_candidates}|number|label=No. of Candidates (for MaxSum)|>
<|{diversity_algo}|selector|lov={diversity_algo_options}|dropdown|label=Diversity Algorithm|>
<|Update Analysis|button|on_action=submit_scenario|>
|>
<br/>
<br/>
<|{selected_scenario}|selector|lov={scenario_selector}|dropdown|label=Scenario|on_change=synchronize_gui_core|value_by_id|>
<|Save Scenario|button|on_action=create_scenario|>
<br/>
"""
我们将在上面的元素的on_change和on_action参数中解释回调函数,因此现在无需担心它们。
之后,我们定义输出部分,其中将根据输入参数显示关键词的频率表和图表。
除了在output_page变量中指定输出部分的Markdown外,我们还将定义图表属性。
# Define keyword bar chart properties in dict
chart_properties = {"type":"bar",
"y":"keyword",
"x":"count",
"orientation": "h",
"layout": {
"xaxis": {"title": "Frequency Count"},
"yaxis": {"title": None},
"showlegend": False, # Hide the legend
"title": "Keyword Frequency Bar Plot",
"margin": {'pad': 0}
}
}
# Output section of dashboard (two column layout)
output_page = """
<|layout|columns=1 1|gap=10px|
<|{df_keywords_count}|table|width=30|page_size=10|height=20|>
<|{df_keywords_count}|chart|properties={chart_properties}|height=20|>
|>
"""
# Combine layout segments
analysis_page = input_page + output_page
最后,我们在上面的最后一行中将输入和输出部分合并成一个名为analysis_page的单一变量。
在我们的前端界面完成之前,还有最后一部分。现在我们已经准备好了两个页面,我们将在主登陆页面上显示它们。
主页面在main.py中定义,这是在执行应用程序时运行的脚本。目标是在主页面上创建一个功能性的菜单栏,供用户在页面之间切换。
from taipy.gui import Gui, Icon, navigate
# Define menu options
menu = [("Analysis", Icon('assets/histogram_menu.svg', 'Analysis')),
('Data', Icon('assets/Datanode.svg', 'Data'))]
# Set wrapper display on landing page
page_markdown = """
<|toggle|theme|>
<|menu|label=Menu|lov={menu}|on_action=menu_function|>
"""
# Set pages for users to access
pages = {"/":page_markdown,
"Analysis":analysis_page,
"Data":data_page}
# Define callback function to execute menu button actions
def menu_function(state, var_name: str, fct: str, var_value: list):
# Change the value of the state.page variable in order to render the correct page
navigate(state, var_value["args"][0])
从上面的代码中,我们可以看到Taipy的状态功能正在运行,页面是根据会话状态中选择的页面呈现的。
此时,我们的前端界面和后端管道已经成功设置。但是,我们尚未将它们连接在一起。
更具体地说,我们需要创建场景组件,以便在管道中处理输入参数的变化,并将输出反映在仪表板中。
场景的附加好处是,每组输入输出都可以保存,以便用户可以回顾以前的配置。
我们将定义四个函数来设置场景组件,这些函数将存储在analysis_md.py脚本中:
此函数根据会话状态中所选场景的输入参数更新关键词DataFrame、频率计数表和相应的柱状图。
# Scenario Function 1 - Update dataframes based on selected scenario
def update_chart(state):
# Select the right scenario and pipeline
scenario = tp.get(state.selected_scenario)
# Update the chart based on this pipeline
state.df = scenario.pipeline_keyword_analysis.data_keywords_df.read()
state.df_keywords_count = scenario.pipeline_keyword_analysis.data_keywords_count.read()
此函数将用户修改的更新后的输入参数注册为一个场景,并通过管道传递这些值。
# Scenario Function 2 - Update data nodes and rerun pipelines
def submit_scenario(state):
print("Submitting scenario...")
notify(state, 'info', 'Submitting scenario...')
# Get the selected scenario: in this current step a single scenario is created then modified here.
scenario = tp.get(state.selected_scenario)
# Change the default parameters by writing in the datanodes
scenario.query.write(str(state.query))
scenario.ngram_max.write(int(state.ngram_max))
scenario.diversity_algo.write(str(state.diversity_algo))
scenario.diversity.write(float(state.diversity))
scenario.top_n.write(int(state.top_n))
scenario.nr_candidates.write(int(state.nr_candidates))
# Execute the pipelines/code
tp.submit(scenario)
notify(state, 'success', 'Execution finished!')
# Update the chart when we change the scenario
update_chart(state)
此函数保存已执行的场景,以便可以轻松重新创建并从已创建的场景下拉菜单中引用。
# Scenario Function 3 - Create (save) scenario
def create_scenario(state):
print("Creating scenario...")
scenario = tp.create_scenario(scenario_cfg, name=f"Scenario N {len(state.scenario_selector)} {state.query}")
state.scenario_selector += [(scenario.id, scenario.name)]
state.selected_scenario = scenario.id
notify(state, 'success', 'Scenario created!')
submit_scenario(state)
此函数从已保存场景的下拉菜单中选择的场景中检索输入参数,并在前端GUI中显示生成的输出。
# Scenario Function 4 - Display selected Scenario in frontend
def synchronize_gui_core(state):
scenario = tp.get(state.selected_scenario)
# Get info of selected scenario and display it on GUI
state.query = scenario.query.read()
state.ngram_max = scenario.ngram_max.read()
state.diversity_algo = scenario.diversity_algo.read()
state.diversity = scenario.diversity.read()
state.top_n = scenario.top_n.read()
state.nr_candidates = scenario.nr_candidates.read()
update_chart(state)
在最后一步,我们通过完成main.py中的代码来包装,以便在执行脚本时Taipy可以正确启动和运行。
# Run application
if __name__ == "__main__":
tp.Core().run()
# Create and execute scenario
scenario_selector = [(s.id, s.name) for s in tp.get_scenarios()]
scenario = tp.create_scenario(scenario_cfg, name="Default Scenario")
selected_scenario = scenario.id
tp.submit(scenario)
df = scenario.pipeline_keyword_analysis.data_keywords_df.read()
df_keywords_count = scenario.pipeline_keyword_analysis.data_keywords_count.read()
Gui(pages=pages).run(title="Keyword Extraction and Analysis with KeyBERT and Taipy",
dark_mode=False,
port=8020,
use_reloader=True)
上面的代码执行以下步骤:
最后,我们可以在命令行中运行python main.py,构建的应用程序将可以通过localhost:8020访问。
与文档相关的关键词提供了对其主题的简洁和全面的指示,突出了其中包含的最重要的主题、概念、思想或论点。 在这篇文章中,我们探讨了如何使用KeyBERT和Taipy提取和分析arXiv摘要的关键词。我们还了解了如何将这些功能交付为一个包含前端用户界面和后端管道的Web应用程序。
欢迎查看附带的GitHub存储库中的代码。
https://github.com/kennethleungty/Keyword-Analysis-with-KeyBERT-and-Taipy