【问题标题】:"recycling" error in user-defined function for data.tabledata.table 的用户定义函数中的“回收”错误
【发布时间】:2020-12-28 03:02:34
【问题描述】:

我已加入两个数据表,并正在根据该数据的子集计算平均值。当下面的代码不在我编写的函数中时,它可以正常运行,但是当我尝试使用该函数时出现此错误:

Error in `[.data.table`(poll.name, AQ.Date >= Cdate & AQ.Date < Cdate +  : 
  i evaluates to a logical vector length 159 but there are 2797432 rows. Recycling of logical i is no longer allowed as it hides more bugs than is worth the rare convenience. Explicitly use rep(...,length=.N) if you really need to recycle.

我的功能:

 myfunc <- function(linked.dat, poll.name) {

  linked.dat[,
        `:=` (t1.avg = mean(poll.name[AQ.Date >= Cdate & AQ.Date < Cdate + 1], na.rm = TRUE),
              t2.avg = mean(poll.name[AQ.Date >= Cdate + 1 & AQ.Date < Cdate + 2], na.rm = TRUE),
              t3.avg = mean(poll.name[AQ.Date >= Cdate + 2 & AQ.Date <= Bdate], na.rm = TRUE),
              total.avg = mean(poll.name)),
        by = ID]

  linked.pollname <- linked.dat

  return(linked.pollname)

}

因此,在示例 df 中使用此函数如下所示:

myfunc(df, O3) 

一些数据:

df <- structure(list(O3 = c(21.1, 27.3, 23.8, 29.5, 23.8, 27.1, 31.6, 
25.8, 31.2, 14, 19.1, 15.5, 15.6, 28.6, 16.9, 27.4, 30.1, 24.4, 
21.2, 22.1, 26.1, 19.9), AQ.Date = structure(c(3679, 3681, 3682, 
3683, 3680, 3685, 3686, 3687, 3684, 3689, 3673, 3675, 3677, 3678, 
3686, 3687, 3688, 3692, 3681, 3693, 3695, 3696), class = "Date"), 
    ID = c("a", "a", "a", "a", "a", "a", "a", "a", "a", "a", 
    "a", "a", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b"
    ), Cdate = structure(c(3673, 3673, 3673, 3673, 3673, 
    3673, 3673, 3673, 3673, 3673, 3673, 3673, 3677, 3677, 3677, 
    3677, 3677, 3677, 3677, 3677, 3677, 3677), class = "Date"), 
    Bdate = structure(c(3690, 3690, 3690, 3690, 3690, 3690, 
    3690, 3690, 3690, 3690, 3690, 3690, 3696, 3696, 3696, 3696, 
    3696, 3696, 3696, 3696, 3696, 3696), class = "Date"), Total_weeks = c(2.428571, 
    2.428571, 2.428571, 2.428571, 2.428571, 2.428571, 2.428571, 
    2.428571, 2.428571, 2.428571, 2.428571, 2.428571, 2.714286, 
    2.714286, 2.714286, 2.714286, 2.714286, 2.714286, 2.714286, 
    2.714286, 2.714286, 2.714286)), row.names = c(NA, -22L), class = "data.frame")

setDT(df) 

我不明白这个错误是什么意思。回收指的是什么?为什么它只发生在函数内?如何调整功能以解决错误?

【问题讨论】:

  • 在不知道您的数据是什么样子的情况下,很难就这个问题为您提供具体的帮助。请让这个问题可重现。这包括样本明确数据(例如,dput(head(x))data.frame(x=...,y=...)),可能还有给定输入的预期输出。参考:stackoverflow.com/q/5963269minimal reproducible examplestackoverflow.com/tags/r/info。谢谢!
  • 您的问题的一个问题(可能是一般问题)是您对myfunc 的调用有一个O3符号,R 试图解决这个问题。就我而言,它什么也没找到,因此很快就会出现找不到对象的错误。但是,如果您在调用(或父)框架中有一个名为 O3 的对象,那么您所做的比我认为您打算做的要多得多。如果我改为使用myfunc(df, "O3"),则会收到错误fastmean was passed type character, not numeric or logicaldata.table 的东西),这表明您使用O3 符号是为了在df 内解析。
  • 您似乎更多地尝试进行非标准评估,但在 data.table 构造之外,这不起作用。
  • 查看我的答案的编辑,我怀疑如果不够的话它更接近。

标签: r function datatable


【解决方案1】:

一般回收

回收与如何将不同长度的向量组合成data.frame(和其他一些地方)有关。 data.frame 的每一列(以及 data.tabletbl_df)的每一列都必须具有相同的长度,如果长度不同,它就会被回收

在大多数(全部?)基本 R 函数中,只要最长的向量是较短向量的偶数倍,回收就会静默完成。例如,

data.frame(x = 1, y = 1:3)
#   x y
# 1 1 1
# 2 1 2
# 3 1 3
data.frame(x = 1:2, y = 1:4)
#   x y
# 1 1 1
# 2 2 2
# 3 1 3
# 4 2 4

