Home > Software design >  Introduce two strings in a "for" loop
Introduce two strings in a "for" loop

Time:03-28

I have this dataframe:

a <- c(2,5,90,77,56,65,85,75,12,24,52,32)
b <- c(45,78,98,55,63,12,23,38,75,68,99,73)
c <- c(77,85,3,22,4,69,86,39,78,36,96,11)
d <- c(52,68,4,25,79,120,97,20,7,19,37,67)
e <- c(14,73,91,87,94,38,1,685,47,102,666,74)

df <- data.frame(a,b,c,d,e)

and this script:

R <- Map(` `, list(1:3), 0:9) 
cmin <- t(as.matrix(rep(NA, ncol(df)))) 

for (r in seq(R)) {
  for (f in seq(ncol(df))) {
    x <- df[R[[r]], f]
    y <- df[R[[r]], -f]
    dif_2 <- (x - y)^2
    cmin[f] <- which.min(colSums(dif_2))
  }
}

dif_3 <- as.matrix(dif_2[,cmin])
sq <- sqrt(dif_3)

How can I put the last two lines of the script into the "for" loop above?

Thanks everyone for helping me!

CodePudding user response:

If the output of 'sq' should be a vector

sq <- c()
for (r in seq(R)) {
  for (f in seq(ncol(df))) {
    x <- df[R[[r]], f]
    y <- df[R[[r]], -f]
    dif_2 <- (x - y)^2
    cmin[f] <- which.min(colSums(dif_2))
    dif_3 <- as.matrix(dif_2[,cmin[f]])
    sq <- c(sq, sqrt(dif_3))
  }
}

-output

> sq
  [1]  12  68   1  31   5   7  25  17   1  25  17   1  31   5   7  68   1  10   5   7  32  17   1   3  17   1   3   5   7  32   8  22   7
 [34]   8  22   7   1   3  75   1   3  75   1  10  38  10  38  27  32  31  26  55  52   4  52  23  55  10  38  27  52   4   1  31  26  22
 [67]  52   4   1  23  55  12  31  26  22   4   1  36  57  63   1   4   1  36  51  11  19  27  84 610  12  55   5  63   1   3  63   1   3
[100]  12  55   5  84 610  35  55   5   5   1   3  32   1   3  32  55   5   5 610  35  78   5   5  15   3  32   3   3  32   3   5   5  15
[133]  28  34 567   5  15  35  32   3  62  12  44  21   5  15  35  34 567   1

If it should be a list

sq <- list()
for (r in seq(R)) {
  for (f in seq(ncol(df))) {
    x <- df[R[[r]], f]
    y <- df[R[[r]], -f]
    dif_2 <- (x - y)^2
    cmin[f] <- which.min(colSums(dif_2))
    dif_3 <- as.matrix(dif_2[,cmin[f]])
    sq <- c(sq, list(sqrt(dif_3)))
  }
}

sqmat <- do.call(cbind, sq)

CodePudding user response:

If I understand correctly, you want the min distances for each row indices given in R. The code below creates two data structures, sq_list1 and sq_3d that store the same values but one o them is a list of matrices and the other is a 3d array with the 3rd index 1:length(R).

sq_list <- replicate(length(R), 
                     matrix(nrow = length(R[[1]]), ncol = ncol(df)),
                     simplify = FALSE)
sq_3d <- replicate(length(R), 
                      matrix(nrow = length(R[[1]]), ncol = ncol(df)))

for (r in seq(R)) {
  for (f in seq(ncol(df))) {
    x <- df[R[[r]], f]
    y <- df[R[[r]], -f]
    dif_2 <- (x - y)^2
    cmin <- which.min(colSums(dif_2))
    dif_3 <- dif_2[, cmin]
    sq_list[[r]][, f] <- sqrt(dif_3)
    sq_3d[, f, r] <- sqrt(dif_3)
  }
}

# output not shown
sq_list
sq_3d

Edit

This seems simpler.

faux <- function(r, df){
  sub_df <- df[r, ]
  sapply(seq(ncol(sub_df)), \(f){
    d <- (sub_df[, f] - sub_df[, -f])^2
    cmin <- which.min(colSums(d))
    sqrt(d[, cmin])
  })
}
sq_list2 <- lapply(R, faux, df = df)
identical(sq_list, sq_list2)
#[1] TRUE
  • Related