使用 DuckDB 计算描述性统计量

大家好!在本文中,我们将一起探索如何使用 DuckDB 对 CSV 数据进行常见的描述性统计计算。

无需导入库、无需创建表格,直接使用 SQL 语句就能快速对数据集进行初步分析。

我们会一起学习如何:

  • 直接读取并查询 CSV 文件
  • 计算数据的平均值和中位数
  • 求出标准差与方差
  • 找出最小值、最大值以及数据范围
  • 计算百分位数
  • 理解这些统计指标背后的含义

通过这篇文章,你将掌握如何用简单高效的 SQL 语句,快速了解数据的集中趋势、波动情况,甚至发现潜在的异常值。

下面用一个国内奶茶店外卖订单的场景演示。

假设有一份 waimai_orders.csv,字段包括:

order_id, order_time, shop_name, category, amount, delivery_fee, distance_km, delivery_min

我们要回答几个问题:

  • 平均每单多少钱?中位数多少?
  • 配送费平均多少?
  • 配送距离和配送时长波动大不大?
  • 最贵、最便宜、最远、最慢分别是多少?
  • 大部分订单金额落在什么区间?

所有操作都依靠 DuckDB 来完成。

1. 环境配置与数据加载

先安装 DuckDB 和 pandas:

pip install duckdb pandas

然后在 Python 里直接查 CSV:

import duckdb

con = duckdb.connect()

con.sql("""
CREATE OR REPLACE VIEW orders AS
SELECT * FROM read_csv_auto('/opt/share/waimai_orders.csv')
""")

con.sql("SELECT * FROM orders LIMIT 5").df()
order_id order_time shop_name category amount delivery_fee distance_km delivery_min
1001 2025-03-01 02:41:00 茶百道(春熙路店) 奶茶 20.7 3.0 1.5 21
1002 2025-03-01 03:09:00 喜茶(太古里店) 果茶 9.9 5.0 2.9 34
1003 2025-03-01 03:10:00 古茗(天府三街店) 果茶 11.8 4.0 1.0 23
1004 2025-03-01 03:17:00 喜茶(太古里店) 咖啡 38.0 3.0 1.0 18
1005 2025-03-01 03:26:00 喜茶(太古里店) 奶茶 38.5 3.0 4.0 37

这里 DuckDB 的优势是:read_csv_auto 自动推断字段类型,CSV 直接当表查。

不用建表,不用导数,不用起服务,对探索式分析来说很省事。

2. 计算均值与中位数

均值和中位数要一起看。均值容易被极端大单拉高,中位数更接近“典型订单”。

con.sql("""
SELECT
  AVG(amount) AS avg_amount,
  MEDIAN(amount) AS median_amount,
  AVG(delivery_fee) AS avg_delivery_fee,
  MEDIAN(delivery_fee) AS median_delivery_fee,
  AVG(distance_km) AS avg_distance,
  MEDIAN(distance_km) AS median_distance,
  AVG(delivery_min) AS avg_delivery_min,
  MEDIAN(delivery_min) AS median_delivery_min
FROM orders
""").df()
指标 数值
平均金额 avg_amount 45.9058
中位金额 median_amount 29.15

平均金额(45.91 元)比中位数(29.15 元)高不少,说明有少数大单把平均值拉高了。

3. 计算标准差与方差

标准差衡量数值偏离均值的程度。

标准差越大,数据越分散。方差也是离散度,但单位是平方,解读不如标准差直观。

con.sql("""
SELECT
  STDDEV(amount) AS std_amount,
  VARIANCE(amount) AS var_amount,
  STDDEV(delivery_min) AS std_delivery_min,
  VARIANCE(delivery_min) AS var_delivery_min,
  STDDEV(distance_km) AS std_distance,
  VARIANCE(distance_km) AS var_distance
FROM orders
""").df()
指标 数值
订单金额标准差 std_amount 50.17
订单金额方差 var_amount 2517.48
配送时长标准差 std_delivery_min 10.49
配送时长方差 var_delivery_min 110.10
配送距离标准差 std_distance 1.50
配送距离方差 var_distance 2.26

订单金额标准差约为 50.17,说明订单金额差异非常大——有的单十几块,有的单可能上百块,分布很分散。

