5

假设多年来在动物园里有每天的动物活动时间序列。一个非常大的数据集的一个子集可能如下所示:

library(data.table)
type <- c(rep('giraffe',90),rep('monkey',90),rep('anteater',90))
status <- as.factor(c(rep('display',31),rep('caged',28),rep('display',31),
rep('caged',25), rep('display',35),rep('caged',30),rep('caged',10),
rep('display',10),rep('caged',10),rep('display',60)))
date <- rep(seq.Date( as.Date("2001-01-01"), as.Date("2001-03-31"), "day" ),3)

其中“类型”是动物类型,“状态”是动物当天在做什么的指标,例如,笼中或展示。

animals <-  data.table(type,status,date);animals
         type  status       date
  1:  giraffe display 2001-01-01
  2:  giraffe display 2001-01-02
  3:  giraffe display 2001-01-03
  4:  giraffe display 2001-01-04
  5:  giraffe display 2001-01-05
 ---                            
266: anteater display 2001-03-27
267: anteater display 2001-03-28
268: anteater display 2001-03-29
269: anteater display 2001-03-30
270: anteater display 2001-03-31

假设我们想要将其聚合到一个月度系列中,该系列列出了动物及其整个月的状态信息。在新系列中,“状态”反映了动物在月初的状态。"fullmonth" 是一个二进制变量 (1=TRUE,0=FALSE),指示此状态是否保持整个月,"anydisp" 是一个二进制变量 (1=TRUE, 0= FALSE),指示动物是否在在一个月内的任何时间显示(>= 1 天)。所以,因为长颈鹿在 1 月和 3 月整整几个月都在展出,但在 2 月被关在笼子里,它会被相应地标记。

date <- rep(seq.Date( as.Date("2001-01-01"), as.Date("2001-03-31"),"month"),3)
type <- c(rep('giraffe',3),rep('monkey',3),rep('anteater',3))
status <- as.factor(c('display','caged','display','caged','display','caged',
'caged','display','display'))
fullmonth <- c(1,1,1,0,1,0,0,1,1)
anydisp <- c(1,0,1,1,1,1,1,1,1)

animals2 <- data.table(date,type,status,fullmonth,anydisp);animals2
     date     type  status fullmonth anydisp
2001-01-01  giraffe display         1   1
2001-02-01  giraffe   caged         1   0
2001-03-01  giraffe display         1   1
2001-01-01   monkey   caged         0   1
2001-02-01   monkey display         1   1
2001-03-01   monkey   caged         0   1
2001-01-01 anteater   caged         0   1
2001-02-01 anteater display         1   1
2001-03-01 anteater display         1   1

我认为zoo可能是要走的路,但是在玩了之后我发现它不能很好地处理非数字值,即使我将任意值分配给定性组件(状态),也不清楚它将如何解决问题。

##aggregate function with zoo? 
library(zoo)
animals$activity <- as.numeric(ifelse(status=='display',1,0))
animals2 <- subset(animals, select=c(date,activity))
datas <- zoo(animals2)
monthlyzoo <- aggregate(datas,as.yearmon,sum)
Error in Summary.factor(1L, na.rm = FALSE) : 
  sum not meaningful for factors

有人知道使用sqldfor的解决方案data.table吗?

更新

想要添加一个新要求,即显示的日期是当月的第一天,即使数据在当月晚些时候开始。例如,这个数据集就说明了这样一种情况:

animals2 <- animals[30:270,];head(animals2)

setkey(animals2, "type", "date")

oo <- animals2[, list(date=date[1], status = status[1],
                      fullmonth = 1 * all(status == status[1]),
                      anydisplay = any(status == "display") * 1 ),
               by = list(month(date), type)][, month := NULL]
oo

      type       date  status fullmonth anydisplay
1: anteater 2001-01-30   caged         0          1
2: anteater 2001-02-01 display         1          1
3: anteater 2001-03-01 display         1          1
4:  giraffe 2001-01-01 display         1          1
5:  giraffe 2001-02-01   caged         1          0
6:  giraffe 2001-03-01 display         1          1
7:   monkey 2001-01-01   caged         0          1 
8:   monkey 2001-02-01 display         1          1
9:   monkey 2001-03-01 display         0          1

sqldf("select 
    min(date) date, 
    type,
    status, 
    max(status) = min(status) fullmonth,
    sum(status = 'display') > 0 anydisp
from animals2
group by type, strftime('%Y %m', date * 3600 * 24, 'unixepoch')
order by type, date")

        date     type  status fullmonth anydisp
1 2001-01-30 anteater   caged         0       1
2 2001-02-01 anteater display         1       1
3 2001-03-01 anteater display         1       1
4 2001-01-01  giraffe display         1       1
5 2001-02-01  giraffe   caged         1       0
6 2001-03-01  giraffe display         1       1
7 2001-01-01   monkey   caged         0       1
8 2001-02-01   monkey display         1       1
9 2001-03-01   monkey   caged         0       1

这可以通过后处理任何解决方案来修改日期来解决:

dateswitch <- paste(year(animals2$date),month(animals2$date),1,sep='/')
dateswitch <- as.Date(dateswitch, "%Y/%m/%d")
animals2$date <- as.Date(dateswitch)
4

2 回答 2

3

像这样的东西?

setkey(animals, "type", "date")
oo <- animals[, list(date=date[1], status = status[1], 
                     fullmonth = 1 * all(status == status[1]), 
                     anydisplay = any(status == "display") * 1), 
by = list(month(date), type)][, month := NULL]
#        type       date  status fullmonth anydisplay
# 1: anteater 2001-01-01   caged         0          1
# 2: anteater 2001-02-01 display         1          1
# 3: anteater 2001-03-01 display         1          1
# 4:  giraffe 2001-01-01 display         1          1
# 5:  giraffe 2001-02-01   caged         1          0
# 6:  giraffe 2001-03-01 display         1          1
# 7:   monkey 2001-01-01   caged         0          1
# 8:   monkey 2001-02-01 display         1          1
# 9:   monkey 2001-03-01 display         0          1
于 2013-05-12T07:18:55.160 回答
2

这是一个 sqldf 解决方案:

library(sqldf)

# define input data.frame where type, status and date variables are defined in question
animals <-  data.frame(type,status,date)

sqldf("select 
    min(date) date, 
    type,
    status, 
    max(status) = min(status) fullmonth,
    sum(status = 'display') > 0 anydisp
from animals
group by type, strftime('%Y %m', date * 3600 * 24, 'unixepoch')
order by type, date")

此命令的输出以及显示的数据是:

        date     type  status fullmonth anydisp
1 2001-01-01 anteater   caged         0       1
2 2001-02-01 anteater display         1       1
3 2001-03-01 anteater display         1       1
4 2001-01-01  giraffe display         1       1
5 2001-02-01  giraffe   caged         1       0
6 2001-03-01  giraffe display         1       1
7 2001-01-01   monkey   caged         0       1
8 2001-02-01   monkey display         1       1
9 2001-03-01   monkey   caged         0       1

添加:发帖人后来在问题中添加了一项附加要求,即即使数据直到该月晚些时候才开始,也将日期显示为当月的第一天。如果DF是上面 sqldf 语句的结果,则将其转换为:

library(zoo)
transform(DF, date = as.Date(as.yearmon(date)))

或者最好删除日期部分(因为如果无论如何都没有该日期的数据,它可能会被认为具有误导性)并使用"yearmon"类给出年份和月份:

library(zoo)
transform(DF, date = as.yearmon(date))
于 2013-05-12T13:00:25.247 回答