分析数据一般会从探索性分析开始,即尝试理解数据本身的概况。通常包括中位数、平均值或分布情况,Python Numpy/Pandas很容易实现,但如果数据量为Tb级,不能简单依赖RAM工具实现。ClickHouse提供的强大的工具来挖掘数据,不仅局限于min/max/avg分析。
测试数据
下面在clickhouse中创建示例表,并生成测试数据:
CREATE TABLE test (
`time` DateTime, `a` UInt64, `b` Float64,
`c` UInt32, `d` UInt32, `e` UInt32
)
ENGINE = MergeTree
ORDER BY time
新版ClickHouse可以不指定ENGINE,为了兼容之前版本,这里显示指定表引擎,下面生成10亿测试数据:
INSERT INTO test
SELECT now() - number, rand64()/1000000000,
round(rand32()/1000000)/100,
rand32()/1000000, rand32()/10000, rand32()/100
FROM numbers(1000000000);
探索性分析
Min, Max, Avg, Median
首先通过基本的聚集函数实现:
SELECT min(a), max(a), avg(a), median(a) FROM test
可以a列的总体情况:
返回结果:
SELECT
min(a),
max(a),
avg(a),
median(a)
FROM test
Query id: ba893a8e-1c1e-4ae0-93d1-b966a370c841
┌─min(a)─┬──────max(a)─┬────────────avg(a)─┬────median(a)─┐
│ 27 │ 18446744043 │ 9223167195.242725 │ 9269412176.5 │
└────────┴─────────────┴───────────────────┴──────────────┘
注意:median函数是近似实现(为了性能考虑),如果需要准确结果实用medianExact()。
对于相同类型列,可以实用ForEach合并器展示所有列的聚集结果:
WITH [a, c, d, e] AS col
SELECT maxForEach(col), minForEach(col),
avgForEach(col), medianForEach(col)
FROM test
注意,这里跳过b列,因为b为Float类型,不是Int类型。结果返回多个数组值,顺序于with子句保持一致:
查看结果:
WITH [a, c, d, e] AS col
SELECT
maxForEach(col),
minForEach(col),
avgForEach(col),
medianForEach(col)
FROM test
Query id: e0da1a1d-0dd7-4ac1-8061-13e5b1d32637
┌─maxForEach(col)────────────────────┬─minForEach(col)─┬─avgForEach(col)────────────────────────────────────────────────────────┬─medianForEach(col)────────────────────┐
│ [18446744043,4294,429496,42949672] │ [27,0,0,0] │ [9223167195.242725,2147.084726271,214757.971990777,21475846.697796952] │ [9094439831,2158,215857.5,21585783.5] │
└────────────────────────────────────┴─────────────────┴────────────────────────────────────────────────────────────────────────┴───────────────────────────────────────┘
加权平均
有时需要计算加权平均,一列为业务度量(假设为a列)、一列为权重(这里假设为c列):
SELECT avgWeighted(a, c) FROM test
结果与标准平均有差异,因为c列表示每行的权重:
SELECT avgWeighted(a, c)
FROM test
Query id: b5af5a0f-2b15-4410-a4b9-2432673b43e1
┌─avgWeighted(a, c)─┐
│ 4500282.012782601 │
└───────────────────┘
分位数
数据值分布分析用于理解大多数样本值的分布情况,可以使用quantile函数,下面展示a列的值分布情况:
SELECT quantile(0.01)(a), quantile(0.05)(a), quantile(0.1)(a),
quantile(0.5)(a), quantile(0.9)(a), quantile(0.95)(a),
quantile(0.99)(a)
FROM test
结果如下:
SELECT
quantile(0.01)(a),
quantile(0.05)(a),
quantile(0.1)(a),
quantile(0.5)(a),
quantile(0.9)(a),
quantile(0.95)(a),
quantile(0.99)(a)
FROM test
Query id: 3085d3ef-387a-4e01-a6b0-42ce33393839
┌─quantile(0.01)(a)─┬─quantile(0.05)(a)─┬─quantile(0.1)(a)─┬─quantile(0.5)(a)─┬───quantile(0.9)(a)─┬──quantile(0.95)(a)─┬─quantile(0.99)(a)─┐
│ 177601178.51 │ 896692543.5 │ 1874314795.8 │ 9045538672 │ 16552719369.300003 │ 17504816857.949997 │ 18283462553.02 │
└───────────────────┴───────────────────┴──────────────────┴──────────────────┴────────────────────┴────────────────────┴───────────────────┘
quantile函数参数表示需要计算的百分位数,范围:0~1之间。
- 0.01 表 1% 百分位 (表示:a列值中仅1%小于计算结果),
- 0.99 表示 99% 百分位,
- 0.5 表示 50% 百分位 (或中位数).
我们可以使用箱线图展示列数据的分布情况。通常用于展示数据分布及异常值。
直方图
histogram函数计算数据直方图,参数为分组数量:
SELECT histogram(10)(a) FROM test
结果如下:
Query id: 12671173-07b6-4626-88cf-1c1e0b06b311
┌─hist_a─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ [(27,1778599749.8154733,96220818.875),(1778599749.8154733,3567318758.13501,96866341.75),(3567318758.13501,5383282603.941727,98348320.75),(5383282603.941727,7229037840.827569,100085775.125),(7229037840.827569,9098282038.82383,101508675.125),(9098282038.82383,10979523217.501022,102238136.25),(10979523217.501022,12860395774.905602,102171698.875),(12860395774.905602,14731643787.83552,101508574.5),(14731643787.83552,16590229016.271152,100691124.875),(16590229016.271152,18446744043,100360533.875)] │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
1 rows in set. Elapsed: 21.144 sec. Processed 1.00 billion rows, 8.00 GB (47.29 million rows/s., 378.36 MB/s.)
返回10元组数组,每个tuple包括起始值、截止值和频数。上面结果不够直观,下面使用bar函数进行展示:
WITH count(*) AS m, histogram(10)(a) AS h
SELECT m, arrayJoin(h).3 AS v, bar(v, 0, m / 10, 50) hist
FROM test
这里计算a列直方图,分为10个组,用频次作为高度:获取元组的第三个值:arrayJoin(h).3
。bar中几个参数意义分别为:当前值,最小值,最大值,最大宽度(bar的最大宽度),结果如下:
WITH
count(*) AS m,
histogram(10)(a) AS h
SELECT
m,
arrayJoin(h).3 AS v,
bar(v, 0, m / 10, 50) AS hist
FROM test
Query id: 84d73ecf-4ad6-436a-b007-d4028a8703b5
┌──────────m─┬─────────────v─┬─hist───────────────────────────────────────────────┐
│ 1000000000 │ 96191900 │ ████████████████████████████████████████████████ │
│ 1000000000 │ 96848619.75 │ ████████████████████████████████████████████████▍ │
│ 1000000000 │ 98342270.625 │ █████████████████████████████████████████████████▏ │
│ 1000000000 │ 100073373.5 │ ██████████████████████████████████████████████████ │
│ 1000000000 │ 101491254.375 │ ██████████████████████████████████████████████████ │
│ 1000000000 │ 102252583.25 │ ██████████████████████████████████████████████████ │
│ 1000000000 │ 102199888.125 │ ██████████████████████████████████████████████████ │
│ 1000000000 │ 101529766.75 │ ██████████████████████████████████████████████████ │
│ 1000000000 │ 100703527.125 │ ██████████████████████████████████████████████████ │
│ 1000000000 │ 100366816.5 │ ██████████████████████████████████████████████████ │
└────────────┴───────────────┴────────────────────────────────────────────────────┘
10 rows in set. Elapsed: 20.589 sec. Processed 1.00 billion rows, 8.00 GB (48.57 million rows/s., 388.56 MB/s.)
偏度(skewness)和峰度(kurtosis) 偏度
SELECT skewPop(a), skewPop(b), skewPop(c), skewPop(d) FROM test
可以看到完美的对称数据,如果偏度范围是 -0.5~0.5
,则为对称。
SELECT
skewPop(a),
skewPop(b),
skewPop(c),
skewPop(d)
FROM test
Query id: 3d8f142e-540a-45cf-b29b-92ebcb680655
┌─────────────skewPop(a)─┬──────────────skewPop(b)─┬──────────────skewPop(c)─┬──────────────skewPop(d)─┐
│ 0.00008286246282390312 │ -0.00009044879302832024 │ -0.00009040144066574894 │ -0.00009043134876494848 │
└────────────────────────┴─────────────────────────┴─────────────────────────┴─────────────────────────┘
下面检查峰度情况,峰度包括正态分布(峰度值=3),厚尾(峰度值>3),瘦尾(峰度值<3)。
SELECT kurtPop(a), kurtPop(b), kurtPop(c), kurtPop(d) FROM test
结果如下:
SELECT
kurtPop(a),
kurtPop(b),
kurtPop(c),
kurtPop(d)
FROM test
Query id: bfa86913-a7ec-46d2-b568-4337cd36c8f1
┌─────────kurtPop(a)─┬─────────kurtPop(b)─┬────────kurtPop(c)─┬─────────kurtPop(d)─┐
│ 1.7999958442027149 │ 1.8000103475159206 │ 1.800009989793573 │ 1.8000101052993867 │
└────────────────────┴────────────────────┴───────────────────┴────────────────────┘
唯一值
ClickHouse使用高效内存近似计算唯一值算法,通常用在探索性分析阶段:
SELECT uniq(a), uniq(b), uniq(c), uniq(d), uniq(e) FROM test
如果需要准确计算,采用count(distinct s) 。uniq采用HLL(HyperLogLog,默认精度为17),可以通过uniqCombined()指定精度,精度越高准确度越高,占用内存越大。
SELECT
uniq(a),
uniq(b),
uniq(c),
uniq(d),
uniq(e)
FROM test
Query id: dff853d6-b2b6-4d60-8a7f-8769feb91a68
┌───uniq(a)─┬─uniq(b)─┬─uniq(c)─┬─uniq(d)─┬──uniq(e)─┐
│ 976951893 │ 4296 │ 4295 │ 431282 │ 42794211 │
└───────────┴─────────┴─────────┴─────────┴──────────┘
最受欢迎值
计算数据集中最受欢迎值
SELECT a, count(*) AS total FROM test
GROUP BY a ORDER BY total DESC LIMIT 5
该语句等价于:
SELECT topK(5)(a) FROM test
结果如下:
SELECT topK(5)(a)
FROM test
Query id: a97a98fa-1ce5-42cf-a201-2094f6cd999f
┌─topK(5)(a)─────────────────────────────────────────────────┐
│ [5887434584,5400923505,14324499147,1971311740,12559436788] │
└────────────────────────────────────────────────────────────┘
topK比传统写法效率更高、更简洁,建议使用topK.
标准差
标准差可以理解数据的分散程度,varPop函数可以计算标准差:
SELECT varPop(a), varPop(c), varPop(d) FROM test
结果如下:
SELECT
varPop(a),
varPop(c),
varPop(d)
FROM test
Query id: 47696a42-dd17-47fa-a937-00e49bc6d11b
┌────────────varPop(a)─┬─────────varPop(c)─┬─────────varPop(d)─┐
│ 28357107720360067000 │ 1537149.986743688 │ 15371500762.27394 │
└──────────────────────┴───────────────────┴───────────────────┘
计算公式:
相关性
计算两列的相关性:
SELECT covarPop(c,d) FROM test
返回结果:
SELECT covarPop(c, d)
FROM test
Query id: 0ac4a304-03e8-42ce-b521-dc23187c6aea
┌─────covarPop(c, d)─┐
│ 153714998.91794837 │
└────────────────────┘
计算公式:
实际应用中相关性系数更常用,它可以消除量纲,计算相关系数:
SELECT corr(c,d) FROM test
返回结果:
SELECT corr(c, d)
FROM test
Query id: 450eb864-f1f5-4945-9bf4-c88bcf9a75d5
┌─────────corr(c, d)─┐
│ 0.9999999725139772 │
└────────────────────┘
因为完美插入测试数据采用不同比例,两者当然为正相关,结果接近1.
总结
ClickHouse提供数学函数、聚集函数用于对大数据量进行探索性分析。一些函数采用近似算法进行优化,如:unique,quantile
,效率更高,通常用于数据分析的初始阶段。下面列举探索性阶段常用的函数:
- min(), max(), avg() and median() 最常用的几个聚集函数
- avgWeighted(col, weights) 计算加权平均
- quantile(level)(col) 计算分位数
- histogram(bins)(col) and bar() 计算并画直方图
- skewPop(col) 计算偏度,判断数据是否对称
- uniq(col) 近似唯一值计算
- topK(N)(col) 计算最受欢迎的N个值
- varPop(col) 计算标准差