将每个id和law(带有开始和结束年份)的行的数据框转换为每个id和year有一行的文件

问题描述 投票:4回答:4

我有一个名为laws的df,每个法律都有一行(每个id一个):

laws <- data.frame(id=c(1,2,3),beginyear=c(2001,2002,2005),endyear=c(2003,2005,2006), law1=c(0,0,1), law2=c(1,0,1))

从中我想创建第二个名为idyear,每个id和year都有一行:

idyear <- data.frame(id=c(rep(1,6),rep(2,6),rep(3,6)), year=(rep(c(2001:2006),3)), law1=c(rep(0,16),1,1), law2=c(1,1,1,rep(0,13),1,1))

我如何有效地编写一些代码来获取idyear df的laws df输出?如果idyear$year> = laws$beginyearidyear$year <= laws$endyear,则两个法则变量是指标变量== 1。

我是R的初学者,但我愿意尝试任何东西(应用,循环等)来实现这一点。

r dataframe
4个回答
3
投票

使用的解决方案。最后一个as.data.frame()是可选的,它只是将tbl转换为数据帧。

library(tidyverse)

idyear <- laws %>%
  mutate(year = map2(beginyear, endyear, `:`)) %>%
  unnest() %>%
  complete(id, year = full_seq(year, period = 1L), fill = list(law1 = 0L, law2 = 0L)) %>%
  select(-beginyear, -endyear) %>%
  as.data.frame()
idyear
#    id year law1 law2
# 1   1 2001    0    1
# 2   1 2002    0    1
# 3   1 2003    0    1
# 4   1 2004    0    0
# 5   1 2005    0    0
# 6   1 2006    0    0
# 7   2 2001    0    0
# 8   2 2002    0    0
# 9   2 2003    0    0
# 10  2 2004    0    0
# 11  2 2005    0    0
# 12  2 2006    0    0
# 13  3 2001    0    0
# 14  3 2002    0    0
# 15  3 2003    0    0
# 16  3 2004    0    0
# 17  3 2005    1    1
# 18  3 2006    1    1

4
投票

1)基地expand.grid将创建一个18 x 2数据框架的所有idyear组合,然后merge将与laws合并回来。将任何law1law2条目归零,year不在beginyearendyear之间。最后放下beginyearendyear列。没有使用包裹。

g <- with(laws, expand.grid(year = min(beginyear):max(endyear), id = id))
m <- merge(g, laws)
m[m$year < m$beginyear | m$year > m$endyear, c("law1", "law2")] <- 0
m <- subset(m, select = - c(beginyear, endyear))

# check
identical(m, idyear)
## [1] TRUE

2)magrittr这是与(1)相同的解决方案,除了我们使用magrittr管道来表达它。注意管道操作符的混合。

library(magrittr)

laws %$%
     expand.grid(year = min(beginyear):max(endyear), id = id) %>%
     merge(laws) %$%
     { .[year < beginyear | year > endyear, c("law1", "law2")] <- 0; .} %>%
     subset(select = - c(beginyear, endyear))

更新:已修复。添加(2)。


3
投票

使用mapply功能可以提供帮助。

# Function to expand year between begin and end
gen_data <- function(x_id, x_beginyear, x_endyear, x_law1, x_law2){
  df <- data.frame(x_id, x_beginyear:x_endyear, x_law1, x_law2)
  df
}

idyearlst <- data.frame()

idyearlst <- rbind(idyearlst, mapply(gen_data, laws$id, laws$beginyear,
 laws$endyear, laws$law1, laws$law2))

# Finally convert list to data.frame
idyear <- setNames(do.call(rbind.data.frame, idyearlst), c("id", "year", "law1", "law2"))

Result will be like:
> idyear
     id year law1 law2
V1.1  1 2001    0    1
V1.2  1 2002    0    1
V1.3  1 2003    0    1
V2.4  2 2002    0    0
V2.5  2 2003    0    0
V2.6  2 2004    0    0
V2.7  2 2005    0    0
V3.8  3 2005    1    1
V3.9  3 2006    1    1

2
投票

这是一种丑陋的方法,但我认为它得到你所追求的,使用G. Grothendieck的g expand.grid数据框作为基础,以及你的laws数据帧。

new.df <- data.frame(t(apply(g, 1, function(x){
  yearspan = laws[laws$id == x['id'], 'beginyear']:laws[laws$id == x['id'], 'endyear']
  law1 = laws$law1[laws$id == x['id'] & x['year'] %in% yearspan]
  law2 = laws$law2[laws$id == x['id'] & x['year'] %in% yearspan]
  x['law1'] = ifelse(length(law1 > 0), law1, 0)
  x['law2'] = ifelse(length(law2 > 0), law2, 0)
  return(x)
})))

> new.df
   id year law1 law2
1   1 2001    0    1
2   1 2002    0    1
3   1 2003    0    1
4   1 2004    0    0
5   1 2005    0    0
6   1 2006    0    0
7   2 2001    0    0
8   2 2002    0    0
9   2 2003    0    0
10  2 2004    0    0
11  2 2005    0    0
12  2 2006    0    0
13  3 2001    0    0
14  3 2002    0    0
15  3 2003    0    0
16  3 2004    0    0
17  3 2005    1    1
18  3 2006    1    1

图书馆:

dplyr(对于arrange,没有必要)

数据:

laws <- data.frame(id=c(1,2,3),
                   beginyear=c(2001,2002,2005),
                   endyear=c(2003,2005,2006), 
                   law1=c(0,0,1), law2=c(1,0,1))

g <- with(laws, expand.grid(id = id, year = min(beginyear):max(endyear)))
g <- arrange(g, id)
© www.soinside.com 2019 - 2024. All rights reserved.