但是当提供非偶数组合时,R 会出错(通常,但并非在所有情况下):

data.frame(x = 1:3, y = 1:4)
# Error in data.frame(x = 1:3, y = 1:4) : 
#   arguments imply differing number of rows: 3, 4

我个人的看法是,回收是方便和安全之间的平衡,这里的“方便”是我想在多行的框架中添加一个具有单个不变值的列,如上面的第一个示例; “安全”是您确定每个函数返回的内容(例如长度)并且没有隐藏惊讶。

对于后者,请考虑一个自定义函数(旨在模仿 which.min)来查找最小值的位置:

myfunc <- function(x) which(x == min(x)) # this is naive, do not use it

对于“正常”数据,它将返回单个值,如

set.seed(42)
myfunc(runif(10))
# [1] 8

但是,也许在处理整数或其他可能发生相等的事情时(以及在一些罕见的numeric 实例中),一个可能会得到多个:

myfunc(sample(10, size = 11, replace = TRUE))
# [1]  2 10

因此,如果您依赖它返回单个值,但它返回两个或更多值,那么......您所依赖的东西可能会进行静默回收,而您并不明智。例如,

set.seed(3)
mydat <- data.frame(x = sample(10, size = 12, replace = TRUE))
mydat$y <- myfunc(mydat$x)
mydat
#     x y
# 1   5 4
# 2  10 8
# 3   7 4
# 4   4 8
# 5  10 4
# 6   8 8
# 7   8 4
# 8   4 8
# 9  10 4
# 10  7 8
# 11  8 4
# 12  8 8

从我的角度来看,只有当它是一个全或一的事情时,回收才是“可接受的”......其他任何东西都可以在很多地方正确使用,但在我看来应该是明确的。

tibble 允许全或 1,否则会出错:

library(tibble)
tibble(x = 1, y = 1:3)
# # A tibble: 3 x 2
#       x     y
#   <dbl> <int>
# 1     1     1
# 2     1     2
# 3     1     3
tibble(x = 1:2, y = 1:3)
# Error: Tibble columns must have compatible sizes.
# * Size 2: Existing data.
# * Size 3: Column `y`.
# i Only values of size one are recycled.

针对您的问题

您正在尝试在 data.table 构造之外对符号 O3 进行非标准评估。我相信您打算根据其他条件取用户提供的框架列的平均值。

这是解决此问题的一种方法:传递一个字符串,然后在data.table 中使用get(poll.name)(无论您需要数据的地方)来获取数据:

myfunc <- function(linked.dat, poll.name) {
  linked.dat[,
             `:=` (t1.avg = mean(get(poll.name)[AQ.Date >= Cdate & AQ.Date < Cdate + 1], na.rm = TRUE),
                   t2.avg = mean(get(poll.name)[AQ.Date >= Cdate + 1 & AQ.Date < Cdate + 2], na.rm = TRUE),
                   t3.avg = mean(get(poll.name)[AQ.Date >= Cdate + 2 & AQ.Date <= Bdate], na.rm = TRUE),
                   total.avg = mean(get(poll.name))),
             by = ID]

  linked.pollname <- linked.dat

  return(linked.pollname)
}

myfunc(df, "O3") 
#       O3    AQ.Date ID      Cdate      Bdate Total_weeks t1.avg t2.avg   t3.avg total.avg
#  1: 21.1 1980-01-28  a 1980-01-22 1980-02-08    2.428571   19.1    NaN 24.60909     24.15
#  2: 27.3 1980-01-30  a 1980-01-22 1980-02-08    2.428571   19.1    NaN 24.60909     24.15
#  3: 23.8 1980-01-31  a 1980-01-22 1980-02-08    2.428571   19.1    NaN 24.60909     24.15
#  4: 29.5 1980-02-01  a 1980-01-22 1980-02-08    2.428571   19.1    NaN 24.60909     24.15
#  5: 23.8 1980-01-29  a 1980-01-22 1980-02-08    2.428571   19.1    NaN 24.60909     24.15
# ---                                                                                      
# 18: 24.4 1980-02-10  b 1980-01-26 1980-02-14    2.714286   15.6   28.6 23.51250     23.23
# 19: 21.2 1980-01-30  b 1980-01-26 1980-02-14    2.714286   15.6   28.6 23.51250     23.23
# 20: 22.1 1980-02-11  b 1980-01-26 1980-02-14    2.714286   15.6   28.6 23.51250     23.23
# 21: 26.1 1980-02-13  b 1980-01-26 1980-02-14    2.714286   15.6   28.6 23.51250     23.23
# 22: 19.9 1980-02-14  b 1980-01-26 1980-02-14    2.714286   15.6   28.6 23.51250     23.23

【讨论】:

  • 接近了吗?
  • 您好,我今天测试了它,当我去掉linked.pollname &lt;- linked 并将其更改为return(linked) 时,它似乎可以工作。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-27
  • 2022-07-19
  • 1970-01-01
  • 2018-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多