用新值替换每个组/因子的第一个数字

时间:2017-03-08 23:21:15

标签: r dplyr

我正在尝试将每个IndID的第一个值替换为来自单独data.frame的新值。请注意,每个IndID的观察数量不同。

使用下面的示例代码,我想将number1number2的第一个值替换为dat2 df中的相应列名。在某些情况下,替换值为NA

set.seed(1)
dat <- data.frame(IndID = rep(c("A","A","B","c","c","D"), each  = 5),
                  number1 = sample(1:100,30),
                  number2 = sample(1:100,30))

dat2 <- data.frame(IndID = c("A","B","c","D"),
                  number1 = c(555,666,NA,888),
                  number2 = c(111,222,NA,444))

优选的结果将产生以下更加有效和优雅的方法。我怀疑dplyr是一个合适的工具,但总是喜欢学习其他方法。

dat[1,2:3] <- c(555,111)
dat[11,2:3] <- c(666,222)
dat[16,2:3] <- c(NA,NA)
dat[26,2:3] <- c(888,444)
dat

4 个答案:

答案 0 :(得分:4)

使用data.table

library(data.table)
DT = data.table(dat)
DT[dat2, on=.(IndID), mult="first", `:=`(number1 = i.number1, number2 = i.number2)]

您可以替代使用setDT(dat)而不是创建DT

顺便说一下,这会抛出一个警告,因为OP混合浮点数(在dat2中)与int(在dat中)。与基数R不同,data.table可以在修改列时防止意外强制。

如果你想避免手动指定列(比如@ Jay的答案):

cols = setdiff(names(dat2), "IndID")
DT[dat2, on=.(IndID), mult="first", (cols) := mget(sprintf("i.%s", cols))]

答案 1 :(得分:3)

你可以尝试:

 dat[match(dat2$IndID, dat$IndID),] <- dat2

答案 2 :(得分:2)

如果您不介意使用基本R方法,则可以执行以下操作。您将获得每个IndID的第一行索引,即ind。然后,您知道在number1number2中需要哪些行替换数字。使用索引并用dat2替换数字。

ind <- which(!duplicated(dat$IndID))
dat[ind, 2] <- dat2$number1
dat[ind, 3] <- dat2$number2


#   IndID number1 number2
#1      A     555     111
#2      A      37      60
#3      A      57     100
#4      A      89      19
#5      A      20      80
#6      A      86      64
#7      A      97      75
#8      A      62      11
#9      A      58      67
#10     A       6      38
#11     B     666     222
#12     B      16      58
#13     B      61      69
#14     B      34      98
#15     B      67      46
#16     c      NA      NA
#17     c      88       2
#18     c      83      40
#19     c      32      61
#20     c      63      57
#21     c      75      39
#22     c      17      88
#23     c      51      35
#24     c      10      97
#25     c      21       6
#26     D     888     444
#27     D       1      24
#28     D      28      91
#29     D      81      48
#30     D      25      29

答案 3 :(得分:1)

a1 <- lapply(split(dat, dat$IndID), function( x ) {  # split dat by IndID column
  x[1, ] <- dat2[dat2$IndID %in% unique(x$IndID), ]  # replace first row with the matching row of dat2
  return( x )                                        # return modified data  
  })

do.call( 'rbind', a1)  # combine all list elements together using rbind

#      IndID number1 number2
# A.1      A     555     111
# A.2      A      37      60
# A.3      A      57     100
# A.4      A      89      19
# A.5      A      20      80
# A.6      A      86      64
# A.7      A      97      75
# A.8      A      62      11
# A.9      A      58      67
# A.10     A       6      38
# B.11     B     666     222
# B.12     B      16      58
# B.13     B      61      69
# B.14     B      34      98
# B.15     B      67      46
# c.16     c      NA      NA
# c.17     c      88       2
# c.18     c      83      40
# c.19     c      32      61
# c.20     c      63      57
# c.21     c      75      39
# c.22     c      17      88
# c.23     c      51      35
# c.24     c      10      97
# c.25     c      21       6
# D.26     D     888     444
# D.27     D       1      24
# D.28     D      28      91
# D.29     D      81      48
# D.30     D      25      29