lecreprays
lecreprays

Reputation: 77

Sequential subtraction for each observation against all other observations

Here's some example data for this problem, let's call this example dataset df:

     df$x  

   obs  x   
    1   2  
    2   4   
    3   8   
    4   16   

What I'd like to accomplish is to find the difference for each x against all other xs for all x and store those differences in an object.

Here's what the math should look like:

some code later:
result_df

       obs  col1 col2 col3   
        1   2-4  2-8  2-16
        2   4-2  4-8  4-16
        3   8-2  8-4  8-16   
        4   16-2 16-4 16-8

What I've tried doing so far is something like this:

for (i in 1:nrow(df)){
#Create empty matrix
mat<-matrix(rep(0,(nrow(df))*(nrow(df)-1)),ncol=nrow(df)-1,nrow=nrow(df))
#occupy matrix with desired results
mat[i,]<-df$x[i]-df$x[i+1]
print(mat)
}

I intended this code to be valid for the first row of my result_df in my example (I guess I would have to create another loop to do it for each given x?), but it doesn't give me the desired results.

I hope that's clear. Thanks! It'd be great to me able to do this in base R so I get a better grasp of it.

Upvotes: 1

Views: 316

Answers (3)

akrun
akrun

Reputation: 887038

Here is another option using CJ from data.table

library(data.table)
matrix(CJ(df$x, df$x)[V1 != V2, V1-V2], nrow(df), byrow=TRUE)
#     [,1] [,2] [,3]
#[1,]   -2   -6  -14
#[2,]    2   -4  -12
#[3,]    6    4   -8
#[4,]   14   12    8

Or a base R option is outer

m1 <- outer(df$x, df$x, `-`)
cbind(obs = 1:4, matrix(m1[m1!=0], nrow= nrow(df), byrow = TRUE,
            dimnames = list(NULL, paste0('col', 1:3))))
#     obs col1 col2 col3
#[1,]   1    2    6   14
#[2,]   2   -2    4   12
#[3,]   3   -6   -4    8
#[4,]   4  -14  -12   -8

This can be converted to data.frame by wrapping with as.data.frame

Upvotes: 0

Mike H.
Mike H.

Reputation: 14360

Another option would be to use expand.grid:

expanded <- expand.grid(df$x, df$x)
subtr <- expanded[!(expanded$Var1 == expanded$Var2), "Var2"] - expanded[!(expanded$Var1 == expanded$Var2), "Var1"]
data.frame(matrix(subtr, nrow = nrow(df), byrow = T))

#  X1 X2  X3
#1 -2 -6 -14
#2  2 -4 -12
#3  6  4  -8
#4 14 12   8

Upvotes: 0

Lamia
Lamia

Reputation: 3875

You could do it using sapply:

d=t(sapply(1:nrow(df),function(i) df$x[i]-df$x[-i]))
res_df=data.frame(df$obs,d)
names(res_df)=c("obs",paste0("col",c(1:3)))

This returns:

obs col1 col2 col3
1   1   -2   -6  -14
2   2    2   -4  -12
3   3    6    4   -8
4   4   14   12    8

Upvotes: 3

Related Questions