表reg_data
是PostgreSQL表。事实证明,在PostgreSQL中运行回归更快。但是,当我运行数十万个数据集时,我希望按数据集执行数据集并将每个数据的结果附加到表中。
有没有办法使用原生dplyr
动词将PostgreSQL数据附加到PostgreSQL表?我不确定将数据带到R然后将它们发送回PostgreSQL(只有6个数字和几个识别字段)需要付出巨大的代价,但它确实看起来不够优雅。
library(dplyr)
pg <- src_postgres()
reg_data <- tbl(pg, "reg_data")
reg_results <-
reg_data %>%
summarize(r_squared=regr_r2(y, x),
num_obs=regr_count(y, x),
constant=regr_intercept(y, x),
slope=regr_slope(y, x),
mean_analyst_fog=regr_avgx(y, x),
mean_manager_fog=regr_avgy(y, x)) %>%
collect() %>%
as.data.frame()
# Push to database.
dbWriteTable(pg$con, c("bgt", "within_call_data"), reg_results,
append=TRUE, row.names=FALSE)
答案 0 :(得分:4)
dplyr
不包含在数据库中插入或更新记录的命令,因此没有完整的原生dplyr
解决方案。但是你可以将dplyr与常规SQL语句结合起来,以避免将数据带到R.
让我们从collect()
陈述
library(dplyr)
pg <- src_postgres()
reg_data <- tbl(pg, "reg_data")
reg_results <-
reg_data %>%
summarize(r_squared=regr_r2(y, x),
num_obs=regr_count(y, x),
constant=regr_intercept(y, x),
slope=regr_slope(y, x),
mean_analyst_fog=regr_avgx(y, x),
mean_manager_fog=regr_avgy(y, x))
现在,您可以使用compute()
代替collect()
在数据库中创建临时表。
temp.table.name <- paste0(sample(letters, 10, replace = TRUE), collapse = "")
reg_results <- reg_results %>% compute(name=random.table.name)
其中temp.table.name
是随机表名称。在计算中使用选项name= temp.table.name
,我们将此随机名称分配给创建的临时表。
现在,我们将使用库RPostgreSQL
创建一个插入查询,该查询使用临时表中存储的结果。由于临时表仅存在于src_postgresql()
创建的连接中,我们需要重用它。
library(RPostgreSQL)
copyconn <- pg$con
class(copyconn) <- "PostgreSQLConnection" # I get an error if I don't fix the class
最后插入查询
sql <- paste0("INSERT INTO destination_table SELECT * FROM ", temp.tbl.name,";")
dbSendQuery(copyconn, sql)
因此,一切都在数据库中发生,数据不会被带入R。
修改强>
当我们从temp.tbl.name
获取reg_results
时,此帖子的早期版本确实打破了封装。使用计算中的name=
选项可以避免这种情况。
答案 1 :(得分:2)
另一种选择是使用一个名为sql_render()
的命令来创建每个SQL语句,然后使用另一个名为db_save_query()
的命令来使用SQL语句创建表,然后使用手动语句来附加到表。要遍历每个查询,请使用purrr
命令:map
和walk
。优选地,像compute()
命令这样的命令应该这样做,但是代替它,以下是完全可重现的示例:
library(dplyr)
library(dbplyr)
library(purrr)
# Setting up a SQLite db with 3 tables
con <- DBI::dbConnect(RSQLite::SQLite(), path = ":memory:")
copy_to(con, filter(mtcars, cyl == 4), "mtcars1")
copy_to(con, filter(mtcars, cyl == 6), "mtcars2")
copy_to(con, filter(mtcars, cyl == 8), "mtcars3")
# Pre-process the SQL statements
tables <- c("mtcars1","mtcars2","mtcars3")
all_results <- tables %>%
map(~{
tbl(con, .x) %>%
summarise(avg_mpg = mean(mpg),
records = n()) %>%
sql_render()
})
# Execute the SQL statements, 1st one creates the table
# subsquent queries are insterted to the table
first_query <- TRUE
all_results %>%
walk(~{
if(first_query == TRUE){
first_query <<- FALSE
db_save_query(con, ., "results")
} else {
dbExecute(con, build_sql("INSERT INTO results ", .))
}
})
tbl(con, "results")
dbDisconnect(con)