立即开始增强您的 PostgreSQL。
PostgreSQL 有两个函数可以计算任何百分比的值列表的百分位数:percentile_cont()
和 percentile_disc()
。这两个函数的工作原理类似,但它们在生成最终结果的方式上有所不同。两者都与 WITHIN GROUP
子句返回的有序集聚合一起使用。
percentile_disc()
函数从输入集中返回一个最接近请求百分位数的值。返回的值实际上存在于集合中。
以下是 percentile_disc()
语法
SELECT
percentile_disc(<fraction double precision>) WITHIN GROUP (<sort_expression>)
FROM <table>;
percentile_cont()
函数根据分布返回多个值之间的插值。它更准确,但它可能会在输入集中返回两个值之间的小数值。
percentile_cont()
语法
SELECT
percentile_cont(<fraction double precision>) WITHIN GROUP (<sort_expression>)
FROM <table>;
计算中位数
计算多个百分位数
计算一系列百分位数
对于以下示例,我们将使用存储在名为 city_data:
的表中的这组天气数据
日期 | 城市 | 温度 | 降水量 |
2021-09-04 | 迈阿密 | 68.36 | 0.00 |
2021-09-05 | 迈阿密 | 72.50 | 0.00 |
2021-09-01 | 迈阿密 | 65.30 | 0.28 |
2021-09-02 | 迈阿密 | 64.40 | 0.79 |
2021-09-03 | 迈阿密 | 68.18 | 0.47 |
2021-09-04 | 亚特兰大 | 67.28 | 0.00 |
2021-09-05 | 亚特兰大 | 68.72 | 0.00 |
2021-09-01 | 亚特兰大 | 63.14 | 0.20 |
2021-09-02 | 亚特兰大 | 62.60 | 0.59 |
2021-09-03 | 亚特兰大 | 62.60 | 0.39 |
中位数也称为第 50 个百分位数。您可以使用以下查询从数据集中计算它
SELECT
percentile_disc(0.5) WITHIN GROUP (
ORDER BY temperature)
FROM city_data;
结果是
percentile_disc |
65.30 |
因为查询使用了 percentile_disc()
,所以结果是数据集中存在的值。如果要查找真正的中位数,它不是此数据中的值,则必须使用 percentile_cont()
。以下是查询
SELECT
percentile_cont(0.5) WITHIN GROUP (
ORDER BY temperature)
FROM city_data;
结果如下
percentile_cont |
66.28999999999999 |
但由于有两个城市,您可能希望通过添加 GROUP BY
子句来计算每个城市的中位数温度。以下是该查询
SELECT
city,
percentile_cont(0.5) WITHIN GROUP (
ORDER BY
temperature)
FROM
city_data
GROUP BY
city;
结果是
城市 | percentile_cont |
亚特兰大 | 63.14 |
迈阿密 | 68.18 |
在本例中,我们将使用名为 conditions 的数据库表,其中包含以下值
时间 | 设备 ID | 温度 | 湿度 |
2016-11-15 07:00:00 | weather-pro-000001 | 32.4 | 49.8 |
2016-11-15 07:00:00 | weather-pro-000002 | 39.800000000000004 | 50.2 |
2016-11-15 07:00:00 | weather-pro-000003 | 36.800000000000004 | 49.8 |
2016-11-15 07:00:00 | weather-pro-000004 | 71.8 | 50.1 |
2016-11-15 07:00:00 | weather-pro-000005 | 71.8 | 49.9 |
2016-11-15 07:00:00 | weather-pro-000006 | 37 | 49.8 |
假设我们想要计算每个设备湿度的各种百分位数。以下是一个示例查询
SELECT
device_id,
percentile_cont(0.25) WITHIN GROUP(
ORDER BY
humidity) AS percentile_25,
percentile_cont(0.50) WITHIN GROUP(
ORDER BY
humidity) AS percentile_50,
percentile_cont(0.75) WITHIN GROUP(
ORDER BY
humidity) AS percentile_75,
percentile_cont(0.95) WITHIN GROUP(
ORDER BY
humidity) AS percentile_95
FROM
conditions
GROUP BY
device_id ;
以下是结果的一部分
设备 ID | percentile_25(第 25 个百分位数) | percentile_50(第 50 个百分位数) | percentile_75(第 75 个百分位数) | percentile_95(第 95 个百分位数) |
weather-pro-000000 | 49.29999999999999 | 50.500000000000036 | 53.10000000000007 | 54.9000000000001 |
weather-pro-000001 | 49.09999999999999 | 50.00000000000003 | 51.60000000000005 | 55.6 |
weather-pro-000002 | 52.500000000000036 | 53.60000000000005 | 54.00000000000006 | 54.500000000000064 |
weather-pro-000003 | 51.100000000000016 | 51.90000000000003 | 52.90000000000004 | 53.800000000000054 |
weather-pro-000004 | 48.60000000000001 | 49.20000000000002 | 49.60000000000002 | 50.400000000000034 |
在本例中,我们将回到最初的 city_data
数据集,因为此查询在大型数据集上运行可能需要很长时间。我们将使用 generate_series()
函数创建每个整数百分比,然后在 percentile_cont 函数中使用这些值。以下是查询
SELECT
city,
percentile,
percentile_cont(p) WITHIN GROUP (
ORDER BY
temperature)
FROM
city_data,
generate_series(0.01, 1, 0.01) AS percentile
GROUP BY
city, percentile;
由于查询生成了 200 行结果,以下是一些结果的选取
城市 | 百分位数 | percentile_cont |
亚特兰大 | 0.25 | 62.6 |
亚特兰大 | 0.26 | 62.6216 |
亚特兰大 | 0.27 | 62.6432 |
亚特兰大 | 0.28 | 62.6648 |
亚特兰大 | 0.29 | 62.6864 |
亚特兰大 | 0.30 | 62.708 |
在大型数据集(例如 Timescale 数据库中的时序数据)上计算百分位数可能涉及大量昂贵的计算。它可能会增加数据库的内存占用量,导致更高的网络成本,并使流数据变得不可行。聚合函数也不能部分化或并行化。
很多时候,你不需要这种类型的准确性,而近似百分位数计算就足够接近了。这就是 Timescale 引入 approx_percentile()
超函数 的原因。approx_percentile()
函数实现了 UDDSketch 算法,该算法使用修改后的直方图来近似分布的形状。这允许在不需要使用所有数据或在返回结果之前对其进行排序的情况下计算“足够好”的百分位数。
approx_percentile()
语法
approx_percentile(
percentile DOUBLE PRECISION,
sketch uddsketch
) RETURNS DOUBLE PRECISION
第二个参数是要对其执行 approx_percentile
操作的草图,通常从 percentile_agg()
调用返回。以下是一个示例查询
SELECT
approx_percentile(0.01, percentile_agg(data))
FROM generate_series(0, 100) data;
结果
approx_percentile(近似百分位数) |
0.999 |
要详细了解如何在 PostgreSQL 中使用 percentile_cont()
和 percentile_disc()
函数,请参阅 PostgreSQL 文档。
要详细了解 Timescale 的 approx_percentile()
函数,请阅读 Timescale 文档 中的更多信息。
有关如何在查询中使用这些函数的示例,请参阅 Timescale 文档的以下部分