保留组中的第一个值

时间:2016-06-07 02:50:55

标签: r

我希望按组保留变量的第一个值。下面的代码执行此操作,但使用for-loops并且看起来过于复杂。有没有更有效的方法,特别是在基地R?对象desired.result包含我想要的结果。

my.data <- read.table(text = '

     my.string   my.cov  my.id
     11.......      1      1
     1.1......      3      2
     ..1.2....      4      2
     ....2.2..      5      2
     12.......      2      3
     .22......      3      3
     ..24.....      3      3
     1...2....      1      4
     ....2...4      0      4
     ..2..4...      5      5
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')

desired.result <- read.table(text = '

     my.string   my.cov  my.id
     11.......      1      1
     1.1......      3      2
     ..1.2....      3      2
     ....2.2..      3      2
     12.......      2      3
     .22......      2      3
     ..24.....      2      3
     1...2....      1      4
     ....2...4      1      4
     ..2..4...      5      5
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')

my.seq <- rle(my.data$my.id)$lengths
my.data$first <- unlist(lapply(my.seq, function(x) seq(1,x)))
my.data$last  <- unlist(lapply(my.seq, function(x) seq(x,1,-1)))

my.data$my.new.cov <- rep(NA, nrow(my.data))

for(i in 1:nrow(my.data)) {
    if(my.data$first[i] == 1) my.data$my.new.cov[i] = my.data$my.cov[i]
    if(my.data$first[i] >  1) my.data$my.new.cov[i] = my.data$my.new.cov[(i - 1)]
}

my.data$my.cov <- my.data$my.new.cov

my.data <- my.data[, c('my.string', 'my.cov', 'my.id')]

all.equal(my.data, desired.result)

# [1] TRUE

3 个答案:

答案 0 :(得分:3)

这似乎是这样做的:

my.data$my.cov <- ave(my.data$my.cov, my.data$my.id, FUN = function(x) head(x,1))

答案 1 :(得分:3)

我们可以使用data.table

library(data.table)
setDT(my.data)[,  my.cov := my.cov[1L], by = my.id]
my.data
#    my.string my.cov my.id
# 1: 11.......      1     1
# 2: 1.1......      3     2
# 3: ..1.2....      3     2
# 4: ....2.2..      3     2
# 5: 12.......      2     3
# 6: .22......      2     3
# 7: ..24.....      2     3
# 8: 1...2....      1     4
# 9: ....2...4      1     4
#10: ..2..4...      5     5

注意:发布的base R解决方案(split)如果未排序,会在某些结果中显示错误的结果。

答案 2 :(得分:1)

以下是基础R解决方案:

do.call(rbind, lapply(split(my.data, my.data$my.id), 
        function(group) {
            group$my.cov = group$my.cov[1]; group }))

    my.string my.cov my.id
1   11.......      1     1
2.2 1.1......      3     2
2.3 ..1.2....      3     2
2.4 ....2.2..      3     2
3.5 12.......      2     3
3.6 .22......      2     3
3.7 ..24.....      2     3
4.8 1...2....      1     4
4.9 ....2...4      1     4
5   ..2..4...      5     5