用自然语言查询大规模时序数据


在金融等许多领域,数十亿/数万亿行的时间序列数据集并不罕见,而是常态。然而,从这些庞大的数据集中获得任何见解往往非常困难,仅仅是因为它们太难处理了。

加载速度慢,查询速度慢,保持实时性可能是个头疼的问题。

这就是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("每种股票哪一天的收盘价最高?")

这为什么重要:

  1. 规模化速度:虽然这个例子使用了一个小数据集,但kdb+可以轻松处理数十亿行数据。无论你有1,000行还是1,000,000,000行,相同的query_and_plot函数都能正常工作。
  2. 可访问性:非q-SQL专家的领域专家现在可以使用自然语言探索数据。这使高性能时间序列分析更加民主化。
  3. 快速迭代:与其手动编写、调试和优化查询,你可以通过对话式方式探索数据集,获得即时的可视化反馈。
  4. 节省资金:q开发人员和数据科学家的时间价值连城。如果他们能更快地完成任务,即使是小型量化开发团队也能节省数百万元。

6、结论

大多数查询都需要多次重新运行,直到生成有效的绘图和SQL代码,但这仍然比我自己编写这些查询容易得多。我认为通过更好的提示,很多错误都会消失。我也认为如果我要把这个变成一个工具,我会尝试10个不同的查询,可能使用不同的LLM,看看哪个成功。

我的建议是,如果可以的话,使用大模型——小模型目前可能不足以应对。

通过结合kdb+的性能与AI的自然语言能力,我们创造了一个强大的时间序列分析工具。这种方法从兆字节扩展到拍字节,使复杂的分析对任何可以用普通英语提问的人都变得触手可及。

金融行业每秒处理数百万笔交易——现在分析师可以像数据到达时一样快速查询和可视化这些数据。过去需要几个小时的查询编写和图表配置现在只需几秒钟,只需提出一个简单的问题。

随着数据集呈指数增长,像这样的工具不仅方便,而且在数据驱动行业中保持竞争力必不可少。

我很好奇是否有人尝试过在这个规模上进行生成性数据分析,或者用LLM编写q查询?


原文链接:How I’m Automating Billion-Row Time-Series Queries and Visualizations with AI

汇智网翻译整理,转载请标明出处