使用累计的输出差异

Fus*_*cho 7 r lubridate cumsum

为什么这两个操作不同?

library(lubridate)
library(magrittr)

> seconds_to_period(1:1000) %>% cumsum %>% sum
[1] 14492440
> 1:1000 %>% cumsum %>% sum
[1] 167167000
Run Code Online (Sandbox Code Playgroud)

但是,我看到的问题是,该事实cumsum 仅增加了周期的秒数,而忽略了其余的时间

seconds_to_period(60) +  seconds_to_period(60)
[1] "2M 0S"
Run Code Online (Sandbox Code Playgroud)

> cumsum(c(seconds_to_period(60), seconds_to_period(60)))
[1] 0 0
Run Code Online (Sandbox Code Playgroud)

为什么此行为是默认形式?我认为这很不直观。此外,克服此问题并获得与cumsum(1:1000)使用“ Period”类润滑脂相同的结果的方法是什么,该方法不需要执行以下操作:

c(seconds_to_period(60), seconds_to_period(60)) %>% as.numeric %>% cumsum

Loc*_*ris 6

作为cumsum原始对象,您可以在这里https://github.com/Microsoft/microsoft-r-open/blob/master/source/src/main/cum.c看到R它在做什么。此外,如果您从第215行读到:

PROTECT(t = coerceVector(CAR(args), REALSXP));
    n = XLENGTH(t);
    PROTECT(s = allocVector(REALSXP, n));
    setAttrib(s, R_NamesSymbol, getAttrib(t, R_NamesSymbol));
    UNPROTECT(2); 
Run Code Online (Sandbox Code Playgroud)

这是从开始period到结束的强制numeric,因为周期的结构,它只是保持.Data

比较

seconds_to_period(60)@.Data
seconds_to_period(59)@.Data
Run Code Online (Sandbox Code Playgroud)

因此,在C级别,R 强制执行数据as.numeric,而是更快,更有效(但是您可能会说得不太细微,因为它没有.Data像从中那样实现其他元素as.numeric)。

看起来像这样:

 setClass("Foo", representation(.Data="numeric", number1 = "numeric", number2 = "numeric"))

 bar <- new("Foo",.Data=5, number1 = 12, number2 = 31)

 cumsum(bar) 
Run Code Online (Sandbox Code Playgroud)

结果为5,因为它仅强制 numeric Data

此外:

 setClass("Foo2", representation(.Data="numeric", number1 = "numeric", number2 = "numeric"))

 bar2 <- new("Foo2", number1 = 12, number2 = 31)

 cumsum(bar2) 
Run Code Online (Sandbox Code Playgroud)

还给你,numeric(0)因为没有.Data

 setClass("Foo3", representation( number1 = "numeric", number2 = "numeric"))

 bar3 <- new("Foo3", number1 = 12, number2 = 31)

 cumsum(bar3) 
Run Code Online (Sandbox Code Playgroud)

这根本不起作用:在.Data内部,如果没有R,则R不知道numeric在执行该操作时如何强制它cumsum

所以:这是因为R内部如何处理复杂的S4对象。您总是可以告诉lubridate人们创建一个新参数seconds,并将其存储在.Data整个S4对象的累积秒数中。我想这种方式cumsum会起作用。但是现在,.Data用来存储第二个参数。见edit(seconds_to_period)

function (x) 
{
  span <- as.double(x)
  remainder <- abs(span)
  newper <- period(second = rep(0, length(x)))
  slot(newper, "day") <- remainder%/%(3600 * 24)
  remainder <- remainder%%(3600 * 24)
  slot(newper, "hour") <- remainder%/%(3600)
  remainder <- remainder%%(3600)
  slot(newper, "minute") <- remainder%/%(60)
  slot(newper, ".Data") <- remainder%%(60)
  newper * sign(span)
}
Run Code Online (Sandbox Code Playgroud)

最后,只是为了好玩。这是我cumsum在这里如何工作的模拟版本:

setClass("Period2",representation(.Data="numeric", period="Period"))


seconds_to_period_2 <- function(x){
   (lapply(x, function(y) new("Period2", .Data=y, period=seconds_to_period(y))))
}

a<-seconds_to_period_2(1:60)

cumsum(a)
Run Code Online (Sandbox Code Playgroud)

最好!

  • 我为这个社区感到非常自豪,并能像这样回答。我从中学到了很多,谢谢! (2认同)