使用 dbplyr 时避免算术溢出错误
Avoid arithmetic overflow error when using dbplyr
此问题与 类似,但属于总结性问题,因此发布的答案不太合适。数据是这样的,一行标识一个单位时间对:
large_sql_df
id t var1 var2
1 1 10 0
1 2 20 1
2 1 11 0
我想按 var2
和时间 t
汇总:
localdf <- large_sql_df %>%
group_by(var, t) %>%
summarise(count = n(), var1_mean = mean(var1))
这给出了错误:“将表达式转换为数据类型 int 时出现算术溢出错误。”我认为这是因为 count
变成了一个非常大的数字。有没有一种方法可以阻止这种情况发生而不必在 SQL?
中执行整个查询
算术溢出限制为 2,147,483,647(参见 here),因此这可能不是由计数引起的。它更有可能是由 mean(var1)
引起的,因为要计算平均值,计算机首先必须计算 sum(var1)
。如果您的 var1 列通常包含大于 40 的值,则可能会发生溢出错误 (40 * 350 million > 2,147,483,647)。
的解决方案也与您的问题相关:明确地将 var1 转换为更合适的格式。类似于以下内容:
localdf <- large_sql_df %>%
mutate(var1 = CAST(var1 AS FLOAT)) %>%
group_by(var, t) %>%
summarise(count = n(), var1_mean = mean(var1))
根据您的 dbplyr 版本,您可能需要 mutate(var1 = sql("CAST(var1 AS FLOAT)"))
.
有关不同数据类型的讨论,请参阅 this 问题。虽然 float 是一种不精确的数据类型,但它可以处理最大 10E38 的数字。如果您对如此大的总数取平均值,那么引入的印象不太可能很重要。
这只是阐述了来自@simon-s-a 的答案的一些要素:
library(dplyr, warn.conflicts = FALSE)
df <- read.table(header = TRUE, text = "
id t var1 var2
1 1 10 0
1 2 20 1
2 1 11 0")
large_sql_df <- dbplyr::tbl_memdb(df)
localdf <-
large_sql_df %>%
mutate(var1 = as.double(var1)) %>%
group_by(var2, t) %>%
summarise(count = n(), var1_mean = mean(var1, na.rm = TRUE),
.groups = "drop")
localdf
#> # Source: lazy query [?? x 4]
#> # Database: sqlite 3.35.5 [:memory:]
#> var2 t count var1_mean
#> <int> <int> <int> <dbl>
#> 1 0 1 2 10.5
#> 2 1 2 1 20
localdf %>% show_query()
#> <SQL>
#> SELECT `var2`, `t`, COUNT(*) AS `count`, AVG(`var1`) AS `var1_mean`
#> FROM (SELECT `id`, `t`, CAST(`var1` AS REAL) AS `var1`, `var2`
#> FROM `df`)
#> GROUP BY `var2`, `t`
由 reprex package (v2.0.0)
于 2021-07-07 创建
此问题与
large_sql_df
id t var1 var2
1 1 10 0
1 2 20 1
2 1 11 0
我想按 var2
和时间 t
汇总:
localdf <- large_sql_df %>%
group_by(var, t) %>%
summarise(count = n(), var1_mean = mean(var1))
这给出了错误:“将表达式转换为数据类型 int 时出现算术溢出错误。”我认为这是因为 count
变成了一个非常大的数字。有没有一种方法可以阻止这种情况发生而不必在 SQL?
算术溢出限制为 2,147,483,647(参见 here),因此这可能不是由计数引起的。它更有可能是由 mean(var1)
引起的,因为要计算平均值,计算机首先必须计算 sum(var1)
。如果您的 var1 列通常包含大于 40 的值,则可能会发生溢出错误 (40 * 350 million > 2,147,483,647)。
localdf <- large_sql_df %>%
mutate(var1 = CAST(var1 AS FLOAT)) %>%
group_by(var, t) %>%
summarise(count = n(), var1_mean = mean(var1))
根据您的 dbplyr 版本,您可能需要 mutate(var1 = sql("CAST(var1 AS FLOAT)"))
.
有关不同数据类型的讨论,请参阅 this 问题。虽然 float 是一种不精确的数据类型,但它可以处理最大 10E38 的数字。如果您对如此大的总数取平均值,那么引入的印象不太可能很重要。
这只是阐述了来自@simon-s-a 的答案的一些要素:
library(dplyr, warn.conflicts = FALSE)
df <- read.table(header = TRUE, text = "
id t var1 var2
1 1 10 0
1 2 20 1
2 1 11 0")
large_sql_df <- dbplyr::tbl_memdb(df)
localdf <-
large_sql_df %>%
mutate(var1 = as.double(var1)) %>%
group_by(var2, t) %>%
summarise(count = n(), var1_mean = mean(var1, na.rm = TRUE),
.groups = "drop")
localdf
#> # Source: lazy query [?? x 4]
#> # Database: sqlite 3.35.5 [:memory:]
#> var2 t count var1_mean
#> <int> <int> <int> <dbl>
#> 1 0 1 2 10.5
#> 2 1 2 1 20
localdf %>% show_query()
#> <SQL>
#> SELECT `var2`, `t`, COUNT(*) AS `count`, AVG(`var1`) AS `var1_mean`
#> FROM (SELECT `id`, `t`, CAST(`var1` AS REAL) AS `var1`, `var2`
#> FROM `df`)
#> GROUP BY `var2`, `t`
由 reprex package (v2.0.0)
于 2021-07-07 创建