使用DuckDB关系型API实现包含NULL值的唯一值计数聚合(n_unique)
DuckDB关系型API实现包含NULL值的唯一值计数聚合(n_unique)
我明白你的需求啦——想用DuckDB的Relational API统计包含NULL在内的唯一值数量,之前的方案因为array_agg默认忽略NULL,导致结果没把NULL算进去。咱们调整一下就能解决这个问题!
问题根源
原来的方法里,array_agg函数默认会跳过NULL值,所以哪怕后面用array_unique去重,也没法把NULL当作一个独立的唯一值统计进来。想要包含NULL,核心就是让array_agg把NULL也收集到数组里。
修正后的解决方案
我们只需要给array_agg加上ignore_nulls=False的参数,确保NULL被纳入聚合数组,再通过array_unique去重(DuckDB的array_unique会把NULL视为一个独立元素),最后用array_length得到去重后的数量:
import duckdb def n_unique(column_name: str) -> duckdb.Expression: # 1. 聚合列的所有值(包含NULL)到数组 agg_with_nulls = duckdb.FunctionExpression( 'array_agg', duckdb.ColumnExpression(column_name), ignore_nulls=False # 关键参数:不忽略NULL ) # 2. 对数组去重(NULL会被保留为一个唯一值) unique_array = duckdb.FunctionExpression('array_unique', agg_with_nulls) # 3. 返回去重后数组的长度,也就是唯一值的总数 return duckdb.FunctionExpression('array_length', unique_array)
测试验证
用你给出的测试数据跑一下:
rel = duckdb.sql('select * from values (1, 4), (2, null), (null, null) df(a, b)') result = rel.aggregate([n_unique('a').alias('unique_a'), n_unique('b').alias('unique_b')]) print(result)
输出结果完全符合你的预期:
┌──────────┬──────────┐ │ unique_a │ unique_b │ │ int64 │ int64 │ ├──────────┼──────────┤ │ 3 │ 2 │ └──────────┴──────────┘
这里unique_a统计了1、2、NULL三个唯一值,unique_b统计了4、NULL两个唯一值,完美包含了NULL的情况!
备注:内容来源于stack exchange,提问作者ignoring_gravity
相关产品推荐
相关产品推荐

