我有一个数据框,其中包含"name"位美国总统(上任和结束任职的年份)("from""to"列)。这是一个示例:

name           from  to
Bill Clinton   1993 2001
George W. Bush 2001 2009
Barack Obama   2009 2012


...以及dput的输出:

dput(tail(presidents, 3))
structure(list(name = c("Bill Clinton", "George W. Bush", "Barack Obama"
), from = c(1993, 2001, 2009), to = c(2001, 2009, 2012)), .Names = c("name", 
"from", "to"), row.names = 42:44, class = "data.frame")


我想要创建具有两列("name""year")的数据框架,总统任职期间每年都有一行。因此,我需要创建一个每年从“ from”到"to"的常规序列。这是我的期望值:

name           year
Bill Clinton   1993
Bill Clinton   1994
...
Bill Clinton   2000
Bill Clinton   2001
George W. Bush 2001
George W. Bush 2002
... 
George W. Bush 2008
George W. Bush 2009
Barack Obama   2009
Barack Obama   2010
Barack Obama   2011
Barack Obama   2012


我知道我可以使用data.frame(name = "Bill Clinton", year = seq(1993, 2001))扩展单个总统的职位,但是我不知道如何为每个总统迭代。

我该怎么做?我觉得我应该知道这一点,但是我正在画一个空白。

更新1

好,我已经尝试了两种解决方案,但出现错误:

foo<-structure(list(name = c("Grover Cleveland", "Benjamin Harrison", "Grover Cleveland"), from = c(1885, 1889, 1893), to = c(1889, 1893, 1897)), .Names = c("name", "from", "to"), row.names = 22:24, class = "data.frame")
ddply(foo, "name", summarise, year = seq(from, to))
Error in seq.default(from, to) : 'from' must be of length 1


#1 楼

您可以使用plyr软件包:

library(plyr)
ddply(presidents, "name", summarise, year = seq(from, to))
#              name year
# 1    Barack Obama 2009
# 2    Barack Obama 2010
# 3    Barack Obama 2011
# 4    Barack Obama 2012
# 5    Bill Clinton 1993
# 6    Bill Clinton 1994
# [...]


,如果按年份对数据进行排序很重要,则可以使用arrange函数:

df <- ddply(presidents, "name", summarise, year = seq(from, to))
arrange(df, df$year)
#              name year
# 1    Bill Clinton 1993
# 2    Bill Clinton 1994
# 3    Bill Clinton 1995
# [...]
# 21   Barack Obama 2011
# 22   Barack Obama 2012


编辑1:继@edgester的“ Update 1”之后,更合适的方法是使用adply来说明具有非连续性条款的总裁:

adply(foo, 1, summarise, year = seq(from, to))[c("name", "year")]


评论


您的解决方案适用于大多数数据。请查看我的更新。

– Edgester
2012年7月16日在1:04

adply解决方案是唯一没有错误“ seq.default(from,to)中的错误:'from'的长度必须为1”的解决方案。感谢您提供有效的解决方案。您能否解释为什么其他解决方案出现“必须长度为1”错误?

– Edgester
2012年8月7日在0:45



@JoshOBrien和我的都在您的示例数据上工作,因此如果不查看完整数据就很难说。也许您可以将数据精简为一个重现您看到的错误的子集?这样我们也许可以提供帮助。

–弗洛德尔
2012年8月7日17:30

#2 楼

这是一个data.table解决方案。它具有很好的(如果是次要的)功能,可以按照提供的顺序保留总统:

library(data.table)
dt <- data.table(presidents)
dt[, list(year = seq(from, to)), by = name]
#               name year
#  1:   Bill Clinton 1993
#  2:   Bill Clinton 1994
#  ...
#  ...
# 21:   Barack Obama 2011
# 22:   Barack Obama 2012


编辑:要处理具有非连续性条款的总统,请改用以下命令:

dt[, list(year = seq(from, to)), by = c("name", "from")]


#3 楼

使用tidyverseunnest的替代map2方法。

library(tidyverse)

presidents %>%
  unnest(year = map2(from, to, seq)) %>%
  select(-from, -to)

#              name  year
# 1    Bill Clinton  1993
# 2    Bill Clinton  1994
...
# 21   Barack Obama  2011
# 22   Barack Obama  2012


编辑:从tidyr v1.0.0不能再将新变量作为unnest()的一部分创建。

presidents %>%
  mutate(year = map2(from, to, seq)) %>%
  unnest(year) %>%
  select(-from, -to)


评论


很棒的答案。如此简单,却如此有效。

– JFG123
12月1日1:07

#4 楼

这是一个dplyr解决方案:

library(dplyr)

# the data
presidents <- 
structure(list(name = c("Bill Clinton", "George W. Bush", "Barack Obama"
), from = c(1993, 2001, 2009), to = c(2001, 2009, 2012)), .Names = c("name", 
"from", "to"), row.names = 42:44, class = "data.frame")

# the expansion of the table
presidents %>%
    rowwise() %>%
    do(data.frame(name = .$name, year = seq(.$from, .$to, by = 1)))

# the output
Source: local data frame [22 x 2]
Groups: <by row>

             name  year
            (chr) (dbl)
1    Bill Clinton  1993
2    Bill Clinton  1994
3    Bill Clinton  1995
4    Bill Clinton  1996
5    Bill Clinton  1997
6    Bill Clinton  1998
7    Bill Clinton  1999
8    Bill Clinton  2000
9    Bill Clinton  2001
10 George W. Bush  2001
..            ...   ...



#5 楼

另一个base解决方案:

l <- mapply(`:`, d$from, d$to)
data.frame(name = d$name[rep(1:nrow(d), lengths(l))], year = unlist(l))
#              name year
# 1    Bill Clinton 1993
# 2    Bill Clinton 1994
# ...snip
# 8    Bill Clinton 2000
# 9    Bill Clinton 2001
# 10 George W. Bush 2001
# 11 George W. Bush 2002
# ...snip
# 17 George W. Bush 2008
# 18 George W. Bush 2009
# 19   Barack Obama 2009
# 20   Barack Obama 2010
# 21   Barack Obama 2011
# 22   Barack Obama 2012


#6 楼

这是一个快速的R基本解决方案,其中Df是您的data.frame

do.call(rbind, apply(Df, 1, function(x) {
  data.frame(name=x[1], year=seq(x[2], x[3]))}))


它给出了有关行名的一些警告,但似乎返回了正确的data.frame。 />

评论


+1-非常好,尽管我希望它不会抛出这些警告,并且不会产生带有如此丑陋的行名的结果。

–乔什·奥布莱恩(Josh O'Brien)
2012年7月16日在6:07

@ JoshO'Brien,我实际上并不介意行名,它为数据添加了一个层次:我们可以迅速确定比尔·克林顿(Bill Clinton)为美国第42任总统。这在plyr和data.table解决方案中都丢失了。

– A5C1D2H2I1M1N2O1R2T1
2012年7月16日在7:07

#7 楼

使用tidyverse的另一种选择是将gather数据转换为长格式,即group_byname并在fromto日期之间创建一个序列。

library(tidyverse)

presidents %>%
  gather(key, date, -name) %>%
  group_by(name) %>%
  complete(date = seq(date[1], date[2]))%>%
  select(-key) 

# A tibble: 22 x 2
# Groups:   name [3]
#   name          date
#   <chr>        <dbl>
# 1 Barack Obama  2009
# 2 Barack Obama  2010
# 3 Barack Obama  2011
# 4 Barack Obama  2012
# 5 Bill Clinton  1993
# 6 Bill Clinton  1994
# 7 Bill Clinton  1995
# 8 Bill Clinton  1996
# 9 Bill Clinton  1997
#10 Bill Clinton  1998
# … with 12 more rows


#8 楼

使用by创建一个by数据列表的列表L,每个总裁一个data.frame,然后将它们组合在一起。不使用任何软件包。

L <- by(presidents, presidents$name, with, data.frame(name, year = from:to))
do.call("rbind", setNames(L, NULL))


如果您不介意行名,那么最后一行可以简化为:

do.call("rbind", L)


#9 楼

使用dplyrtidyr的另一种解决方案:

library(magrittr) # for pipes
df <- data.frame(tata = c('toto1', 'toto2'), from = c(2000, 2004), to = c(2001, 2009))

#    tata from   to
# 1 toto1 2000 2001
# 2 toto2 2004 2009

df %>% 
  dplyr::as.tbl() %>%
  dplyr::rowwise() %>%
  dplyr::mutate(combined = list(seq(from, to))) %>%
  dplyr::select(-from, -to) %>%
  tidyr::unnest(combined)

#   tata  combined
#   <fct>    <int>
# 1 toto1     2000
# 2 toto1     2001
# 3 toto2     2004
# 4 toto2     2005
# 5 toto2     2006
# 6 toto2     2007
# 7 toto2     2008
# 8 toto2     2009