我还没有在网上找到解决方案,因为提出问题的正确问题并不容易。 我有两个data.frames,x和y,并希望将它们组合起来得到z:
棘手的是z比较x和y的日期值,并采用最新的观察来更新A,B,C和D.因此“动态”更新/组合。
x=data.frame(c("2000-01-01","2000-06-01","2001-01-01"),c("100","100","100"),c("200","200","200"))
colnames(x)=c("Date","A","B")
y=data.frame(c("2000-01-05","2000-04-09"),c("10","0"),c("0","35"))
colnames(y)=c("Date","C","D")
z=data.frame(c("2000-01-01","2000-01-05","2000-04-09","2000-06-01","2001-01-01"),c("100","100","100","100","100"),c("200","200","200","200","200"),c("0","10","10","0","0"),c("0","0","35","0","0"))
colnames(z)=c("Date","A","B","C","D")
x$Date = as.Date(x$Date)
y$Date = as.Date(y$Date)
问题:如何通过有效的代码到达z
?
举例说明:
> x
Date A B
1 2000-01-01 100 200
2 2000-06-01 100 200
3 2001-01-01 100 200
> y
Date C D
1 2000-01-05 10 0
2 2000-04-09 0 35
> z
Date A B C D
1 2000-01-01 100 200 0 0
2 2000-01-05 100 200 10 0
3 2000-04-09 100 200 10 35
4 2000-06-01 100 200 10 35
5 2001-01-01 100 200 10 35
>
编辑: 感谢下面的答案。 解决方案似乎是一个简单的完全连接,然后是循环中的循环(我想出了第二步):
x$Date = as.Date(x$Date)
y$Date = as.Date(y$Date)
tt=merge(x,y,by='Date',all=TRUE)
for (i in 2:(ncol(x)+ncol(y)-1)){
for (j in 2:(nrow(x)+nrow(y))){
if (is.na(tt[j,i])==TRUE & is.na(tt[j-1,i])==FALSE){
tt[j,i]=tt[j-1,i]}
}
}
EDIT2:其他人发布的解决方案似乎更有效率。仅仅为了完整性,如果y中的0被NA替换,则我的更长解决方案有效,即将y定义为:
y=data.frame(c("2000-01-05","2000-04-09"),c("10",NA),c(NA,"35"))
colnames(y)=c("Date","C","D")
然后在最后一步中替换z中的NA。
我从第一次编辑中学到了,我没有编辑上面的原始问题,以避免混淆。
非常感谢你的帮助!
答案 0 :(得分:3)
可能的解决方案可能是使用data.table
打包中的na.locf
和zoo
函数的组合:
# loading the needed packages
library(data.table)
library(zoo)
# converting x & y to datatables
setDT(x)
setDT(y)
# merge x & y into z
z <- merge(x, y, by="Date", all=TRUE) # this works in base R as well
# fill the NA's with the last observation
cols <- c("A","B","C","D") # in this specific case, you can also use: LETTERS[1:4]
z[, (cols) := lapply(.SD, na.locf, rule = 1, na.rm=FALSE), .SDcols= cols]
这给出了:
> z
Date A B C D
1: 2000-01-01 100 200 NA NA
2: 2000-01-05 100 200 10 0
3: 2000-04-09 100 200 0 35
4: 2000-06-01 100 200 0 35
5: 2001-01-01 100 200 0 35
这个结果也可以在@Tensibai在评论中提到的基础R中实现(由于某种原因,起初我的系统没有工作):
z <- merge(x, y, by="Date", all=TRUE)
z <- na.locf(z)
要获得准确的所需输出,您需要一些额外的步骤(省略第一步,因为它们是相同的):
# merge x & y into z
z <- merge(x, y, by="Date", all=TRUE) # this works in base R as well
# replace the zero with NA
z[z==0] <- NA
# fill the NA's with the last observation
cols <- LETTERS[1:4]
z[, (cols) := lapply(.SD, na.locf, rule = 1, na.rm=FALSE), .SDcols= cols]
# replace the remaining NA's with zero's
z[is.na(z)] <- 0
这给出了:
> z
Date A B C D
1: 2000-01-01 100 200 0 0
2: 2000-01-05 100 200 10 0
3: 2000-04-09 100 200 10 35
4: 2000-06-01 100 200 10 35
5: 2001-01-01 100 200 10 35
在基地R你会这样做:
z <- merge(x, y, by="Date", all=TRUE)
z[z==0] <- NA
z <- na.locf(z)
z[is.na(z)] <- 0
得到相同的结果。
答案 1 :(得分:0)
使用dplyr和一些函数的替代方法:
library(lubridate)
library(dplyr)
# dataset
x=data.frame(c("2000-01-01","2000-06-01","2001-01-01"),
c("100","100","100"),
c("200","200","200"), stringsAsFactors = F)
colnames(x)=c("Date","A","B")
y=data.frame(c("2000-01-05","2000-04-09"),
c("10","0"),
c("0","35"), stringsAsFactors = F)
colnames(y)=c("Date","C","D")
# update date columns
x$Date = ymd(x$Date)
y$Date = ymd(y$Date)
# function that replaces NAs with 0s
ff = function(x){x[is.na(x)]=0
return(as.numeric(x))}
# function that updates zero elements with the previous ones
ff2 = function(x){
for (i in 2:length(x)){x[i] = ifelse(x[i]==0, x[i-1], x[i])}
return(x)
}
# create the full dataset
xy =
x %>%
full_join(y, by="Date") %>%
arrange(Date)
xy
# Date A B C D
# 1 2000-01-01 100 200 <NA> <NA>
# 2 2000-01-05 <NA> <NA> 10 0
# 3 2000-04-09 <NA> <NA> 0 35
# 4 2000-06-01 100 200 <NA> <NA>
# 5 2001-01-01 100 200 <NA> <NA>
xy %>%
group_by(Date) %>%
mutate_each(funs(ff)) %>%
ungroup %>%
select(-Date) %>%
mutate_each(funs(ff2)) %>%
bind_cols(data.frame(Date=xy$Date)) %>%
select(Date,A,B,C,D)
# Date A B C D
# 1 2000-01-01 100 200 0 0
# 2 2000-01-05 100 200 10 0
# 3 2000-04-09 100 200 10 35
# 4 2000-06-01 100 200 10 35
# 5 2001-01-01 100 200 10 35