数据聚合
数据 聚合概述
当我们使用VChart等图表库来绘制柱状图、折线图等图表时,如果使用的数据集dataset并未经过聚合处理,可能会对可视化效果产生不良影响。 举例来说,假设我们有一份商品销售额明细数据集:
// 商品销售数据集 [ { "Product name": "Coke", "Sales": 2350 }, { "Product name": "Coke", "Sales": 1027 }, { "Product name": "Coke", "Sales": 1027 }, { "Product name": "Coke", "Sales": 1027 }, { "Product name": "Sprite", "Sales": 215 }, { "Product name": "Sprite", "Sales": 654 }, { "Product name": "Sprite", "Sales": 159 }, { "Product name": "Sprite", "Sales": 28 }, { "Product name": "Fanta", "Sales": 345 }, { "Product name": "Fanta", "Sales": 654 }, { "Product name": "Fanta", "Sales": 2100 }, { "Product name": "Fanta", "Sales": 1679 }, { "Product name": "Mirinda", "Sales": 1476 }, { "Product name": "Mirinda", "Sales": 830 }, { "Product name": "Mirinda", "Sales": 532 }, { "Product name": "Mirinda", "Sales": 498 } ]
在这个数据集中,有两个字段Product name和Sales。可以看出在这个数据集中,有多条数据具有相同的Product name。如果我们想使用这份数据将Product name作为X轴,Sales作为Y轴来绘制柱状图,展示不同地区的销售额,则在X轴每个维值下面将有多条柱子与之对应。
对于这种数据集,不同图表库的处理方式不同。VChart的处理方式是将这些柱子堆叠起来进行展示:

使用这种未聚合的数据集绘制图表可能会有以下几个问题:
- 数据过载:如果数据集非常大,那么图表中可能会有大量的图元,这可能会使图表变得非常混乱,难以阅读和理解,还会导致性能问题。
- 隐藏重要的信息:如果数据没有经过适 当的聚合,那么可能会隐藏一些重要的信息。例如,如果你有一个包含每天销售额的数据集,那么直接绘制这个数据集可能会导致图表变得非常混乱。但是,如果你将数据按月聚合,那么可能会更容易看出销售额的趋势。
- 数据分布不清:未聚合的数据可能会使得数据的分布特征不明显,例如平均值、中位数、众数等。
因此,通常在绘制图表之前,我们会先对数据进行适当的聚合,以便更好地展示数据的特征和趋势。
同时由于原始的数据集没有对字段进行筛选和排序,某些图表展示意图无法满足,例如:帮我展示销售额最多的10个部门,帮我展示北方区域各商品的销售额等。
VMind 1.2.2版本开始支持智能数据聚合功能。该功能会将用户传入的数据作为一张数据表,使用大语言模型根据用户的指令生成SQL查询语句,从数据表中查询数据,并通过GROUP BY和聚合函数对数据进行分组聚合、排序、筛选。
接下来,我们将详细介绍VMind数据聚合功能的使用方法。
dataQuery
VMind对象的dataQuery函数是一个强大的数据聚合工具。它接收三个参数:用户展示意图userPrompt,数据集字段信息fieldInfo和原始数据集dataset。你可以在数据格式与数据处理中找到关于fieldInfo和dataset的详细信息。VMind会根据用户的展示意图,编写SQL语句并对dataset执行查询,查询结果会被储存在函数返回值的dataset属性中;同时,查询结果中的字段可能会发生变化,更新后的字段信息也会被储存在返回结果的fieldInfo属性中。
下面,让我们通过一个示例来看看如何使用dataQuery函数:
import VMind from '@visactor/vmind' const sourceDataset = [ { "Product name": "Coke", "Sales": 2350 }, { "Product name": "Coke", "Sales": 1027 }, { "Product name": "Coke", "Sales": 1027 }, { "Product name": "Coke", "Sales": 1027 }, { "Product name": "Sprite", "Sales": 215 }, { "Product name": "Sprite", "Sales": 654 }, { "Product name": "Sprite", "Sales": 159 }, { "Product name": "Sprite", "Sales": 28 }, { "Product name": "Fanta", "Sales": 345 }, { "Product name": "Fanta", "Sales": 654 }, { "Product name": "Fanta", "Sales": 2100 }, { "Product name": "Fanta", "Sales": 1679 }, { "Product name": "Mirinda", "Sales": 1476 }, { "Product name": "Mirinda", "Sales": 830 }, { "Product name": "Mirinda", "Sales": 532 }, { "Product name": "Mirinda", "Sales": 498 } ] const sourceFieldInfo = [ { "fieldName": "Product name", "type": "string", "role": "dimension" }, { "fieldName": "Sales", "type": "int", "role": "measure" } ] const userPrompt=`展示各商品销售额` const vmind = new VMind(options) //调用dataQuery传入userPrompt,sourceFieldInfo和sourceDataset,执行数据聚合 const { fieldInfo, dataset } = vmind.dataQuery(userPrompt, sourceFieldInfo, sourceDataset);
在这个例子中,dataQuery函数返回的dataset如下:
[ { "Product name": "Coke", "total_sales": 5431 }, { "Product name": "Sprite", "total_sales": 1056 }, { "Product name": "Fanta", "total_sales": 4778 }, { "Product name": "Mirinda", "total_sales": 3336 } ]
返回的fieldInfo如下:
[ { "fieldName": "Product name", "description": "The name of the product.", "type": "string", "role": "dimension" }, { "fieldName": "total_sales", "description": "An aggregated field representing the total sales of each product. It is generated by summing up the 'Sales' values for each product.", "type": "int", "role": "measure" } ]
有了这些信息,我们就可以直接使用fieldInfo和dataset生成图表了。具体的操作步骤,你可以在图表智能生成章节中找到。
📢 注意:dataQuery方法会将userPrompt和fieldInfo传递给大模型用于生成SQL,dataset中的明细数据并不会被传递。
最后,我们将得到如下的柱状图:

在这个例子中,VMind生成的SQL语句为:
SELECT `Product name`, SUM(`Sales`) AS total_sales FROM dataSource GROUP BY `Product name`
这条SQL语句从sourceDataset中筛选出Produce name和Sales两个字段,按照Produce name进行分组,并对Sales字段进行了求和,生成了新的字段total_sales。VMind将执行这一sql语句,得到聚合后的数据集。
需要注意的是,dataQuery执行过程中,目前支持的SQL关键词有:SELECT, GROUP BY, WHERE, HAVING, ORDER BY, LIMIT。目前支持的聚合函数有:MAX(), MIN(), SUM(), COUNT(), AVG(),但不支持子查询、JOIN、条件语句等复杂的SQL操作。
数据筛选与排序
在这个部分,我们将学习如何使用自然语言来对数据集进行筛选和排序等操作。
首先,让我们看一下下面的数据集(dataset)和字段信息(fieldInfo):
import VMind from '@visactor/vmind' const sourceDataset = [ { "商品名称": "可乐", "region": "south", "销售额": 2350 }, { "商品名称": "可乐", "region": "east", "销售额": 1027 }, { "商品名称": "可乐", "region": "west", "销售额": 1027 }, { "商品名称": "可乐", "region": "north", "销售额": 1027 }, { "商品名称": "雪碧", "region": "south", "销售额": 215 }, { "商品名称": "雪碧", "region": "east", "销售额": 654 }, { "商品名称": "雪碧", "region": "west", "销售额": 159 }, { "商品名称": "雪碧", "region": "north", "销售额": 28 }, { "商品名称": "芬达", "region": "south", "销售额": 345 }, { "商品名称": "芬达", "region": "east", "销售额": 654 }, { "商品名称": "芬达", "region": "west", "销售额": 2100 }, { "商品名称": "芬达", "region": "north", "销售额": 1679 }, { "商品名称": "醒目", "region": "south", "销售额": 1476 }, { "商品名称": "醒目", "region": "east", "销售额": 830 }, { "商品名称": "醒目", "region": "west", "销售额": 532 }, { "商品名称": "醒目", "region": "north", "销售额": 498 } ] const sourceFieldInfo = [ { "fieldName": "商品名称", "type": "string", "role": "dimension" }, { "fieldName": "region", "type": "string", "role": "dimension" }, { "fieldName": "销售额", "type": "int", "role": "measure" } ]
假设我们想要展示北方区域销售额排名前三的商品,我们可以这样做:
const userPrompt = `帮我展示北方排名前三的商品销售额` const vmind = new VMind(options) // 调用dataQuery方法,传入userPrompt,sourceFieldInfo和sourceDataset,执行数据聚合 const { fieldInfo, dataset } = vmind.dataQuery(userPrompt, sourceFieldInfo, sourceDataset);
在dataQuery方法执行过程中,会生成如下的SQL语句:
SELECT `商品名称`, SUM(`销售额`) AS total_sales FROM dataSource WHERE region = 'north' GROUP BY `商品名称` ORDER BY total_sales DESC LIMIT 3
这个SQL语句将筛选出区域(region)为'north'的数据,然后按照"商品名称"进行分组,并计算每个商品的总销售额,最后按照销售额从高到低排序,并只取销售额最高的前三个商品。
最后,执行图表生成操作,我们就可以得到如下的图表:
