17

我经常对从关系数据库中提取的数据创建非参数统计信息(黄土、核密度等)。为了使数据管理更容易,我想将 R 输出存储回我的数据库中。使用简单的数字或文本数据框很容易做到这一点,但我还没有弄清楚如何将 R 对象存储回我的关系数据库中。那么有没有办法将内核密度向量存储回关系数据库?

现在我通过将 R 对象保存到网络驱动器空间来解决这个问题,以便其他人可以根据需要加载对象。

4

5 回答 5

15

一个非常复杂的示例 R 变量:

library(nlme)
model <- lme(uptake ~ conc + Treatment, CO2, random = ~ 1 | Plant / Type)

R 变量的最佳存储数据库方法取决于您要如何使用它。

我需要对值进行数据库内分析

在这种情况下,您需要将对象分解为数据库可以本地处理的值。这通常意味着将其转换为一个或多个数据帧。最简单的方法是使用broom包。

library(broom)
coefficients_etc <- tidy(model)
model_level_stats <- glance(model)
row_level_stats <- augment(model)

我只想要存储

在这种情况下,您想要序列化您的 R 变量。也就是说,将它们转换为字符串或二进制 blob。有几种方法可以做到这一点。


我的数据必须可以被 R 以外的程序访问,并且需要是人类可读的

您应该以跨平台文本格式存储数据;可能是 JSON 或 YAML。JSON 不支持一些重要的概念,例如Inf; YAML 更通用,但 R 中的支持并不成熟。XML 也是可能的,但是对于存储大型数组来说太冗长了。

library(RJSONIO)
model_as_json <- toJSON(model)
nchar(model_as_json) # 17916

library(yaml)
# yaml package doesn't yet support conversion of language objects,
# so preprocessing is needed
model2 <- within(
  model,
  {
     call <- as.character(call)
     terms <- as.character(terms)
  }
)
model_as_yaml <- as.yaml(model2) 
nchar(model_as_yaml) # 14493

我的数据必须可由 R 以外的程序访问,并且不需要是人类可读的

您可以将数据写入开放的跨平台二进制格式,例如 HFD5。目前对 HFD5 文件(通过rhdf5)的支持有限,因此不支持复杂对象。(你可能需要unclass一切。)

library(rhdf5)
h5save(rapply(model2, unclass, how = "replace"), file = "model.h5")
bin_h5 <- readBin("model.h5", "raw", 1e6)
length(bin_h5) # 88291 not very efficient in this case

feather包可让您以 R 和 Python 均可读取的格式保存数据帧。要使用它,您首先必须将模型对象转换为数据帧,如答案前面的扫帚部分所述。

library(feather)
library(broom)
write_feather(augment(model), "co2_row.feather")  # 5474 bytes
write_feather(tidy(model), "co2_coeff.feather")   # 2093 bytes
write_feather(glance(model), "co2_model.feather") #  562 bytes

另一种选择是将变量的文本版本(参见上一节)保存到压缩文件中,并将其字节存储在数据库中。

writeLines(model_as_json)
tar("model.tar.bz", "model.txt", compression = "bzip2")
bin_bzip <- readBin("model.tar.bz", "raw", 1e6)
length(bin_bzip) # only 42 bytes!

我的数据只需要 R 可以访问,并且需要是人类可读的

将变量转换为字符串有两种选择:serializedeparse.

p <- function(x)
{
  paste0(x, collapse = "\n")
}

serialize需要发送到文本连接,而不是写入文件,您可以写入控制台并捕获它。

 model_serialized <- p(capture.output(serialize(model, stdout())))
 nchar(model_serialized) # 23830

使用deparsewithcontrol = "all"可在稍后重新解析时最大化可逆性。

model_deparsed <- p(deparse(model, control = "all"))
nchar(model_deparsed) # 22036

我的数据只需要 R 可以访问,并且不需要是人类可读的

前面部分中显示的相同类型的技术可以在这里应用。您可以压缩序列化或解析的变量并将其作为原始向量重新读取。

serialize也可以用二进制格式写变量。在这种情况下,它最容易与它的 wrapper 一起使用saveRDS

saveRDS(model, "model.rds")
bin_rds <- readBin("model.rds", "raw", 1e6)
length(bin_rds) # 6350
于 2014-09-29T10:58:56.220 回答
12

使用序列化功能将任何 R 对象转换为(原始或字符)字符串,然后存储该字符串。见help(serialize)

将其反转以进行检索:获取字符串,然后unserialize()放入 R 对象。

于 2009-09-08T17:31:52.583 回答
10

对于sqlite(可能还有其他人):

CREATE TABLE data (blob BLOB);

现在在R

RSQLite::dbGetQuery(db.conn, 'INSERT INTO data VALUES (:blob)', params = list(blob = list(serialize(some_object)))

注意. list_ some_object的输出serialize是一个原始向量。如果没有list,将为每个向量元素执行 INSERT 语句。将其包装在列表中可以RSQLite::dbGetQuery将其视为一个元素。

要从数据库中取回对象:

some_object <- unserialize(RSQLite::dbGetQuery(db.conn, 'SELECT blob FROM data LIMIT 1')$blob[[1]])

这里发生的事情是您获取该字段blob(这是一个列表,因为 RSQLite 不知道查询将返回多少行)。由于LIMIT 1保证只返回 1 行,我们将其与[[1]]原始原始向量一起使用。然后你需要unserialize原始向量来获取你的对象。

于 2017-10-31T01:11:30.060 回答
2

使用 textConnection / saveRDS / loadRDS 可能是最通用和最高级的:

zz<-textConnection('tempConnection', 'wb')
saveRDS(myData, zz, ascii = T)
TEXT<-paste(textConnectionValue(zz), collapse='\n')

#write TEXT into SQL
...
closeAllConnections()  #if the connection persists, new data will be appended

#reading back:
#1. pull from SQL into queryResult
...
#2. recover the object
recoveredData <- readRDS(textConnection(queryResult$TEXT))
于 2017-04-20T16:08:52.473 回答
2

[100% 工作 - 2020 年 2 月 27 日]

描述:如果要将模型存储到 POSTGRES 表中,请执行以下步骤,然后查询并加载它。一个重要的部分是ascii = TRUE,否则在序列化时会产生错误

db <- pgsql_connect #connection to your database

serialized_model <- rawToChar(serialize(model_fit, NULL, ascii=TRUE))

insert_query <-'INSERT INTO table (model) VALUES ($1)'
rs <- dbSendQuery(db, insert_query, list(serialized_model))
dbClearResult(rs)

serialized_model <- dbGetQuery(db, "select model from table order by created_at desc limit 1")

model_fit2 <- unserialize(charToRaw(as.character(serialized_model[,c('model')])))
model_fit2
于 2020-02-27T22:56:29.277 回答