我有以下列表,我想在每组ID之前添加一个新行,保留ID并将A和B设置为1.00。
ID DATEE A B
102984 2016-11-23 2.0 2.0
140349 2016-11-23 1.5 1.5
167109 2017-04-16 2.0 2.0
167109 2017-06-21 1.5 1.5
最终结果:
ID DATEE A B
102984 NA 1.0 1.0
102984 2016-11-23 2.0 2.0
140349 NA 1.0 1.0
140349 2016-11-23 1.5 1.5
167109 NA 1.0 1.0
167109 2017-04-16 2.0 2.0
167109 2017-06-21 1.5 1.5
到目前为止,我使用了以下代码,在每个组的底部添加一个空行do.call(rbind,by(df,df $ ID,rbind,""))但是我当我替换""时,我们无法在各自的列中引入特定值。通过值向量。
答案 0 :(得分:7)
以下是tidyverse
的一个选项。我们按“ID”获取distinct
行数据集,mutate
将变量'A','B'变为1,将'DATEE'变为NA,然后使用bind_rows
行绑定原始数据集和arrange
by'ID'
library(tidyverse)
df1 %>%
distinct(ID, .keep_all= TRUE) %>%
mutate_at(vars("A", "B"), funs((1))) %>%
mutate(DATEE = NA) %>%
bind_rows(., df1) %>%
arrange(ID)
# ID DATEE A B
#1 102984 <NA> 1.0 1.0
#2 102984 2016-11-23 2.0 2.0
#3 140349 <NA> 1.0 1.0
#4 140349 2016-11-23 1.5 1.5
#5 167109 <NA> 1.0 1.0
#6 167109 2017-04-16 2.0 2.0
#7 167109 2017-06-21 1.5 1.5
(我假设日期格式已经修复,例如df1$DATEE = as.Date(df1$DATEE)
。)
或翻译成基地R:
new1 = data.frame(ID = unique(df1$ID), DATEE = Sys.Date()[NA_integer_], A = 1, B = 1)
tabs = list(new1, df1)
res = do.call(rbind, tabs)
res <- res[order(res$ID), ]
# ID DATEE A B
# 1 102984 <NA> 1.0 1.0
# 4 102984 2016-11-23 2.0 2.0
# 2 140349 <NA> 1.0 1.0
# 5 140349 2016-11-23 1.5 1.5
# 3 167109 <NA> 1.0 1.0
# 6 167109 2017-04-16 2.0 2.0
# 7 167109 2017-06-21 1.5 1.5
或者使用data.table:
library(data.table)
new1 = data.table(ID = unique(df1$ID), DATEE = Sys.Date()[NA_integer_], A = 1, B = 1)
tabs = list(new1, df1)
res = rbindlist(tabs)
setorder(res)
# ID DATEE A B
#1: 102984 <NA> 1.0 1.0
#2: 102984 2016-11-23 2.0 2.0
#3: 140349 <NA> 1.0 1.0
#4: 140349 2016-11-23 1.5 1.5
#5: 167109 <NA> 1.0 1.0
#6: 167109 2017-04-16 2.0 2.0
#7: 167109 2017-06-21 1.5 1.5
还有其他一些方法:
# or let DATEE and other cols be filled as NA
library(data.table)
new1 = data.table(ID = unique(df1$ID), A = 1, B = 1)
tabs = list(df1, new1)
res = rbindlist(tabs, fill = TRUE, idcol = "src")
setorder(res, ID, -src)
res[, src := NULL ]
# or a more compact option (assuming df1$A has no missing values)
library(data.table)
setDT(df1)[, .SD[c(.N+1, seq_len(.N))], ID][is.na(A), c("A", "B") := 1][]
答案 1 :(得分:4)
以下是基础R
的两种解决方案根据ID
拆分为子组,在每个子组的顶部添加一行,并在最后添加rbind
一切。
do.call(rbind, lapply(split(df, df$ID), function(a){
rbind(setNames(c(a$ID[1], NA, 1, 1), names(a)), a)
}))
# ID DATEE A B
#102984.1 102984 <NA> 1.0 1.0
#102984.2 102984 2016-11-23 2.0 2.0
#140349.1 140349 <NA> 1.0 1.0
#140349.2 140349 2016-11-23 1.5 1.5
#167109.1 167109 <NA> 1.0 1.0
#167109.3 167109 2017-04-16 2.0 2.0
#167109.4 167109 2017-06-21 1.5 1.5
或者您最初可以复制第一行(通过使用ave标识它们),然后在每列中替换适当的值。
df = df[sort(c(1:NROW(df), which(ave(df$A, df$ID, FUN = seq_along) == 1))),]
df$DATEE = replace(df$DATEE, which(ave(df$A, df$ID, FUN = seq_along) == 1), NA)
df$A = replace(df$A, which(ave(df$A, df$ID, FUN = seq_along) == 1), 1)
df$B = replace(df$B, which(ave(df$A, df$ID, FUN = seq_along) == 1), 1)
df
# ID DATEE A B
#1 102984 <NA> 1.0 1.0
#1.1 102984 2016-11-23 2.0 2.0
#2 140349 <NA> 1.0 1.0
#2.1 140349 2016-11-23 1.5 1.5
#3 167109 <NA> 1.0 1.0
#3.1 167109 2017-04-16 2.0 2.0
#4 167109 2017-06-21 1.5 1.5
答案 2 :(得分:4)
使用purrr
的另一个想法。首先,我们通过split()
ID
数据,然后我们使用imap
(索引映射)和dfr
(通过行绑定返回数据帧)循环遍历每个组和add_row()
具有指定值。
library(tidyverse)
df %>%
split(.$ID) %>%
# We don't have to specify "DATEE", absent variables get missing values
imap_dfr(~ add_row(.x, ID = .y, A = 1, B = 1, .before = 1))
给出了:
# ID DATEE A B
#1 102984 <NA> 1.0 1.0
#2 102984 2016-11-23 2.0 2.0
#3 140349 <NA> 1.0 1.0
#4 140349 2016-11-23 1.5 1.5
#5 167109 <NA> 1.0 1.0
#6 167109 2017-04-16 2.0 2.0
#7 167109 2017-06-21 1.5 1.5
来自文档:
imap_xxx(x, ...)
是一个索引地图,如果map2(x, names(x), ...)
有名称,则为x
的简写,如果不是,则为map2(x, seq_along(x), ...)
。 如果您需要计算值和值,这非常有用 元素的位置。
答案 3 :(得分:3)
查找非重复项的索引u
,然后重复提供DF2
的行。然后在uu
中找到非重复项DF2
,并将NA,1,1插入除第一列以外的行中。没有包使用。
u <- !duplicated(DF$ID)
DF2 <- DF[rep(1:nrow(DF), 1 + u), ]
uu <- !duplicated(DF2$ID)
DF2[uu, -1] <- list(NA, 1, 1)
,并提供:
> DF2
ID DATEE A B
1 102984 <NA> 1.0 1.0
1.1 102984 2016-11-23 2.0 2.0
2 140349 <NA> 1.0 1.0
2.1 140349 2016-11-23 1.5 1.5
3 167109 <NA> 1.0 1.0
3.1 167109 2017-04-16 2.0 2.0
4 167109 2017-06-21 1.5 1.5
注意:可重复形式的输入是:
Lines <- "
ID DATEE A B
102984 2016-11-23 2.0 2.0
140349 2016-11-23 1.5 1.5
167109 2017-04-16 2.0 2.0
167109 2017-06-21 1.5 1.5"
DF <- read.table(text = Lines, header = TRUE)
更新:已更正输出(代码正确但输出不对应)以及简化代码。
答案 4 :(得分:2)
加入这个派对,这是另一个基础R解决方案。我们复制行名称以扩展我们的数据框,然后简单地替换值
d1 <- df[rep(rownames(df), (!duplicated(df$ID)) + 1),]
d1$DATEE <- replace(d1$DATEE, !duplicated(d1$ID), NA)
d1[-c(1:2)] <- lapply(d1[-c(1:2)], function(i) replace(i, is.na(d1$DATEE), 1))
由此给出,
ID DATEE A B 1 102984 <NA> 1.0 1.0 1.1 102984 2016-11-23 2.0 2.0 2 140349 <NA> 1.0 1.0 2.1 140349 2016-11-23 1.5 1.5 3 167109 <NA> 1.0 1.0 3.1 167109 2017-04-16 2.0 2.0 4 167109 2017-06-21 1.5 1.5
答案 5 :(得分:2)
我们也可以使用您想要使用的by
函数,甚至可以使用基数为R的tapply
函数tapply
确保将INDICES
放入列表中,因为这样是一个数据框架。敌人by
没有必要把它放在一个列表中。因此,在下面的代码中,我们可以将by(A,A$ID...
替换为tapply(A,list(A$ID)...
,两者都会得到相同的结果。
`rownames<-`(do.call(rbind,by(A,A$ID,
function(i) rbind(data.frame(ID=i$ID[1],DATEE=NA,A=1,B=1),i))),NULL)
ID DATEE A B
1 102984 <NA> 1.0 1.0
2 102984 2016-11-23 2.0 2.0
3 140349 <NA> 1.0 1.0
4 140349 2016-11-23 1.5 1.5
5 167109 <NA> 1.0 1.0
6 167109 2017-04-16 2.0 2.0
7 167109 2017-06-21 1.5 1.5
不需要对此进行排序,因为这可能会扭曲数据之前的顺序。