删除某些行并根据条件替换值

时间:2017-02-22 21:15:23

标签: r

我有以下数据:

set.seed(2)
d <- data.frame(iteration=c(1,1,2,2,2,3,4,5,6,6,6),
            value=sample(11),
            var3=sample(11))
      iteration value var3
1          1     3     7
2          1     8     4
3          2     6     8
4          2     2     3
5          2     7     9
6          3     9     11
7          4     1     10
8          5     4     1
9          6    10     2
10         6    11     6
11         6     5     5

现在,我想要以下内容: 1. IF 更多比一次迭代删除最后行并替换最后行的值与之前的值。 所以在上面的示例中,这是我想要的输出:

d<-data.frame(iteration=c(1,2,2,3,4,5,6,6),
          value=c(8,6,7,9,1,4,10,5))

     iteration value var3
1         1     8     7
2         2     6     8
3         2     7     3
4         3     9     11
5         4     1     10
6         5     4     1
7         6    10     2
8         6     5     6

2 个答案:

答案 0 :(得分:3)

我们可以使用data.table

library(data.table)
setDT(d)[, .(value = if(.N>1) c(value[seq_len(.N-2)], value[.N]) else value), iteration]
#   iteration value
#1:         1     8
#2:         2     6
#3:         2     7
#4:         3     9
#5:         4     1
#6:         5     4
#7:         6    10
#8:         6     5

更新

根据OP帖子中的更新,我们可以先在&#39;值&#39;中创建一个lead值的新列,然后分配&#39; value1&#39;价值&#39;仅适用于满足&#39; i1&#39;中的条件的人,然后对行进行子集

setDT(d)[, value1 := shift(value, type = "lead"), iteration]
i1 <- d[, if(.N >1) .I[.N-1], iteration]$V1 
d[i1, value := value1]
d[d[, if(.N > 1) .I[-.N] else .I, iteration]$V1][, value1 := NULL][]
#   iteration value var3
#1:         1     8    7
#2:         2     6    8
#3:         2     7    3
#4:         3     9   11
#5:         4     1   10
#6:         5     4    1
#7:         6    10    2
#8:         6     5    6

答案 1 :(得分:2)

使用split-apply-combine方法的这个基本R解决方案返回与@ akrun的data.table版本相同的值,尽管逻辑似乎不同。

do.call(rbind, lapply(split(d, d$iteration),
                      function(i)
                       if(nrow(i) >= 3) i[-(nrow(i)-1),] else tail(i, 1)))
     iteration value
1            1     8
2.3          2     6
2.5          2     7
3            3     9
4            4     1
5            5     4
6.9          6    10
6.11         6     5

我们的想法是将data.frame拆分为沿迭代的data.frames列表,然后对于每个data.frame,检查是否有超过2行,如果是,则抓住第一行和最后一行,如果没有,然后只返回最后一行。 do.call rbind然后将这些观察结果编译成单个data.frame。

请注意,这在其他变量存在的情况下不起作用。