随机重新编码每行中值的第一个和第二个实例



我有一个数据帧,其中每行中有两个值的实例(假设值为34(。我想用3替换一个实例,用4替换另一个实例(没有替换,所以如果第一个实例得到4,第二个实例得到3。反之亦然。(我想随机分配(这样一些行使用3然后4,其他行使用4然后3。(

这是我的例子:

# sample data
df1 <- data.frame(a= c(1, 2, NA, NA),b= c(2, NA, 1, NA),c= c(NA, NA,34, 2),
d= c(NA, 34, NA,1),e= c(34, 34,2,34),f= c(34, 1, NA,NA),
g= c(NA, NA,34, NA), h= c(NA,NA, NA, 34))
> df1
a  b  c  d  e  f  g  h
1  1  2 NA NA 34 34 NA NA
2  2 NA NA 34 34  1 NA NA
3 NA  1 34 NA  2 NA 34 NA
4 NA NA  2  1 34 NA NA 34

这里有一个符合我目标的输出:

a  b  c  d e  f  g  h
1  1  2 NA NA 3  4 NA NA
2  2 NA NA  4 3  1 NA NA
3 NA  1  4 NA 2 NA  3 NA
4 NA NA  2  1 4 NA NA  3

到目前为止,在我的尝试中,我已经能够使用which()apply()来识别容纳34的列

indexes_34 <- apply(df1, 1,  function(x) {which(x == 34)})

我随机生成了一个向量列表,其元素包含3和4或4和3。

ord <- list()
for(i in 1:nrow(df1)){
ord[[i]] <- sample(c(3,4), 2)
}

但我在编写将每个"ord"向量中的值分配给"df1"的每一行的正确索引的代码时遇到了问题。

有没有一种简单的方法可以做到这一点?

一个dplyrpurrr选项可以是:

df1 %>%
mutate(pmap_dfr(across(everything()), 
~ `[<-`(c(...), which(c(...) == 34), sample(c(3, 4)))))
a  b  c  d e  f  g  h
1  1  2 NA NA 4  3 NA NA
2  2 NA NA  4 3  1 NA NA
3 NA  1  4 NA 2 NA  3 NA
4 NA NA  2  1 4 NA NA  3

以下是使用which(..., arr.ind = TRUE)选择34并替换它们的方法:

set.seed(123)
m <- as_tibble(which(df1 == 34, arr.ind = T))
m <- m %>%
group_by(row) %>%
mutate(col = sample(col), value = c(3, 4)) %>%
ungroup()
df1[as.matrix(m[, 1:2])] <- m$value
#    a  b  c  d e  f  g  h
# 1  1  2 NA NA 3  4 NA NA
# 2  2 NA NA  3 4  1 NA NA
# 3 NA  1  3 NA 2 NA  4 NA
# 4 NA NA  2  1 4 NA NA  3

您可以在所有列上循环,并为每列创建一个布尔随机向量,该向量的TRUE值和FALSE值一样多。然后,只需将TRUE值的34替换为3,将其余值替换为4。

for(i in 1:dim(df1)[2]){
rb = runif(dim(df1)[1],0,1)>.5 ## Random vector
df1[,i][df1[,i]==34 & rb] = 3
df1[,i][df1[,i]==34] = 4
}

仅此而已。现在你已经用3和4 随机替换了34

编辑:如果你不想随机进行,而是强制每行必须交替使用3和4,你可以通过在行上循环并用c(3,4)c(4,3)替换34来实现,具体取决于机会。不过,每排必须有两个34。

for(i in 1:dim(df1)[1]){
if(runif(1,0,1)>0.5){replace=c(3,4)}else{replace=c(4,3)}
df1[i,][df1[i,]==34] = replace
}

loop中的循环非常简单,但理解发生的事情可能非常简单。我还试图建立在OP的想法之上:

ord <- list()
for(i in 1:nrow(df1)){
ord[[i]] <- sample(c(3,4), 2)
}
mat <- ifelse(df1 != 34 | is.na(df1), 0, 1 )
for (i in 1:nrow(df1)) {
for (j in 1:ncol(df1)) {
if (mat[i, j] == 1) {
if (sum(mat[i,], na.rm = T) == 2) {
df1[i, j] <- ord[[i]][1]
} else if (sum(mat[i,], na.rm = T) == 1) {
df1[i, j] <- ord[[i]][2]
}
mat[i, j] <- 0
}
}
}

带有purrr的选项
使用pmap_dfr((执行行操作通常非常一致。对于每次迭代,都可以创建一个向量,然后使用sample(c(3,4((修改选定的元素。

df1%>%pmap_dfr(., ~{
v1<-c(...)
v1[v1 %in% 34]<-sample(c(3,4))
v1})
# A tibble: 4 x 8
a     b     c     d     e     f     g     h
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1     1     2    NA    NA     3     4    NA    NA
2     2    NA    NA     3     4     1    NA    NA
3    NA     1     3    NA     2    NA     4    NA
4    NA    NA     2     1     3    NA    NA     4

apply((在这里也很有用
因为这个数据帧可以转换成矩阵而不会丢失任何信息:

data.frame(t(apply(df1, 1, function(x) replace(x, x %in% 34, sample(c(3,4))))))
a  b  c  d e  f  g  h
1  1  2 NA NA 3  4 NA NA
2  2 NA NA  4 3  1 NA NA
3 NA  1  4 NA 2 NA  3 NA
4 NA NA  2  1 3 NA NA  4

相关内容

最新更新