按时间和按组聚合功能

时间:2016-05-15 20:31:56

标签: r time aggregate

我正在尝试使用每年的时间和类型构建堆积条。 我的数据库mat(head)看起来像

head(mat)

  year flights.type flights.duration
1 2000         HR20         01:12:00
2 2000         HR20         02:00:00
3 2000           L4         00:54:00
4 2000           L4         00:42:00
5 2000           L4         00:22:00
6 2000         HR20         00:24:00

我想按年份和类型对flight.duration求和,然后构建一个堆积条。

我尝试使用函数聚合但是随着时间的推移,它无法正常工作。谁能帮我?按年份和类型划分的总和如下:

aggregate(mat$flights.duration,format(.POSIXct(mat$flights.duration,tz="GMT"), "%H:%M:%S"),FUN=sum, by=list(mat$year))

3 个答案:

答案 0 :(得分:2)

使用data.table包和as.difftime()函数的解决方案:

library(data.table)
setDT(mat)[, .(flights.duration.minutes = sum(as.difftime(as.character(flights.duration)))), 
              .(year, flights.type)]

   year flights.type flights.duration.minutes
1: 2000         HR20                 216 mins
2: 2000           L4                 118 mins

答案 1 :(得分:1)

您可以将Collective\Html\HtmlServiceProvider::class, 列转换为数字分钟值,如下所示:

'Collective\Html\HtmlServiceProvider',

然后,使用分组功能,例如来自flights.duration包的功能,如下所示:

df$flights.duration <- apply(df, 1, function(x) {
                               sum(as.numeric(unlist(strsplit(x[3], ':'))) * c(60, 1, 0))
                         })

输出如下:

dplyr

编辑:使用library(dplyr) df %>% group_by(year, flights.type) %>% summarise(flights.duration = sum(flights.duration)) 软件包Source: local data frame [2 x 3] Groups: year [?] year flights.type flights.duration <int> <chr> <dbl> 1 2000 HR20 216 2 2000 L4 118 而不是上面的tidyr函数添加可能更快的其他选项行:

separate

结果与之前相同:

apply

答案 2 :(得分:0)

lubridate包被广泛认为是R中可用的最佳日期/时间包。它基于R DatePOSIXct基类型,并添加了自己的Interval包1}},DurationPeriod类型。

普通hh:mm:ss次最合适的数据类型是Period类型。从理论上讲,应该可以将字符串时间解析为Period值,然后使用sum()执行直接分组aggregate()

不幸的是,事实证明这是一项比人们希望的要困难得多的任务。我最终得到了它,但它需要一些扭曲。

首先,这里是如何将字符串时间解析为Period值。 lubridate提供了一种方便的hms()方法来执行此操作:

df <- data.frame(year=c(2000L,2000L,2000L,2000L,2000L,2000L),flights.type=c('HR20','HR20','L4','L4','L4','HR20'),flights.duration=c('01:12:00','02:00:00','00:54:00','00:42:00','00:22:00','00:24:00'),stringsAsFactors=F);

library(lubridate);
df$flights.duration <- hms(df$flights.duration);

df;
##   year flights.type flights.duration
## 1 2000         HR20        1H 12M 0S
## 2 2000         HR20         2H 0M 0S
## 3 2000           L4           54M 0S
## 4 2000           L4           42M 0S
## 5 2000           L4           22M 0S
## 6 2000         HR20           24M 0S

其次,遗憾的是,lubridate似乎没有为sum()类型提供Period方法:

sum(df$flights.duration);
## [1] 0

(如果你想知道它返回零的原因,Period类型是通过将秒字段存储为矢量的有效载荷(双重类型)和剩余字段(分钟数)来实现的。 ,小时,天,月,年)存储为插槽,也是双重类型。df$flights.duration中的所有值都有零秒,基本sum()函数只能看到矢量有效负载,所以它会求和为零。)

我尝试使用S3方法自己填补这个空白,但很快发现它不起作用,因为Period类型是S4类型。所以我写了这个S4方法:

setMethod('sum',signature(x='Period',na.rm='logical'),function(x,na.rm=FALSE) period(seconds=sum(as.double(x),na.rm=na.rm),minutes=sum(x@minute,na.rm=na.rm),hours=sum(x@hour,na.rm=na.rm),days=sum(x@day,na.rm=na.rm),months=sum(x@month,na.rm=na.rm),years=sum(x@year,na.rm=na.rm)));
## [1] "sum"

sum(df$flights.duration);
## [1] "3H 154M 0S"

不幸的是,还有一个问题:aggregate()默认尝试简化聚合结果,这会将S4结果展平为非S4对象,丢失插槽并破坏数据:< / p>

res <- aggregate(flights.duration~year+flights.type,df,sum);
res;
## Error in paste(x@year, "y ", x@month, "m ", x@day, "d ", x@hour, "H ",  :
##   trying to get slot "year" from an object (class "Period") that is not an S4 object
traceback();
## 8: paste(x@year, "y ", x@month, "m ", x@day, "d ", x@hour, "H ",
##        x@minute, "M ", x@.Data, "S", sep = "")
## 7: format.Period(x[[i]], ..., justify = justify)
## 6: format(x[[i]], ..., justify = justify)
## 5: format.data.frame(x, digits = digits, na.encode = FALSE)
## 4: as.matrix(format.data.frame(x, digits = digits, na.encode = FALSE))
## 3: print.data.frame(list(year = c(2000L, 2000L), flights.type = c("HR20",
##    "L4"), flights.duration = c(0, 0)))
## 2: print(list(year = c(2000L, 2000L), flights.type = c("HR20", "L4"
##    ), flights.duration = c(0, 0)))
## 1: print(list(year = c(2000L, 2000L), flights.type = c("HR20", "L4"
##    ), flights.duration = c(0, 0)))
res$flights.duration;
## [1] 0 0
## attr(,"class")
## [1] "Period"
## attr(,"class")attr(,"package")
## [1] "lubridate"
isS4(res$flights.duration);
## [1] FALSE

如您所见,aggregate()调用成功,但对象已损坏。 print.data.frame()方法在列上失败,因为它恰好在其上调用format(),它调度到S3方法format.Period(),这是lubridate命名空间下的私有方法。它在损坏的对象上失败。

我们可以防止简化:

res <- aggregate(flights.duration~year+flights.type,df,sum,simplify=F);
res;
##   year flights.type flights.duration
## 1 2000         HR20                0
## 2 2000           L4                0
res$flights.duration;
## $`1`
## [1] "3H 36M 0S"
##
## $`4`
## [1] "118M 0S"
##

从技术上讲,它有效,但该列现在是列表类型,这并不理想。它也不再显示出来;我们只是在显示为data.frame的一部分时看到零。

我们可以通过手动转换列来组合列表组件来解决此问题。不幸的是,unlist()do.call(c,...)的明显方法不起作用:

res <- transform(aggregate(flights.duration~year+flights.type,df,sum,simplify=F),flights.duration=do.call(c,flights.duration));
res;
##   year flights.type flights.duration
## 1 2000         HR20                0
## 2 2000           L4                0
res$flights.duration;
## [1] 0 0
isS4(res$flights.duration);
## [1] FALSE

Period值列表变为平面向量,类似于aggregate()完成的简化效果。

问题似乎是列表名称,这会阻止c()调用按预期运行。我们可以使用unname()解决此问题。所以这是最终的解决方案:

res <- transform(aggregate(flights.duration~year+flights.type,df,sum,simplify=F),flights.duration=do.call(c,unname(flights.duration)));
res;
##   year flights.type flights.duration
## 1 2000         HR20        3H 36M 0S
## 2 2000           L4          118M 0S

所以,虽然我们最终到达那里,但我不推荐这个解决方案。 R生态系统的不同派系之间存在太多的复杂性,功能上的差距以及不协调的相互作用。

相关问题