dplyr连接外部数据库时如何在summarize()中使用自定义函数
问题解答:dplyr对接PostgreSQL数据库调用自定义R函数报错问题
首先翻译报错信息如下:
错误位于 postgresqlExecStatement(conn, statement, ...) : RS-DBI 驱动: (无法检索执行结果: 错误: 函数 getprecision(integer, integer) 不存在)
核心原因
dplyr对接远端数据库时,会默认将dplyr语法自动转换为对应数据库的SQL语句,直接下发到数据库端执行。你定义的getPrecision是R环境本地的自定义函数,PostgreSQL数据库端完全没有这个函数的定义,因此SQL执行时直接抛出找不到函数的错误。
另外你提供的示例代码中管道符存在书写错误,正确的管道符为%>%而非%>。
解决方案
方案1:先拉取数据到本地再计算(适合数据量不大的场景)
提前用collect()把需要的字段拉取到R本地内存后,再执行分组聚合和自定义函数,所有计算在R端完成:
getPrecision <- function(true_positive, all_positive){ if_else(sum(all_positive, na.rm = TRUE) == 0, 0, (sum(true_positive, na.rm = TRUE) / sum(all_positive , na.rm = TRUE))) } database_data %>% select(product, true_positive, all_positive) %>% # 提前筛选字段减少拉取量 collect() %>% group_by(product) %>% summarize(precision = getPrecision(true_positive, all_positive))
方案2:转换为dplyr原生语法实现计算(最优解,性能最高)
你需要的精度计算逻辑不需要封装自定义R函数,直接用dplyr原生支持的sum、if_else函数即可实现,这些函数dplyr可以自动翻译为PostgreSQL支持的SQL语法,所有计算在数据库端完成,不需要拉取全量数据:
database_data %>% group_by(product) %>% summarize( precision = if_else( sum(all_positive, na.rm = TRUE) == 0, 0, sum(true_positive, na.rm = TRUE) / sum(all_positive, na.rm = TRUE) ) ) %>% collect()
方案3:在数据库端创建同名自定义函数(适合逻辑高频复用场景)
如果你有数据库的函数创建权限,可以在PostgreSQL中用PL/pgSQL语法创建getprecision函数,这样下发的SQL就可以直接调用该函数,该方案需要适配数据库的函数编写规则,使用成本较高,非必要不推荐。
内容的提问来源于stack exchange,提问作者Karley
相关产品推荐
相关产品推荐

