用自然语言查询大规模时序数据
在金融等许多领域,数十亿/数万亿行的时间序列数据集并不罕见,而是常态。然而,从这些庞大的数据集中获得任何见解往往非常困难,仅仅是因为它们太难处理了。
加载速度慢,查询速度慢,保持实时性可能是个头疼的问题。
这就是kdb+被设计出来的原因:它是最快的时序数据库,也是处理大规模数据集的行业标准,这得益于其惊人的速度和实时流功能——特别是在金融领域,每一微秒都至关重要。
但是尽管kdb+如此快速,它仍然面临一个挑战:从数据中快速获取见解依然很困难。一旦查询编写完成,它们执行得非常快,但编写这些查询却需要耗费大量时间。
在这篇文章中,我将介绍如何创建一个名为query_and_plot的简单函数,我们可以用它来查询海量数据集并几乎即时得到图表和见解。
想象一下,你有一个关于数据集的问题,并立即得到一张图表:
query_and_plot(“绘制TSLA和AAPL的累计收益”)
砰!你就得到了一张图表:
这就是我们今天要做的事情。最终结果如上图所示,但将其分解成各个部分后,其实并不复杂:
如果你想跟着操作或者直接跳到完整代码,请查看这里。
1、读取和加载数据
首先,我们将使用PyKX(提供Python接口的kdb+)加载一个包含3百万分钟级时间序列记录的样本股票数据集到kdb+中:
import pykx as kx
# 加载样本CSV并将数据推送到q中的'trades'
pandas_tbl = pd.read_csv(
'https://huggingface.co/datasets/opensporks/stocks/resolve/main/stocks.csv',
parse_dates=['timestamp']
)
tbl = kx.toq(pandas_tbl) # DataFrame → q Table
tbl = tbl.rename(columns={"close": "closePrice"})
kx.q['trades'] = tbl # 分配给q全局变量
为了运行pykx,我们需要一个免费的个人许可证文件,可以从这里获取:此处。
我们可以轻松扩展到1亿至100亿行,其余逻辑完全相同。
现在我们的数据已加载到kdb+中,表名为‘trades’。让我们看看我们要处理什么:
# 获取表格描述并保存为文本变量:
table_desc = tbl.dtypes
print(table_desc)
# 获取最小和最后日期
min_date = kx.q('first trades`timestamp').pd()
max_date = kx.q('last trades`timestamp').pd()
print(f"\n最小时间戳: {min_date}")
print(f"最大时间戳: {max_date}")
我们可以看到我们有一些股票代号、一些浮点数和时间戳。默认情况下,kdb+以纳秒精度保存时间戳。
2、构建AI翻译器:自然语言→Q-SQL
当我们将kdb+的速度与AI的自然语言理解能力结合起来时,魔法就发生了。我们将创建一个翻译器,将普通英语问题转换为q-SQL查询。q-SQL是q语言上的语法糖,q语言是一种专门为处理kdb+而开发的编程语言和查询语言。大型语言模型目前还不擅长编写q。幸运的是,qSQL在某种程度上符合ANSI标准,因此如果我们告诉LLM qSQL和SQL之间的差异,我们可以生成有效的查询代码:
class TranslateResponse(BaseModel):
qsql: str
def translate_to_qsql(nl_query: str, table: str, schema: str) -> str:
system = (
SYSTEM_PROMPT
)
user = (
f"表: {table}\n"
f"模式: {schema}\n"
f"问题: {nl_query}"
)
resp = client.beta.chat.completions.parse(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system},
{"role": "user", "content": user},
],
response_format=TranslateResponse,
)
return resp.parsed.qsql
系统提示包含有关q-SQL语法和最佳实践的详细说明,确保AI生成有效且高效的kdb+查询。完整的系统提示请参阅colab笔记本。这是一个巨大的任务!我仍在寻找最优解,并对反馈持开放态度。
3、借助AI实现自动化可视化
一旦我们有了查询结果,就需要可视化它们。同样,我们将利用AI根据数据结构自动生成适当的图表:
def visualize_df_with_plotly(df, model="gpt-4o", sample_size=20, temperature=0):
"""
给定一个pandas DataFrame df和一个OpenAI兼容客户端,
推断模式和样本,要求模型生成Plotly Express代码,
然后执行并显示生成的图表。
"""
# 1. 构建模式和样本,将时间戳转换为字符串
sample_df = df.head(sample_size).copy()
for col, dtype in sample_df.dtypes.items():
if "datetime" in str(dtype).lower() or "timestamp" in str(dtype).lower():
sample_df[col] = sample_df[col].astype(str)
sample = sample_df.to_dict(orient="list")
schema_auto = {col: str(dtype) for col, dtype in df.dtypes.items()}
# 2. 准备提示
system = (
"你是Python数据可视化的专家。 "
"给定一个DataFrame模式和样本数据, "
"编写使用Plotly Express的自包含代码, "
"该代码接受df并创建一个名为fig的图形对象, "
"编写代码将df赋值给fig, "
"但不要调用fig.show()。我会处理显示。 "
"如有必要,请随意显示其他聚合和打印数字,只要生成了图形即可。 "
"只给我代码,不要其他内容。 "
"假设df是全局可用的数据框,不要重写其中的值。 "
"考虑用户在查询中想要的内容并提供它。 "
"永远不要硬编码值。 "
)
user = (
f"模式: {json.dumps(schema_auto)}\n\n"
f"样本数据: {json.dumps(sample, default=str)}"
)
# 3. 调用聊天完成API
resp = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": system},
{"role": "user", "content": user}
],
temperature=temperature,
)
# 4. 从响应中提取代码
chart_code = resp.choices[0].message.content
if chart_code.startswith("```"):
chart_code = chart_code.split("\n", 1)[1].rsplit("\n```", 1)[0]
print(chart_code)
# 5. 执行生成的代码
local_vars = {"df": df, "px": px}
exec(chart_code, {}, local_vars)
# 6. 显示图形
fig = local_vars.get("fig")
if fig:
fig.show()
else:
raise RuntimeError("生成的代码未产生fig对象。")
现在我们需要一个函数,它能将pandas df转换为图表。我考虑过使用pandas-ai,这是一个更强大且功能丰富的解决方案,代理可以从中提取更多详细的见解,但我决定自己实现一个可视化函数,以简化流程。
4、将所有内容整合在一起:query_and_plot
现在我们将所有内容整合到一个强大的函数中:
def query_and_plot(nl_query: str, table: str = "trades") -> None:
"""
给定关于kdb+表的自然语言问题,
将其翻译为q-SQL,运行它,并渲染适当的图表。
"""
# --- 翻译为q-SQL ---
# 从q中的表派生模式
q_tbl = tbl
schema = str(q_tbl.dtypes)
print(schema)
# 调用现有的翻译器(假定translate_to_qsql是全局定义的)
qsql = translate_to_qsql(nl_query, table, schema)
print("🔧 生成的q-SQL:\n", qsql)
# --- 执行查询 ---
result = kx.q.sql(qsql)
df = result.pd()
print("AI查询后的结果df")
display(df.head())
print("\n── 结果df描述 ──")
display(df.describe(include="all"))
visualize_df_with_plotly(df)
这个函数将所有内容整合在一起。
它接受自然语言查询,并使用我们上面定义的工具将其转换为图表。
我们从kdb+表中提取模式。我们将模式、自然语言查询和表传递给我们的translate_to_qsql函数,该函数返回要执行的qsql。这就是我们使用kdb+的原因所在:这个查询可能需要几个小时/失败,具体取决于我们想做什么!
现在我们已经提取了一些数据,我们将其转换为Pandas df以便进行绘图。
最后,我们使用我们的visualize_df_with_plotly函数可视化df,该函数接受df并生成LLM代码以创建图表,然后显示图表!
5、实际示例
让我们看看一些实用查询的实际效果:
5.1 累积收益
query_and_plot("绘制TSLA和AAPL的累积收益")
这会生成:
- 一个计算累积收益的q-SQL查询
- 一条多线图,显示随时间的表现
- 自动处理日期解析和百分比计算
5.2 统计分析
query_and_plot("每种股票的平均价格是多少?")
这会产生:
- 按股票符号分组的查询以计算平均值
- 适当的条形图或表格可视化
- 清晰的标签和格式
类似地,我们可以得到每个股票收盘价最高的日期:
query_and_plot("每种股票哪一天的收盘价最高?")
这为什么重要:
- 规模化速度:虽然这个例子使用了一个小数据集,但kdb+可以轻松处理数十亿行数据。无论你有1,000行还是1,000,000,000行,相同的
query_and_plot
函数都能正常工作。 - 可访问性:非q-SQL专家的领域专家现在可以使用自然语言探索数据。这使高性能时间序列分析更加民主化。
- 快速迭代:与其手动编写、调试和优化查询,你可以通过对话式方式探索数据集,获得即时的可视化反馈。
- 节省资金:q开发人员和数据科学家的时间价值连城。如果他们能更快地完成任务,即使是小型量化开发团队也能节省数百万元。
6、结论
大多数查询都需要多次重新运行,直到生成有效的绘图和SQL代码,但这仍然比我自己编写这些查询容易得多。我认为通过更好的提示,很多错误都会消失。我也认为如果我要把这个变成一个工具,我会尝试10个不同的查询,可能使用不同的LLM,看看哪个成功。
我的建议是,如果可以的话,使用大模型——小模型目前可能不足以应对。
通过结合kdb+的性能与AI的自然语言能力,我们创造了一个强大的时间序列分析工具。这种方法从兆字节扩展到拍字节,使复杂的分析对任何可以用普通英语提问的人都变得触手可及。
金融行业每秒处理数百万笔交易——现在分析师可以像数据到达时一样快速查询和可视化这些数据。过去需要几个小时的查询编写和图表配置现在只需几秒钟,只需提出一个简单的问题。
随着数据集呈指数增长,像这样的工具不仅方便,而且在数据驱动行业中保持竞争力必不可少。
我很好奇是否有人尝试过在这个规模上进行生成性数据分析,或者用LLM编写q查询?
原文链接:How I’m Automating Billion-Row Time-Series Queries and Visualizations with AI
汇智网翻译整理,转载请标明出处