How to loop over rolling pairs of columns in dataframe

Viewed 73

I have a dataframe like this:

set.seed(123)
df <- data.frame(v1 = sample(1:4, 100, replace = T),
                 v2 = sample(1:4, 100, replace = T),
                 v3 = sample(1:4, 100, replace = T),
                 v4 = sample(1:4, 100, replace = T),
                 v5 = sample(1:4, 100, replace = T))

and I want to paste together rolling pairs of columns: v1and v2, v2and v3, v3 and v4, and so on. I tried doing this with apply within a for loop:

pairs <- c()
for(i in 1:ncol(df)){
  pairs <- apply(df[,c(i,i+1)], 1, paste0, collapse = "-")
}

but this throws an error:

Error in `[.data.frame`(df, , c(i, i + 1)) : undefined columns selected

What's wrong with the loop? And how could the pairing be achieved?

4 Answers

This works, your code doesn't work because there is no 6th column (which your code tries to select for i = 5).

pairs <- c()
for(i in 1:(ncol(df) - 1)){
  pairs[[i]] <- apply(df[,c(i,i+1)], 1, paste0, collapse = "-")
}

And make sure to use subscripts on pairs to keep all the results (so pairs[[i]]).


Edit

pairs <- c()
for(i in 1:ncol(df)){
  print(i)
  pairs[[i]] <- apply(df[,c(i,i+1)], 1, paste0, collapse = "-")
}
#[1] 1
#[1] 2
#[1] 3
#[1] 4
#[1] 5
#Error in `[.data.frame`(df, , c(i, i + 1)) : undefined columns selected

One option could be:

lapply(Map(`:`, head(1:ncol(df), -1), head(1:ncol(df) + 1, -1)), 
       function(x) Reduce(function(y1, y2) paste(y1, y2, sep = "-"), df[x]))

[[1]]
 [1] "2-3" "4-2" "2-2" "4-4" "4-2" "1-4" "3-4" "4-3" "3-2" "2-1"

[[2]]
 [1] "3-1" "2-4" "2-3" "4-3" "2-2" "4-4" "4-2" "3-2" "2-1" "1-1"

[[3]]
 [1] "1-4" "4-1" "3-4" "3-3" "2-3" "4-2" "2-1" "2-1" "1-2" "1-2"

[[4]]
 [1] "4-4" "1-1" "4-4" "3-3" "3-2" "2-2" "1-3" "1-1" "2-2" "2-3"

Use Map to avoid for loop.

res <-
  Map(function(x, y) apply(df[, x:y], 1, paste0, collapse="-"), 1:(ncol(df) - 1), 2:ncol(df))

