我有一个这样的数据框
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从我们应该从哪里开始定义。
谢谢!
答案 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)
这是gather
和spread
的一个主意。
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