用 dbplyr 总结的五位数

Posted

技术标签:

【中文标题】用 dbplyr 总结的五位数【英文标题】:Five figures summary with dbplyr 【发布时间】:2020-11-26 14:13:54 【问题描述】:

我有 4 年的 R 使用经验,但我对大数据游戏非常陌生,因为我一直在处理 csv 文件。

从远处操纵大量数据令人兴奋,但也不知何故令人沮丧,因为您习惯于重新设计一些简单的事情。

我现在正在努力的任务是对变量进行基本的 5 位数摘要:

summary(df$X)

一些上下文,我与 impala 连接,这些代码行工作正常:

library(dbplyr)
localTable <- tbl(con, 'serverTable')
localTable %>% tally()
localTable %>% filter(X > 10) %>% tally()

如果我只是写

localTable

相反,RStudio 卡住/需要很多时间,所以我使用任务管理器将其抑制。

回到我当前的问题,我尝试通过以下方式进行 5 位数的摘要:

summary(localTable$X) #returns Length 0, Class NULL, Mode NULL
localTable %>% fivenum(X) #returns Error in rank(x, ties.method = "min", na.last = "keep") : unimplemented type 'list' in 'greater'

还使用 summarise 构建自定义 summary()

localTable %>% summarize(Min = min(X),
         Q1 = quantile(X, .25),
         Avg = mean(X), 
         Q3 = quantile(X, .75),
         Max = max(X))

返回一个语法错误。

我的猜测是,我的代码和服务器之间以数据结构的形式存在一个非常微不足道的缺失链接,但我无法弄清楚是什么。

我也尝试将 localTable$x 保存到内存变量中

XL <- localTable$X

但我总是得到一个 NULL

在图形方面,使用 dbplot,如果我尝试的话

library(dbplot)
localTable %>% dbplot_histogram(X)

我得到一个空图形。

我曾考虑在 boxplot 函数中使用 5 位数字摘要,可以这么说,ggplotbuild(object)$data,但是使用 dbplot_boxplot 我得到错误找不到函数“dbplot_boxplot”。

我开始使用 dbplyr 是因为我对 dplyr 非常熟悉,并且我不想使用 DBI::dbGetQuery 在 SQL 中编写查询,但是您可以建议其他软件包,如 implyR、sparklyR 等,以及关于和我发现的一样大的主题都是非常基础的。

编辑:

根据评论中的要求,我添加了结果

str(localTable)

这是

    List of 2 
$ src:List of 2
      ..$ con  :Formal class 'Impala' [package ".GlobalEnv"] with 4 slots
      .. .. ..@ ptr     :<externalptr> 
      .. .. ..@ quote   : chr "`"
      .. .. ..@ info    :List of 15
      .. .. .. ..$ dbname                       : chr "IMPALA"
      .. .. .. ..$ dbms.name                    : chr "Impala"
      .. .. .. ..$ db.version                   : chr "2.9.0-cdh5.12.1"
      .. .. .. ..$ username                     : chr "User"
      .. .. .. ..$ host                         : chr ""
      .. .. .. ..$ port                         : chr ""
      .. .. .. ..$ sourcename                   : chr "impala connector"
      .. .. .. ..$ servername                   : chr "Impala"
      .. .. .. ..$ drivername                   : chr "Cloudera ODBC Driver for Impala"
      .. .. .. ..$ odbc.version                 : chr "03.80.0000"
      .. .. .. ..$ driver.version               : chr "2.6.11.1011"
      .. .. .. ..$ odbcdriver.version           : chr "03.80"
      .. .. .. ..$ supports.transactions        : logi FALSE
      .. .. .. ..$ getdata.extensions.any_column: logi TRUE
      .. .. .. ..$ getdata.extensions.any_order : logi TRUE
      .. .. .. ..- attr(*, "class")= chr [1:3] "Impala" "driver_info" "list"
      .. .. ..@ encoding: chr ""
      ..$ disco: NULL
      ..- attr(*, "class")= chr [1:4] "src_Impala" "src_dbi" "src_sql" "src"
     $ ops:List of 2
      ..$ x   : 'ident' chr "serverTable"
      ..$ vars: chr [1:157] "X" ...
      ..- attr(*, "class")= chr [1:3] "op_base_remote" "op_base" "op"
     - attr(*, "class")= chr [1:5] "tbl_Impala" "tbl_dbi" "tbl_sql" "tbl_lazy" ...

不确定我是否可以输入我的表格,因为它是敏感信息

【问题讨论】:

嗨@goingdeep,看起来查询没有根据summary 中的Length 0, 返回任何结果?我猜你也不能运行str(localTable) hello str(localTable) 输出 2 个列表,如果我展开它,我在 RStudio 的环境选项卡中看到的相同 您可以在您的问题中添加str(localTable) 的结果吗?在问题中显示dput(head(localTable,10)) 以提供前十行数据的样本也可能会有所帮助? 我补充说 localTable %&gt;% summarize(mean = mean(x)) 工作正常(虽然 na.rm = TRUE 不能) 那么您访问的是哪个子列表?基于str 输出,我不明白localTable %&gt;% summarize(mean = mean(x)) 如何提供任何输出,因为localTable$x 不是变量?另外,您在问题中引用了Xx 【参考方案1】:

您的帖子有很多方面。我将尝试解决主要问题。

(1) 你所称的localTable 不是本地的。您拥有的是远程表的本地访问点。它是一个远程表,因为数据存储在数据库中,而不是存储在 R 中。

要将远程表复制到本地 R 内存中,请使用 localTable = collect(remoteTable)。小心使用它。如果数据库中的表有很多 GB,那么传输到 R 的速度会很慢。此外,如果您collect 的数据库表大于 R 可用的 ram,那么您将收到内存不足错误。

我建议使用 collect 将汇总结果移动到 R 中。在数据库中进行处理和汇总,然后将结果提取到 R 中。或者,使用 remoteTable %&gt;% head(20) %&gt;% collect() 仅将前 20 行复制到 R 中。

(2) tableName$colname 不适用于远程表。在 R 中,$ 表示法允许您访问列表的命名组件。 Data.frames 是一种特殊的列表。如果您尝试data(iris) 后跟names(iris),您将获得 iris 的列名。可以使用iris$ 访问其中任何一个。

但是,正如您的 str(localTable) 所示,localTable 是长度为 2 的列表,其中第一个命名项目 src。如果你打电话给names(localTable),那么你会收到两个名字,第一个是src。这意味着你可以调用localTable$src(因为localTable$src也是一个列表,你也可以调用localTable$src$con)。

使用 dbplyr 时,R 会将数据操作命令翻译成数据库语言。为大多数 dplyr 命令定义了翻译,但没有为所有 R 命令定义翻译。

因此,仅访问特定列的推荐方法是使用来自 dplyr 的select

local_copy_of_just_one_column = remoteTable %>%
  select(required_column) %>%
  collect()

(3) 使用自定义摘要函数的方法是正确的。这是在不将数据拉入本地内存 (RAM) 的情况下生成五位数摘要的最佳方法。

语法错误的一个可能原因是您使用的 R 命令可能没有翻译成您的数据库语言。

您可以检查命令是否具有使用translate_sql 定义的翻译。我建议你试试

library(dbplyr)
translate_sql(quantile(colname, 0.25))

查看翻译的样子。

您可以使用show_query 查看整个表操作的翻译。这是我调试 SQL 翻译时的首选方法。试试:

localTable %>%
  summarize(Min = min(X),
            Q1 = quantile(X, .25),
            Avg = mean(X), 
            Q3 = quantile(X, .75),
            Max = max(X)) %>%
  show_query()

如果这没有产生有效的 SQL,那么执行该命令将会出错。

一个可能的原因是 MinMax 在 SQL 中具有特殊含义,因此可能会在您的翻译中产生奇怪的行为。

当我尝试使用 quantile 时,它看起来可能需要 SQL 中的 OVER 子句。这是使用group_by 创建的。因此,也许您想要以下内容:

localSummary = remoteTable %>%
  # create dummy column
  mutate(ones = 1) %>%
  # group to satisfy over clause
  group_by(ones) %>%
  summarise(var_min = min(var),
            var_lq = quantile(var, 0.25),
            var_mean = mean(var),
            var_uq = quantile(var, 0.75),
            var_max = max(var)) %>%
  # copy results from database into R memory
  collect()

【讨论】:

感谢 Simon 详细而彻底的回答。 - 我需要的表只有 1.5GB,我在本地复制它以防我无法从远程提取我想要的信息 - 使用 remoteTable %&gt;% head(20) %&gt;% collect() 我收到错误 Error while retrieving data from in Impala: [08S01] : ImpalaThriftAPICallFailed 。我正在调查它,但它似乎对 IT 部门来说是一件事情。 remoteTable 出现类似错误。 - local_copy_of_just_one_column = remoteTable %&gt;% select(required_column) %&gt;% collect() 我不得不中止 RStudio,因为一小时后它仍在运行。收集所有表花费了 45 分钟,但它完成了工作 - 您的摘要代码也不起作用,我得到 SYNTAX ERROR Encountered: GROUP Expected: FROM, LIMIT, ORDER, UNION, COMMA 无论如何我明白了它的要点,因为我们不能不幸在使用时忘记 SQL我希望的 dbplyr

以上是关于用 dbplyr 总结的五位数的主要内容,如果未能解决你的问题,请参考以下文章

0到7组成无重复数字的五位数,有多少个奇数

由0到4五个数字,组成5位数,每个数字用一次,但十位和百位不能为3(当然万位不能为0),输出所有可能的五位数

oracle 查询最大的五位数

用 R 中的平均值、中位数、范围和数量进行总结

Python生成随机五位数——模仿手机验证码

C语言输出一个五位数,万位和百位数字一样,前三位数字和为9,后两位