res
# [[1]]
# [1] "1-2" "1-4" "1-1" "1-2" "2-1" "4-2" "2-4" "2-3" "1-4" "4-1" "3-4" "4-1" "3-4" "4-3" "1-2"
# [16] "1-2" "2-3" "4-1" "2-1" "2-2" "3-3" "3-4" "1-4" "1-2" "3-4" "4-1" "1-1" "3-4" "1-1" "1-1"
# [31] "4-1" "2-2" "4-3" "4-1" "3-2" "2-4" "1-4" "2-1" "4-3" "2-2" "3-1" "3-1" "2-2" "2-1" "4-1"
# [46] "4-3" "4-4" "2-2" "2-3" "1-2" "4-2" "1-4" "4-1" "2-3" "4-1" "2-1" "3-1" "4-3" "3-3" "1-4"
# [61] "1-1" "2-2" "2-2" "2-3" "2-2" "2-4" "4-3" "3-3" "2-2" "1-1" "2-4" "3-1" "2-4" "2-2" "2-1"
# [76] "4-2" "1-3" "1-2" "1-2" "3-4" "4-2" "1-2" "2-2" "1-3" "1-2" "4-4" "4-4" "1-3" "3-2" "3-2"
# [91] "1-3" "4-4" "1-2" "4-4" "4-4" "2-2" "1-1" "4-1" "2-2" "2-4"
# 
# [[2]]
# [1] "2-4" "4-2" "1-1" "2-4" "1-3" "2-1" "4-2" "3-2" "4-2" "1-4" "4-2" "1-3" "4-4" "3-3" "2-2"
# [16] "2-1" "3-4" "1-2" "1-1" "2-2" "3-1" "4-1" "4-1" "2-3" "4-2" "1-2" "1-4" "4-2" "1-1" "1-1"
# [31] "1-3" "2-2" "3-2" "1-3" "2-3" "4-1" "4-3" "1-4" "3-2" "2-4" "1-1" "1-3" "2-3" "1-2" "1-4"
# [46] "3-4" "4-4" "2-3" "3-1" "2-1" "2-1" "4-2" "1-1" "3-3" "1-2" "1-4" "1-3" "3-1" "3-1" "4-4"
# [61] "1-1" "2-1" "2-1" "3-4" "2-2" "4-3" "3-4" "3-3" "2-4" "1-3" "4-1" "1-1" "4-4" "2-1" "1-2"
# [76] "2-3" "3-4" "2-3" "2-1" "4-3" "2-4" "2-2" "2-3" "3-4" "2-2" "4-3" "4-3" "3-1" "2-1" "2-1"
# [91] "3-3" "4-2" "2-1" "4-3" "4-4" "2-4" "1-3" "1-1" "2-1" "4-4"
# 
# [[3]]
# [1] "4-1" "2-4" "1-2" "4-4" "3-1" "1-1" "2-2" "2-3" "2-1" "4-2" "2-2" "3-2" "4-2" "3-4" "2-3"
# [16] "1-2" "4-3" "2-2" "1-1" "2-1" "1-3" "1-3" "1-1" "3-2" "2-1" "2-2" "4-1" "2-2" "1-4" "1-1"
# [31] "3-3" "2-4" "2-2" "3-3" "3-2" "1-2" "3-2" "4-4" "2-4" "4-3" "1-1" "3-3" "3-1" "2-3" "4-2"
# [46] "4-1" "4-2" "3-4" "1-2" "1-2" "1-1" "2-3" "1-4" "3-2" "2-2" "4-1" "3-3" "1-3" "1-2" "4-3"
# [61] "1-1" "1-3" "1-3" "4-4" "2-1" "3-4" "4-2" "3-2" "4-1" "3-2" "1-3" "1-1" "4-2" "1-3" "2-1"
# [76] "3-4" "4-1" "3-2" "1-3" "3-1" "4-2" "2-4" "3-2" "4-3" "2-3" "3-2" "3-4" "1-1" "1-3" "1-2"
# [91] "3-1" "2-1" "1-1" "3-2" "4-3" "4-2" "3-3" "1-2" "1-3" "4-3"
# 
# [[4]]
# [1] "1-4" "4-4" "2-4" "4-1" "1-4" "1-2" "2-4" "3-1" "1-4" "2-3" "2-2" "2-1" "2-3" "4-2" "3-4"
# [16] "2-1" "3-1" "2-4" "1-1" "1-4" "3-2" "3-2" "1-4" "2-4" "1-1" "2-3" "1-4" "2-1" "4-3" "1-4"
# [31] "3-2" "4-3" "2-1" "3-2" "2-2" "2-2" "2-2" "4-4" "4-3" "3-1" "1-3" "3-1" "1-4" "3-3" "2-1"
# [46] "1-2" "2-2" "4-3" "2-3" "2-4" "1-2" "3-1" "4-4" "2-2" "2-1" "1-3" "3-3" "3-2" "2-3" "3-3"
# [61] "1-2" "3-1" "3-4" "4-2" "1-2" "4-3" "2-1" "2-2" "1-3" "2-2" "3-1" "1-2" "2-2" "3-1" "1-1"
# [76] "4-2" "1-3" "2-3" "3-2" "1-4" "2-2" "4-2" "2-4" "3-1" "3-2" "2-1" "4-3" "1-1" "3-2" "2-4"
# [91] "1-2" "1-3" "1-4" "2-3" "3-2" "2-4" "3-1" "2-2" "3-2" "3-3"

For 2 columns I would not use row-wise apply, use them in paste directly.

For example, with lapply :

lapply(seq_along(df)[-1], function(x) paste(df[, x-1], df[, x], sep = "-"))
Related