ClickHouse实现大数据探索性分析

分析数据一般会从探索性分析开始,即尝试理解数据本身的概况。通常包括中位数、平均值或分布情况,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 │
└──────────────────────┴───────────────────┴───────────────────┘

计算公式:
ClickHouse实现大数据探索性分析_第1张图片

相关性

计算两列的相关性:

SELECT covarPop(c,d) FROM test

返回结果:


SELECT covarPop(c, d)
FROM test

Query id: 0ac4a304-03e8-42ce-b521-dc23187c6aea

┌─────covarPop(c, d)─┐
│ 153714998.91794837 │
└────────────────────┘

计算公式:

ClickHouse实现大数据探索性分析_第2张图片

实际应用中相关性系数更常用,它可以消除量纲,计算相关系数:

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) 计算标准差

你可能感兴趣的:(ClickHouse,clickhouse,数据分析,探索性分析)