按年拆分数据

spe*_*ndo 8 split r dataframe

我有这样的数据:

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)

我计算出现次数的第二步可能很容易.

但是,我如何将数据分成多年?

先感谢您!

Ram*_*ath 9

这是一种使用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)

  • 请不要传播使用`=`而不是`<-`这个糟糕的想法. (3认同)
  • 您是否看过`dcast`声明的输出?它遵循您在问题中描述的相同格式.如果这不是您想要的输出,请编辑您的问题以反映输出格式. (2认同)

G. *_*eck 6

这是一个只使用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跨越和ATTRIBUTEID在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上面显示的相同的输入和相同的功能并返回相同的结果,tabout上面相同.也可以尝试它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)