我有这样的数据:
ID ATTRIBUTE START END
1 A 01-01-2000 15-03-2010
1 B 05-11-2001 06-02-2002
2 B 01-02-2002 08-05-2008
2 B 01-06-2008 01-07-2008
Run Code Online (Sandbox Code Playgroud)
我现在想要计算每年具有特定属性的不同ID的数量.
结果可能如下所示:
YEAR count(A) count(B)
2000 1 0
2001 1 1
2002 1 2
2003 1 1
2004 1 1
2005 1 1
2006 1 1
2007 1 1
2008 1 1
2009 1 0
2010 1 0
Run Code Online (Sandbox Code Playgroud)
我计算出现次数的第二步可能很容易.
但是,我如何将数据分成多年?
先感谢您!
这是一种使用Hadley的一些包的方法.
library(lubridate); library(reshape2); library(plyr)
# extract years from start and end dates after converting them to date
dfr2 = transform(dfr, START = year(dmy(START)), END = year(dmy(END)))
# for every row, construct a sequence of years from start to end
dfr2 = adply(dfr2, 1, transform, YEAR = START:END)
# create pivot table of year vs. attribute with number of unique values of ID
dcast(dfr2, YEAR ~ ATTRIBUTE, function(x) length(unique(x)), value_var = 'ID')
Run Code Online (Sandbox Code Playgroud)
编辑:如果原件data.frame很大,那么adply可能需要花费很多时间.在这种情况下,有用的替代方法是使用该data.table包.以下是我们如何adply使用替换呼叫data.table.
require(data.table)
dfr2 = data.table(dfr2)[,list(YEAR = START:END),'ID, ATTRIBUTE']
Run Code Online (Sandbox Code Playgroud)
这是一个只使用R核心的解决方案.首先,我们显示输入数据以保持全部自包含:
DF <- data.frame(ID = c(1, 1, 2, 2),
ATTRIBUTE = c("A", "B", "B", "B"),
START = c("01-01-2000", "05-11-2001", "01-02-2002", "01-06-2008"),
END = c("15-03-2010", "06-02-2002", "08-05-2008", "01-07-2008"))
Run Code Online (Sandbox Code Playgroud)
现在我们有输入解决方案如下: yr定义为提取年份的函数.计算的内容是遵循定义的陈述yr.对于每一行DF的匿名函数产生具有年的数据帧在列1跨越和ATTRIBUTE和ID在2列和3.例如,对应于第一行中的数据帧DF是11行data.frame(YEAR = 2000:2010, ATTRIBUTE = 1, ID = "A")和对应于该数据帧第二排DF是两排data.frame(YEAR = 2001:2002, ATTRIBUTE = 1, ID = "B").该lapply对中的每一行产生这样的数据帧的列表,一个DF以上它产生与4个分量的列表中的示例输入左右.使用do.call我们rbind该名单的组成部分,即个人数据帧,产生一个大的数据帧.我们unique从这个大型数据框中删除重复行(使用),删除ID列(第三列)并运行table结果:
yr <- function(d) as.numeric(sub(".*-", "", d))
out <- table(unique(do.call(rbind, lapply(1:nrow(DF), function(r) with(DF[r, ],
data.frame(YEAR = seq(yr(START), yr(END)), ATTRIBUTE, ID)))))[, -3])
Run Code Online (Sandbox Code Playgroud)
结果表是:
> out
ATTRIBUTE
YEAR A B
2000 1 0
2001 1 1
2002 1 2
2003 1 1
2004 1 1
2005 1 1
2006 1 1
2007 1 1
2008 1 1
2009 1 0
2010 1 0
Run Code Online (Sandbox Code Playgroud)
编辑:
海报后来表明内存可能是一个问题所以这里是一个sqldf解决方案,它处理R之外的sqlite中的关键大中间结果(dbname = tempfile()告诉它这样做)所以R的任何内存限制都不会影响它.它使用与yr上面显示的相同的输入和相同的功能并返回相同的结果,tab与out上面相同.也可以尝试它dbname = tempfile(),以防它实际上适合在内存中.
library(sqldf)
DF2 <- transform(DF, START = yr(START), END = yr(END))
years <- data.frame(year = min(DF2$START):max(DF2$END))
tab.df <- sqldf("select year, ATTRIBUTE, count(*) as count from
(select distinct year, ATTRIBUTE, ID
from years, DF2
where year between START and END)
group by year, ATTRIBUTE", dbname = tempfile())
tab <- xtabs(count ~., tab.df)
Run Code Online (Sandbox Code Playgroud)