配送时长的标准差约为 10.49 分钟,意味着配送耗时波动明显:以平均配送时长(约 20 ~ 30 分钟)为中心,大部分订单送达时间会落在 均值 ±10 分钟左右 的范围内,也就是既有 20 多分钟就能送到的单,也可能出现 40 ~ 50 分钟甚至更久的订单。

配送时长的这种波动值得重点关注。

4. 计算最小值、最大值与范围

最小值、最大值看边界。范围就是最大值减最小值,快速了解数据跨度。

con.sql("""
SELECT
  MIN(amount) AS min_amount,
  MAX(amount) AS max_amount,
  MAX(amount) - MIN(amount) AS range_amount,
  MIN(delivery_min) AS min_delivery_min,
  MAX(delivery_min) AS max_delivery_min,
  MAX(delivery_min) - MIN(delivery_min) AS range_delivery_min,
  MIN(distance_km) AS min_distance,
  MAX(distance_km) AS max_distance,
  MAX(distance_km) - MIN(distance_km) AS range_distance
FROM orders
""").df()
指标 数值
最小金额 min_amount 9.9 元
最大金额 max_amount 289.3 元
金额极差 range_amount 279.4 元
最慢配送 max_delivery_min 89 分钟
最快配送 min_delivery_min 18 分钟
配送时长极差 range_delivery_min 71 分钟
最远距离 max_distance 12.3 公里
最近距离 min_distance 0.5 公里
距离极差 range_distance 11.8 公里

最贵的订单约 289 元 ,可能是团餐;但金额极差达到 279 元,说明客单价跨度非常大。

最远配送距离约 12.3 公里 、最慢的订单用了 89 分钟 才送到,这种单虽然占比可能不高,但会明显拉低整体配送体验。

如果这类"远距离/超时长"订单的占比不低,就需要考虑是否要加收配送费,或者适当调整配送覆盖范围。

5. 计算百分位数

百分位数比均值更能看清分布。四分位数最常用:Q1 是 25% 分位,Q2 是中位数,Q3 是 75% 分位。

con.sql("""
SELECT
  QUANTILE_CONT(amount, 0.25) AS q1_amount,
  QUANTILE_CONT(amount, 0.50) AS median_amount,
  QUANTILE_CONT(amount, 0.75) AS q3_amount,
  QUANTILE_CONT(delivery_min, 0.25) AS q1_delivery_min,
  QUANTILE_CONT(delivery_min, 0.50) AS median_delivery_min,
  QUANTILE_CONT(delivery_min, 0.75) AS q3_delivery_min,
  QUANTILE_CONT(distance_km, 0.25) AS q1_distance,
  QUANTILE_CONT(distance_km, 0.50) AS median_distance,
  QUANTILE_CONT(distance_km, 0.75) AS q3_distance
FROM orders
""").df()
指标 Q1 中位数 Q3
金额 19.775 29.15 44.675
配送时长 22.0 28.0 36.0
配送距离 1.4 2.2 3.3

这说明:

  • 一半订单金额在 约 20 到 45 元 之间(Q1≈19.8 元,Q3≈44.7 元);
  • 75% 的订单金额低于 约 45 元;
  • 75% 的订单配送时长在 36 分钟 以内;
  • 75% 的订单配送距离在 3.3 公里 以内。

这些数字可以直接用来做决策:重点服务 3.3 公里以内(75% 的订单都在这范围内),超过这个距离可以加配送费;满减门槛可以围绕 45 元 附近设计,而不是拍脑袋定。

6. 总结与建议

DuckDB 在这类场景里很顺手:

  • 直接查 CSV,不用建表、不用导库;
  • SQL 写起来清楚,多个统计指标一次查完;
  • 输出 .df() 就能继续用 pandas、matplotlib;
  • 数据大一点也不虚,列式引擎,聚合快;
  • 改条件快,加个 WHERE 就能只看某天、某品类、某门店。

描述性统计不是终点,但它是理解数据的第一步。

先算清楚均值、中位数、标准差、范围和四分位数,再决定下一步怎么分析。

比如继续 GROUP BY category 看品类,或者 date_trunc('day', order_time) 看每天趋势。

DuckDBSQL 很快,适合这种快速探索。

posted @ 2026-09-23 13:04  wang_yb  阅读(30)  评论(0)    收藏  举报