根据条件替换列集中的值

时间:2019-03-07 02:16:41

标签: r

我有一个这样的数据框

id  v1  v2  v3  v4  v5  pos
1   11  12  11  10  10  3
2   17  11  22  40  23  4
1   11  22  50  10  10  2

我想根据与pos相关的条件更改其值以获取:

id  v1  v2  v3  v4  v5  pos
1   11  12  12  12  12  3
2   17  11  22  22  22  4
1   11  11  11  11  11  2

因此,基本上,值会获得先前的值,而变量pos从我们应该从哪里开始定义。

谢谢!

3 个答案:

答案 0 :(得分:2)

一种使用某些索引的方法,这种方法在运行时应该很有效。
但是,由于使副本的大小与输入数据的大小相同,因此在内存方面并不是超级有效:

vars <- paste0("v",1:5)
nv <- dat[vars][cbind(seq_len(nrow(dat)), dat$pos-1)]
ow <- col(dat[vars]) >= dat$pos
dat[vars][ow] <- nv[row(ow)[ow]]

#  id v1 v2 v3 v4 v5 pos
#1  1 11 12 12 12 12   3
#2  2 17 11 22 22 22   4
#3  1 11 11 11 11 11   2

说明:

获取感兴趣的变量:

vars <- paste0("v",1:5)

获取要覆盖每一行的新值:

nv <- dat[vars][cbind(seq_len(nrow(dat)), dat$pos-1)]

使要覆盖的单元格形成逻辑矩阵

ow <- col(dat[vars]) >= dat$pos

使用行标识符覆盖单元格以选择适当的值。

dat[vars][ow] <- nv[row(ow)[ow]]

使用更大的数据集进行快速比较计时:

dat <- dat[rep(1:3,1e6),]

# indexing
#   user  system elapsed 
#   1.36    0.31    1.68 

# apply
#   user  system elapsed 
#  77.30    0.83   78.41 

# gather/spread
#   user  system elapsed 
# 293.43    3.64  299.10

答案 1 :(得分:1)

这是gatherspread的一个主意。

library(tidyverse)

dat2 <- dat %>%
  rowid_to_column() %>%
  gather(v, value, starts_with("v")) %>%
  group_by(rowid) %>%
  mutate(value = ifelse(row_number() >= (pos - 1), nth(value, (pos - 1)[[1]]), value)) %>%
  spread(v, value) %>%
  ungroup() %>%
  select(names(dat))

dat2
# # A tibble: 3 x 7
#      id    v1    v2    v3    v4    v5   pos
#   <int> <int> <int> <int> <int> <int> <int>
# 1     1    11    12    12    12    12     3
# 2     2    17    11    22    22    22     4
# 3     1    11    11    11    11    11     2

数据

dat <- read.table(text = "id  v1  v2  v3  v4  v5  pos
1   11  12  11  10  10  3
2   17  11  22  40  23  4
1   11  22  50  10  10  2",
                  header = TRUE)
library(tidyverse)

答案 2 :(得分:1)

使用基数R中的apply

data.frame(t(apply(df, 1, function(x) 
     c(x[1:x["pos"]], rep(x[x["pos"]], ncol(df) - x["pos"] - 2), x['pos']))))

#  X1 X2 X3 X4 X5 X6
#1  1 11 12 12 12  3
#2  2 17 11 22 22  4
#3  1 11 11 11 11  2