0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Jupyter Notebook + chDBでローカルファイルを集計する

0
Posted at

ClickHouseというDBがあります。

このDBにはサーバを建てることなく、ローカルでエンジンを使用する機能が用意されています。

自分は、clickhouse-local をS3に吐かれたアクセスログの調査や、集計クエリを作成するためDBのCSVダンプファイルに対してSQLを試すのに使用しています。chDB は触ってこなかったので、使ってみたいと思います。

ちなみにそれらの違いは以下の通りです。

特徴 clickhouse-local chDB
実行モデル CLI(単体実行ツール) インプロセス(ライブラリとしてアプリ内に組込)
サーバー必要性 不要 不要
対象 単発クエリ/ローカル分析 アプリ内 SQL エンジン
API CLI / SQL インターフェイス Python/Go/Rust/Node.js API
データ処理 ファイル/ドライブ上データ プロセス内でデータ分析

Jupyter Notebook + chDB

インプロセスとのことで、Jupyter Notebookで使うのを試してみたいと思います。データはawsのMLチュートリアル用データ(banking.csv)をDLして使います。

さくっとインストールと、プロセス立ち上げをします。

$ python3 -m venv .venv
$ source .venv/bin/activate
(.venv) $ pip install notebook chdb
(.venv) $ jupyter notebook

以降は、Jupyter NotebookのMarkdown出力です。一部カラムが長い箇所を編集しています。

所管としては

  • 1つ目のクエリ実行のみファイル読み込みで時間がかかるが、その後は高速
  • クエリの結果は変数(result)に入るので、扱いやすそう
    • DataFrame 以外にも JSONLines など

chdbサンプル

import chdb

file = './banking.csv'

1. データの読み込み

query = f"""
SELECT * FROM file({file}, CSVWithNames)
LIMIT 5
"""

result = chdb.query(query, "DataFrame")
result
age job marital …
0 44 blue-collar married …
1 53 technician married …
2 28 management single …
3 39 services married …
4 55 retired married …

5 rows × 21 columns

2. 職業別の集計

query = f"""
SELECT 
    job,
    COUNT(*) as count,
    SUM(CASE WHEN y = 1 THEN 1 ELSE 0 END) as subscribed,
    ROUND(SUM(CASE WHEN y = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) as subscription_rate,
    ROUND(AVG(age), 1) as avg_age
FROM file({file}, CSVWithNames)
GROUP BY job
ORDER BY count DESC
"""

result = chdb.query(query, "DataFrame")
result

job count subscribed subscription_rate avg_age
0 admin. 10422 1352 12.97 38.2
1 blue-collar 9254 638 6.89 39.6
2 technician 6743 730 10.83 38.5
3 services 3969 323 8.14 37.9
4 management 2924 328 11.22 42.4
5 retired 1720 434 25.23 62.0
6 entrepreneur 1456 124 8.52 41.7
7 self-employed 1421 149 10.49 39.9
8 housemaid 1060 106 10.00 45.5
9 unemployed 1014 144 14.20 39.7
10 student 875 275 31.43 25.9
11 unknown 330 37 11.21 45.6

3. 年齢層別の集計

query = f"""
SELECT 
    CASE 
        WHEN age < 30 THEN '20代'
        WHEN age < 40 THEN '30代'
        WHEN age < 50 THEN '40代'
        WHEN age < 60 THEN '50代'
        ELSE '60代以上'
    END as age_group,
    COUNT(*) as count,
    SUM(CASE WHEN y = 1 THEN 1 ELSE 0 END) as subscribed,
    ROUND(SUM(CASE WHEN y = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) as subscription_rate
FROM file({file}, CSVWithNames)
GROUP BY age_group
ORDER BY MIN(age)
"""

result = chdb.query(query, "DataFrame")
result

age_group count subscribed subscription_rate
0 20代 5669 922 16.26
1 30代 16938 1715 10.13
2 40代 10526 834 7.92
3 50代 6862 697 10.16
4 60代以上 1193 472 39.56

4. 月別の集計

query = f"""
SELECT 
    month,
    COUNT(*) as count,
    SUM(CASE WHEN y = 1 THEN 1 ELSE 0 END) as subscribed,
    ROUND(SUM(CASE WHEN y = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) as subscription_rate
FROM file({file}, CSVWithNames)
GROUP BY month
ORDER BY 
    CASE month
        WHEN 'jan' THEN 1
        WHEN 'feb' THEN 2
        WHEN 'mar' THEN 3
        WHEN 'apr' THEN 4
        WHEN 'may' THEN 5
        WHEN 'jun' THEN 6
        WHEN 'jul' THEN 7
        WHEN 'aug' THEN 8
        WHEN 'sep' THEN 9
        WHEN 'oct' THEN 10
        WHEN 'nov' THEN 11
        WHEN 'dec' THEN 12
    END
"""

result = chdb.query(query, "DataFrame")
result

month count subscribed subscription_rate
0 mar 546 276 50.55
1 apr 2632 539 20.48
2 may 13769 886 6.43
3 jun 5318 559 10.51
4 jul 7174 649 9.05
5 aug 6178 655 10.60
6 sep 570 256 44.91
7 oct 718 315 43.87
8 nov 4101 416 10.14
9 dec 182 89 48.90
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?