当我们用pandas处理百万级,千万级,乃至上亿行的数据时,缓慢的速度常常让我们痛苦不堪。
这时候,不妨试试duckdb.
duckdb在本地单机即可运行,性能非常高。
它可以像spark那样使用sql语句进行数据分析和数据转换。
当处理几千万行以上的数据时,它的效率通常是pandas的几十几百倍。
公众号算法美食屋后台回复关键词:源码,获取本文notebook源代码。
duckdb个库的用法非常简单,核心API只有以下几个。
`import duckdb`
`#输入建表:可以从parquet,pandas dataframe建表`
`tb = duckdb.read_parquet('input_data.parquet')`
`tb = duckdb.from_df(df) #从pandas转换`
`#分析转换:执行sql,支持自定义函数UDF`
`tb2 = duckdb.sql('select * from tb where val>1000 and val<10000 order by val')`
`duckdb.create_function('myfunc',myfunc,[duckdb.typing.VARCHAR],duckdb.typing.VARCHAR)`
`#输出落表: 推荐导出成parquet格式,效率最高`
`tb2.to_parquet('output_data.parquet')`
`df2 = tb2.to_df() #也可以转换成pandas`
一,输入建表
`import numpy as np`
`import pandas as pd`
`import duckdb`
`#生成示例数据(5000万行)`
`dfdemo = pd.DataFrame(`
`{`
`'category': np.random.choice(list('ABCDEF'), 50000000),`
`'val': np.round(np.random.uniform(0, 1000000, 50000000), 3)`
`}`
`)`
`dfdemo.to_parquet('dfdemo.parquet', index=False)`
对比读取数据速度,duckdb比pandas快几十倍
二,SQL分析
1, 基本查询
where查询对比 (duckdb比pandas快20倍)
groupby 操作对比 (duckdb比pandas快40倍)
join 操作对比 (duckdb比pandas快600倍)
2,自定义函数UDF
pyspark的一个优点是可以在sql中使用注册自定义函数(UDF),比较灵活。
那么duckdb支持在sql中使用注册自定义函数吗?of course!
⚫️ 注册方法:使用create_function方法来注册一个Python函数作为UDF。需要提供函数名称、Python函数、参数类型和返回类型。
⚫️ 类型注解:如果Python函数有类型注解,可以省略parameters和return_type参数,DuckDB会根据注解自动推断。
⚫️ 空值处理:默认情况下,当UDF接收到NULL值时,会立即返回NULL。如果需要特殊处理,可以设置null_handling="special"。
⚫️ 异常处理:默认情况下,如果Python函数抛出异常,DuckDB会重新抛出该异常。如果希望改为返回null,可以设置exception_handling="return_null"。
⚫️ 副作用:如果UDF的结果受随机性影响,需要将side_effects设置为True。
⚫️ 使用Arrow:如果函数需要接收Arrow数组,设置type='arrow'。这会通知系统提供Arrow数组给函数,并期望函数返回相同数量的数组。
⚫️ 使用Native:当设置type='native'时,函数将按单个元组接收数据,并返回单个值。这适用于与不操作Arrow的Python库交互,如faker。
`import duckdb`
`from faker import Faker`
`def generate_random_name(i:int) -> str:`
`fake = Faker()`
`fake.random.seed(i)`
`#演示异常逻辑处理`
`#if i%10==0:`
`# raise Exception('error')`
`name = fake.name()`
`return name`
`#移除UDF`
`if 'random_name' in get_rand_funs()['function_name'].tolist():`
`duckdb.remove_function('random_name')`
`#注册UDF`
`duckdb.create_function("random_name", generate_random_name,`
`[duckdb.typing.BIGINT], duckdb.typing.VARCHAR,`
`exception_handling="return_null")`
三,输出落表
`tb\_student.to\_parquet('student.parquet')`
公众号算法美食屋后台回复关键词:源码,获取本文notebook源代码。
万水千山总是情,点个在看行不行?😋😋